Selaa lähdekoodia

Improve ordering of entries and types

Thibaut Courouble 9 vuotta sitten
vanhempi
commit
82d0725747

+ 31 - 2
lib/docs/core/entry_index.rb

@@ -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

+ 0 - 4
lib/docs/core/models/entry.rb

@@ -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

+ 0 - 10
lib/docs/core/models/type.rb

@@ -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

+ 21 - 2
test/lib/docs/core/entry_index_test.rb

@@ -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
 

+ 0 - 18
test/lib/docs/core/models/entry_test.rb

@@ -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'

+ 0 - 21
test/lib/docs/core/models/type_test.rb

@@ -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\/%?#'