Skip to content

Commit 2cfbdb3

Browse files
committed
Make sorting more consistent
condense sort_by_ancestry and add tests Data has 2 use cases: - no rank function: only move parents to in front of children - rank function: sort each level with ranking function
1 parent 8c4cb97 commit 2cfbdb3

File tree

2 files changed

+33
-28
lines changed

2 files changed

+33
-28
lines changed

lib/ancestry/class_methods.rb

+6-10
Original file line numberDiff line numberDiff line change
@@ -68,17 +68,13 @@ def arrange_serializable options={}, nodes=nil, &block
6868
# Pseudo-preordered array of nodes. Children will always follow parents,
6969
# for ordering nodes within a rank provide block, eg. Node.sort_by_ancestry(Node.all) {|a, b| a.rank <=> b.rank}.
7070
def sort_by_ancestry(nodes, &block)
71-
arranged = nodes if nodes.is_a?(Hash)
72-
73-
unless arranged
71+
if nodes.is_a?(Hash)
72+
arranged = nodes
73+
else
7474
presorted_nodes = nodes.sort do |a, b|
75-
a_cestry, b_cestry = a.ancestry || '0', b.ancestry || '0'
76-
77-
if block_given? && a_cestry == b_cestry
78-
yield a, b
79-
else
80-
a_cestry <=> b_cestry
81-
end
75+
r = a.ancestor_ids <=> b.ancestor_ids
76+
r = yield(a, b) if r == 0 && block_given?
77+
r
8278
end
8379

8480
arranged = arrange_nodes(presorted_nodes)

test/concerns/sort_by_ancestry_test.rb

+27-18
Original file line numberDiff line numberDiff line change
@@ -8,40 +8,49 @@ def test_sort_by_ancestry
88
# - n3
99
# - n4
1010
# - n5
11+
# - n6
1112
n1 = model.create!
1213
n2 = model.create!(:parent => n1)
1314
n3 = model.create!(:parent => n2)
1415
n4 = model.create!(:parent => n2)
1516
n5 = model.create!(:parent => n1)
17+
n6 = model.create!(:parent => n5)
18+
nodes = [n1, n2, n3, n4, n5, n6]
1619

17-
records = model.sort_by_ancestry(model.all.sort_by(&:id).reverse)
18-
if records[1] == n2
19-
if records[2] == n3
20-
assert_equal [n1, n2, n3, n4, n5].map(&:id), records.map(&:id)
21-
else
22-
assert_equal [n1, n2, n4, n3, n5].map(&:id), records.map(&:id)
23-
end
24-
else
25-
if records[3] == n3
26-
assert_equal [n1, n5, n2, n3, n4].map(&:id), records.map(&:id)
27-
else
28-
assert_equal [n1, n5, n2, n4, n3].map(&:id), records.map(&:id)
29-
end
30-
end
20+
# n1 needs to move to front, and n2 needs to move in front of n4, n3
21+
assert_equal [n1, n5, n6, n2, n4, n3].map(&:id), model.sort_by_ancestry(model.all.sort_by(&:id).reverse).map(&:id)
22+
# none are parents
23+
#assert_equal [n5, n4, n3].map(&:id), model.sort_by_ancestry([n5, n4, n3]).map(&:id)
24+
# at the same level
25+
assert_equal [n3, n4].map(&:id), model.sort_by_ancestry([n3, n4]).map(&:id)
26+
# n1 needs to move below both
27+
assert_equal [n1, n5, n2].map(&:id), model.sort_by_ancestry([n5, n2, n1]).map(&:id)
28+
# n1 needs to move below even a double descendant
29+
#assert_equal [n1, n5, n4].map(&:id), model.sort_by_ancestry([n5, n4, n1]).map(&:id)
3130
end
3231
end
3332

3433
def test_sort_by_ancestry_with_block
3534
AncestryTestDatabase.with_model :extra_columns => {:rank => :integer} do |model|
35+
# - n1 (0)
36+
# - n5 (0)
37+
# - n3 (3)
38+
# - n2 (1)
39+
# - n4 (0)
40+
# - n6 (1)
3641
n1 = model.create!(:rank => 0)
3742
n2 = model.create!(:rank => 1)
38-
n3 = model.create!(:rank => 0, :parent => n1)
43+
n3 = model.create!(:rank => 3, :parent => n1)
3944
n4 = model.create!(:rank => 0, :parent => n2)
40-
n5 = model.create!(:rank => 1, :parent => n1)
45+
n5 = model.create!(:rank => 0, :parent => n1)
4146
n6 = model.create!(:rank => 1, :parent => n2)
4247

43-
records = model.sort_by_ancestry(model.all.sort_by(&:rank).reverse) {|a, b| a.rank <=> b.rank}
44-
assert_equal [n1, n3, n5, n2, n4, n6].map(&:id), records.map(&:id)
48+
sort = -> (a, b) { a.rank <=> b.rank }
49+
records = model.sort_by_ancestry(model.all.sort_by(&:rank).reverse, &sort)
50+
# all parents, all children
51+
assert_equal [n1, n5, n3, n2, n4, n6].map(&:id), records.map(&:id)
52+
# all parents, some children
53+
assert_equal [n1, n5, n2].map(&:id), model.sort_by_ancestry([n2, n1, n5],&sort).map(&:id)
4554
end
4655
end
4756
end

0 commit comments

Comments
 (0)