Improve ordering of entries and types

This commit is contained in:
Thibaut Courouble 2016-09-04 10:46:54 -04:00
parent f9dfcf4504
commit 82d0725747
6 changed files with 52 additions and 57 deletions

View file

@ -46,11 +46,40 @@ module Docs
end
def entries_as_json
@entries.sort!.map { |entry| entry.as_json }
@entries.sort! { |a, b| sort_fn(a.name, b.name) }.map(&:as_json)
end
def types_as_json
@types.values.sort!.map { |type| type.as_json }
@types.values.sort! { |a, b| sort_fn(a.name, b.name) }.map(&:as_json)
end
SPLIT_INTS = /(?<=\d)\.(?=[\s\d])/.freeze
def sort_fn(a, b)
if (a.getbyte(0) >= 49 && a.getbyte(0) <= 57) || (b.getbyte(0) >= 49 && b.getbyte(0) <= 57)
a_split = a.split(SPLIT_INTS)
b_split = b.split(SPLIT_INTS)
a_length = a_split.length
b_length = b_split.length
return a.casecmp(b) if a_length == 1 && b_length == 1
return 1 if a_length == 1
return -1 if b_length == 1
a_split.each_with_index { |s, i| a_split[i] = s.to_i unless i == a_length - 1 }
b_split.each_with_index { |s, i| b_split[i] = s.to_i unless i == b_length - 1 }
if b_length > a_length
(b_length - a_length).times { a_split.insert(-2, 0) }
elsif a_length > b_length
(a_length - b_length).times { b_split.insert(-2, 0) }
end
a_split <=> b_split
else
a.casecmp(b)
end
end
end
end

View file

@ -22,10 +22,6 @@ module Docs
other.name == name && other.path == path && other.type == type
end
def <=>(other)
name.to_s.casecmp(other.name.to_s)
end
def name=(value)
@name = value.try :strip
end

View file

@ -7,16 +7,6 @@ module Docs
self.count ||= 0
end
STARTS_WITH_INTEGER = /\A\d/
def <=>(other)
if name && other && name =~ STARTS_WITH_INTEGER && other.name =~ STARTS_WITH_INTEGER
name.to_i <=> other.name.to_i
else
name.to_s.casecmp(other.name.to_s)
end
end
def slug
name.parameterize
end

View file

@ -110,8 +110,17 @@ class DocsEntryIndexTest < MiniTest::Spec
entry.name = 'B'; index.add(entry)
entry.name = 'a'; index.add(entry)
entry.name = 'c'; index.add(entry)
entry.name = nil; index.add(entry)
assert_equal [nil, 'a', 'B', 'c'], index.as_json[:entries].map { |e| e[:name] }
assert_equal ['a', 'B', 'c'], index.as_json[:entries].map { |e| e[:name] }
end
it "sorts numbered names" do
entry.name = '4.2.2. Test'; index.add(entry)
entry.name = '4.20. Test'; index.add(entry)
entry.name = '4.3. Test'; index.add(entry)
entry.name = '4. Test'; index.add(entry)
entry.name = '2 Test'; index.add(entry)
entry.name = 'Test'; index.add(entry)
assert_equal ['4. Test', '4.2.2. Test', '4.3. Test', '4.20. Test', '2 Test', 'Test'], index.as_json[:entries].map { |e| e[:name] }
end
end
@ -132,6 +141,16 @@ class DocsEntryIndexTest < MiniTest::Spec
entry.type = 'c'; index.add(entry)
assert_equal ['a', 'B', 'c'], index.as_json[:types].map { |e| e[:name] }
end
it "sorts numbered names" do
entry.type = '1.8.2. Test'; index.add(entry)
entry.type = '1.90. Test'; index.add(entry)
entry.type = '1.9. Test'; index.add(entry)
entry.type = '9. Test'; index.add(entry)
entry.type = '1 Test'; index.add(entry)
entry.type = 'Test'; index.add(entry)
assert_equal ['1.8.2. Test', '1.9. Test', '1.90. Test', '9. Test', '1 Test', 'Test'], index.as_json[:types].map { |e| e[:name] }
end
end
end

View file

@ -82,24 +82,6 @@ class DocsEntryTest < MiniTest::Spec
end
end
describe "#<=>" do
it "returns 1 when the other's name is less" do
assert_equal 1, build_entry('b') <=> build_entry('a')
end
it "returns -1 when the other's name is greater" do
assert_equal -1, build_entry('a') <=> build_entry('b')
end
it "returns 0 when the other's name is equal" do
assert_equal 0, build_entry('a') <=> build_entry('a')
end
it "is case-insensitive" do
assert_equal 0, build_entry('a') <=> build_entry('A')
end
end
describe "#root?" do
it "returns true when #path is 'index'" do
entry.path = 'index'

View file

@ -18,27 +18,6 @@ class DocsTypeTest < MiniTest::Spec
end
end
describe "#<=>" do
it "returns 1 when the other type's name is less" do
assert_equal 1, Type.new('b') <=> Type.new('a')
assert_equal 1, Type.new('15 a') <=> Type.new('4 b')
end
it "returns -1 when the other type's name is greater" do
assert_equal -1, Type.new('a') <=> Type.new('b')
assert_equal -1, Type.new('8 a') <=> Type.new('16 b')
end
it "returns 0 when the other type's name is equal" do
assert_equal 0, Type.new('a') <=> Type.new('a')
assert_equal 0, Type.new('23 a') <=> Type.new('23 b')
end
it "is case-insensitive" do
assert_equal 0, Type.new('a') <=> Type.new('A')
end
end
describe "#slug" do
it "parameterizes the #name" do
name = 'a.b c\/%?#'