acts_as_ordered_tree 1.3.1 → 2.0.0.beta3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/acts_as_ordered_tree.rb +22 -100
- data/lib/acts_as_ordered_tree/adapters.rb +17 -0
- data/lib/acts_as_ordered_tree/adapters/abstract.rb +23 -0
- data/lib/acts_as_ordered_tree/adapters/postgresql.rb +150 -0
- data/lib/acts_as_ordered_tree/adapters/recursive.rb +157 -0
- data/lib/acts_as_ordered_tree/compatibility.rb +22 -0
- data/lib/acts_as_ordered_tree/compatibility/active_record/association_scope.rb +9 -0
- data/lib/acts_as_ordered_tree/compatibility/active_record/default_scoped.rb +19 -0
- data/lib/acts_as_ordered_tree/compatibility/active_record/null_relation.rb +71 -0
- data/lib/acts_as_ordered_tree/compatibility/features.rb +153 -0
- data/lib/acts_as_ordered_tree/deprecate.rb +24 -0
- data/lib/acts_as_ordered_tree/hooks.rb +38 -0
- data/lib/acts_as_ordered_tree/hooks/update.rb +86 -0
- data/lib/acts_as_ordered_tree/instance_methods.rb +92 -453
- data/lib/acts_as_ordered_tree/iterators/arranger.rb +35 -0
- data/lib/acts_as_ordered_tree/iterators/level_calculator.rb +52 -0
- data/lib/acts_as_ordered_tree/iterators/orphans_pruner.rb +58 -0
- data/lib/acts_as_ordered_tree/node.rb +78 -0
- data/lib/acts_as_ordered_tree/node/attributes.rb +48 -0
- data/lib/acts_as_ordered_tree/node/movement.rb +62 -0
- data/lib/acts_as_ordered_tree/node/movements.rb +111 -0
- data/lib/acts_as_ordered_tree/node/predicates.rb +98 -0
- data/lib/acts_as_ordered_tree/node/reloading.rb +49 -0
- data/lib/acts_as_ordered_tree/node/siblings.rb +139 -0
- data/lib/acts_as_ordered_tree/node/traversals.rb +53 -0
- data/lib/acts_as_ordered_tree/persevering_transaction.rb +93 -0
- data/lib/acts_as_ordered_tree/position.rb +143 -0
- data/lib/acts_as_ordered_tree/relation/arrangeable.rb +33 -0
- data/lib/acts_as_ordered_tree/relation/iterable.rb +41 -0
- data/lib/acts_as_ordered_tree/relation/preloaded.rb +46 -11
- data/lib/acts_as_ordered_tree/transaction/base.rb +57 -0
- data/lib/acts_as_ordered_tree/transaction/callbacks.rb +67 -0
- data/lib/acts_as_ordered_tree/transaction/create.rb +68 -0
- data/lib/acts_as_ordered_tree/transaction/destroy.rb +34 -0
- data/lib/acts_as_ordered_tree/transaction/dsl.rb +214 -0
- data/lib/acts_as_ordered_tree/transaction/factory.rb +67 -0
- data/lib/acts_as_ordered_tree/transaction/move.rb +70 -0
- data/lib/acts_as_ordered_tree/transaction/passthrough.rb +12 -0
- data/lib/acts_as_ordered_tree/transaction/reorder.rb +42 -0
- data/lib/acts_as_ordered_tree/transaction/save.rb +64 -0
- data/lib/acts_as_ordered_tree/transaction/update.rb +78 -0
- data/lib/acts_as_ordered_tree/tree.rb +148 -0
- data/lib/acts_as_ordered_tree/tree/association.rb +20 -0
- data/lib/acts_as_ordered_tree/tree/callbacks.rb +57 -0
- data/lib/acts_as_ordered_tree/tree/children_association.rb +120 -0
- data/lib/acts_as_ordered_tree/tree/columns.rb +102 -0
- data/lib/acts_as_ordered_tree/tree/deprecated_columns_accessors.rb +24 -0
- data/lib/acts_as_ordered_tree/tree/parent_association.rb +31 -0
- data/lib/acts_as_ordered_tree/tree/perseverance.rb +19 -0
- data/lib/acts_as_ordered_tree/tree/scopes.rb +56 -0
- data/lib/acts_as_ordered_tree/validators.rb +1 -1
- data/lib/acts_as_ordered_tree/version.rb +1 -1
- data/spec/acts_as_ordered_tree_spec.rb +80 -909
- data/spec/adapters/postgresql_spec.rb +14 -0
- data/spec/adapters/recursive_spec.rb +12 -0
- data/spec/adapters/shared.rb +272 -0
- data/spec/callbacks_spec.rb +177 -0
- data/spec/counter_cache_spec.rb +31 -0
- data/spec/create_spec.rb +110 -0
- data/spec/destroy_spec.rb +57 -0
- data/spec/inheritance_spec.rb +176 -0
- data/spec/move_spec.rb +94 -0
- data/spec/node/movements/concurrent_movements_spec.rb +354 -0
- data/spec/node/movements/move_higher_spec.rb +46 -0
- data/spec/node/movements/move_lower_spec.rb +46 -0
- data/spec/node/movements/move_to_child_of_spec.rb +147 -0
- data/spec/node/movements/move_to_child_with_index_spec.rb +124 -0
- data/spec/node/movements/move_to_child_with_position_spec.rb +85 -0
- data/spec/node/movements/move_to_left_of_spec.rb +120 -0
- data/spec/node/movements/move_to_right_of_spec.rb +120 -0
- data/spec/node/movements/move_to_root_spec.rb +67 -0
- data/spec/node/predicates_spec.rb +211 -0
- data/spec/node/reloading_spec.rb +42 -0
- data/spec/node/siblings_spec.rb +193 -0
- data/spec/node/traversals_spec.rb +71 -0
- data/spec/persevering_transaction_spec.rb +98 -0
- data/spec/relation/arrangeable_spec.rb +88 -0
- data/spec/relation/iterable_spec.rb +104 -0
- data/spec/relation/preloaded_spec.rb +57 -0
- data/spec/reorder_spec.rb +83 -0
- data/spec/spec_helper.rb +30 -38
- data/spec/support/db/boot.rb +22 -0
- data/spec/{db → support/db}/config.travis.yml +2 -0
- data/spec/{db → support/db}/config.yml +1 -0
- data/spec/{db → support/db}/schema.rb +9 -0
- data/spec/support/factories.rb +2 -2
- data/spec/support/matchers.rb +67 -58
- data/spec/support/models.rb +6 -14
- data/spec/support/tree_factory.rb +315 -0
- data/spec/tree/children_association_spec.rb +72 -0
- data/spec/tree/columns_spec.rb +65 -0
- data/spec/tree/scopes_spec.rb +39 -0
- metadata +161 -43
- data/lib/acts_as_ordered_tree/adapters/postgresql_adapter.rb +0 -104
- data/lib/acts_as_ordered_tree/arrangeable.rb +0 -80
- data/lib/acts_as_ordered_tree/class_methods.rb +0 -72
- data/lib/acts_as_ordered_tree/relation/base.rb +0 -26
- data/lib/acts_as_ordered_tree/tenacious_transaction.rb +0 -30
- data/spec/concurrency_support_spec.rb +0 -156
@@ -0,0 +1,124 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Movements, '#move_to_child_with_index', :transactional do
|
6
|
+
shared_examples '#move_to_child_with_index' do |factory|
|
7
|
+
describe "#move_to_child_with_index #{factory}" do
|
8
|
+
tree :factory => factory do
|
9
|
+
root {
|
10
|
+
node_1
|
11
|
+
node_2
|
12
|
+
node_3 {
|
13
|
+
node_4
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'moving node to same parent and same position' do
|
19
|
+
before { node_2.move_to_child_with_index(root, 1) }
|
20
|
+
|
21
|
+
expect_tree_to_match {
|
22
|
+
root {
|
23
|
+
node_1
|
24
|
+
node_2
|
25
|
+
node_3 {
|
26
|
+
node_4
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'moving node to same parent with another position' do
|
33
|
+
before { node_1.move_to_child_with_index(root, 1) }
|
34
|
+
|
35
|
+
expect_tree_to_match {
|
36
|
+
root {
|
37
|
+
node_2
|
38
|
+
node_1
|
39
|
+
node_3 {
|
40
|
+
node_4
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'moving node to same parent to lowest position' do
|
47
|
+
before { node_1.move_to_child_with_index(root, -1) }
|
48
|
+
|
49
|
+
expect_tree_to_match {
|
50
|
+
root {
|
51
|
+
node_2
|
52
|
+
node_3 {
|
53
|
+
node_4
|
54
|
+
}
|
55
|
+
node_1
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'moving node to position with negative index' do
|
61
|
+
before { node_4.move_to_child_with_index(root, -2) }
|
62
|
+
|
63
|
+
expect_tree_to_match {
|
64
|
+
root {
|
65
|
+
node_1
|
66
|
+
node_4
|
67
|
+
node_2
|
68
|
+
node_3
|
69
|
+
}
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'moving node to root with index starting from end' do
|
74
|
+
before { node_4.move_to_child_with_index(nil, -1) }
|
75
|
+
|
76
|
+
expect_tree_to_match {
|
77
|
+
node_4
|
78
|
+
root {
|
79
|
+
node_1
|
80
|
+
node_2
|
81
|
+
node_3
|
82
|
+
}
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'moving to node to very position with large negative index' do
|
87
|
+
before { node_4.move_to_child_with_index(root, -100) }
|
88
|
+
|
89
|
+
expect_tree_to_match {
|
90
|
+
root {
|
91
|
+
node_4
|
92
|
+
node_1
|
93
|
+
node_2
|
94
|
+
node_3
|
95
|
+
}
|
96
|
+
}
|
97
|
+
end
|
98
|
+
|
99
|
+
context 'moving to node to very large position' do
|
100
|
+
before { node_4.move_to_child_with_index(root, 100) }
|
101
|
+
|
102
|
+
expect_tree_to_match {
|
103
|
+
root {
|
104
|
+
node_1
|
105
|
+
node_2
|
106
|
+
node_3
|
107
|
+
node_4
|
108
|
+
}
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'when attribute, not related to tree, changed' do
|
113
|
+
before { @old_name = node_2.name }
|
114
|
+
before { node_2.name = 'new name' }
|
115
|
+
|
116
|
+
it { expect{node_2.move_to_child_with_index(root, 1)}.to change(node_2, :name).to(@old_name) }
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
include_examples '#move_to_child_with_index', :default
|
122
|
+
include_examples '#move_to_child_with_index', :default_with_counter_cache
|
123
|
+
include_examples '#move_to_child_with_index', :scoped
|
124
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Movements, '#move_to_child_with_position', :transactional do
|
6
|
+
shared_examples '#move_to_child_with_position' do |factory|
|
7
|
+
describe "#move_to_child_with_position #{factory}" do
|
8
|
+
tree :factory => factory do
|
9
|
+
root {
|
10
|
+
node_1
|
11
|
+
node_2
|
12
|
+
node_3 {
|
13
|
+
node_4
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'moving node to same parent and same position' do
|
19
|
+
before { node_2.move_to_child_with_position(root, 2) }
|
20
|
+
|
21
|
+
expect_tree_to_match {
|
22
|
+
root {
|
23
|
+
node_1
|
24
|
+
node_2
|
25
|
+
node_3 {
|
26
|
+
node_4
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'moving node to same parent with another position' do
|
33
|
+
before { node_1.move_to_child_with_position(root, 2) }
|
34
|
+
|
35
|
+
expect_tree_to_match {
|
36
|
+
root {
|
37
|
+
node_2
|
38
|
+
node_1
|
39
|
+
node_3 {
|
40
|
+
node_4
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'moving node to same parent to lowest position' do
|
47
|
+
before { node_1.move_to_child_with_position(root, 3) }
|
48
|
+
|
49
|
+
expect_tree_to_match {
|
50
|
+
root {
|
51
|
+
node_2
|
52
|
+
node_3 {
|
53
|
+
node_4
|
54
|
+
}
|
55
|
+
node_1
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'moving to node to very large position' do
|
61
|
+
before { node_4.move_to_child_with_position(root, 100) }
|
62
|
+
|
63
|
+
expect_tree_to_match {
|
64
|
+
root {
|
65
|
+
node_1
|
66
|
+
node_2
|
67
|
+
node_3
|
68
|
+
node_4
|
69
|
+
}
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when attribute, not related to tree, changed' do
|
74
|
+
before { @old_name = node_2.name }
|
75
|
+
before { node_2.name = 'new name' }
|
76
|
+
|
77
|
+
it { expect{node_2.move_to_child_with_position(root, 2)}.to change(node_2, :name).to(@old_name) }
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
include_examples '#move_to_child_with_position', :default
|
83
|
+
include_examples '#move_to_child_with_position', :default_with_counter_cache
|
84
|
+
include_examples '#move_to_child_with_position', :scoped
|
85
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Movements, '#move_to_left_of', :transactional do
|
6
|
+
shared_examples '#move_to_left_of' do |factory|
|
7
|
+
describe "#move_to_left_of #{factory}" do
|
8
|
+
tree :factory => factory do
|
9
|
+
root {
|
10
|
+
node_1
|
11
|
+
node_2
|
12
|
+
node_3 {
|
13
|
+
node_4
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'moving node to next position' do
|
19
|
+
before { node_1.move_to_left_of(node_2) }
|
20
|
+
|
21
|
+
expect_tree_to_match {
|
22
|
+
root {
|
23
|
+
node_1
|
24
|
+
node_2
|
25
|
+
node_3 {
|
26
|
+
node_4
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'moving node to same parent higher' do
|
33
|
+
before { node_3.move_to_left_of(node_1) }
|
34
|
+
|
35
|
+
expect_tree_to_match {
|
36
|
+
root {
|
37
|
+
node_3 {
|
38
|
+
node_4
|
39
|
+
}
|
40
|
+
node_1
|
41
|
+
node_2
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'moving node to same parent lower' do
|
47
|
+
before { node_1.move_to_left_of(node_3) }
|
48
|
+
|
49
|
+
expect_tree_to_match {
|
50
|
+
root {
|
51
|
+
node_2
|
52
|
+
node_1
|
53
|
+
node_3 {
|
54
|
+
node_4
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'moving inner node to left of root' do
|
61
|
+
before { node_3.move_to_left_of(root) }
|
62
|
+
|
63
|
+
expect_tree_to_match {
|
64
|
+
node_3 {
|
65
|
+
node_4
|
66
|
+
}
|
67
|
+
root {
|
68
|
+
node_1
|
69
|
+
node_2
|
70
|
+
}
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'moving inner node to left of another inner node (shallower)' do
|
75
|
+
before { node_4.move_to_left_of(node_1) }
|
76
|
+
|
77
|
+
expect_tree_to_match {
|
78
|
+
root {
|
79
|
+
node_4
|
80
|
+
node_1
|
81
|
+
node_2
|
82
|
+
node_3
|
83
|
+
}
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'moving inner node to left of another inner node (deeper)' do
|
88
|
+
before { node_1.move_to_left_of(node_4) }
|
89
|
+
|
90
|
+
expect_tree_to_match {
|
91
|
+
root {
|
92
|
+
node_2
|
93
|
+
node_3 {
|
94
|
+
node_1
|
95
|
+
node_4
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'attempt to perform impossible movement' do
|
102
|
+
it { expect{ root.move_to_left_of(node_1) }.not_to change(current_tree, :all) }
|
103
|
+
it { expect{ node_3.move_to_left_of(node_4) }.not_to change(current_tree, :all) }
|
104
|
+
it { expect{ node_1.move_to_left_of(node_1) }.not_to change(current_tree, :all) }
|
105
|
+
it { expect{ node_3.move_to_left_of(node_3) }.not_to change(current_tree, :all) }
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when attribute, not related to tree, changed' do
|
109
|
+
before { @old_name = node_2.name }
|
110
|
+
before { node_2.name = 'new name' }
|
111
|
+
|
112
|
+
it { expect{node_2.move_to_left_of(node_4)}.to change(node_2, :name).to(@old_name) }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
include_examples '#move_to_left_of', :default
|
118
|
+
include_examples '#move_to_left_of', :default_with_counter_cache
|
119
|
+
include_examples '#move_to_left_of', :scoped, :scope_type => 's'
|
120
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Movements, '#move_to_right_of', :transactional do
|
6
|
+
shared_examples '#move_to_right_of' do |factory|
|
7
|
+
describe "#move_to_right_of #{factory}" do
|
8
|
+
tree :factory => factory do
|
9
|
+
root {
|
10
|
+
node_1
|
11
|
+
node_2
|
12
|
+
node_3 {
|
13
|
+
node_4
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'moving node to same parent higher' do
|
19
|
+
before { node_3.move_to_right_of(node_1) }
|
20
|
+
|
21
|
+
expect_tree_to_match {
|
22
|
+
root {
|
23
|
+
node_1
|
24
|
+
node_3 {
|
25
|
+
node_4
|
26
|
+
}
|
27
|
+
node_2
|
28
|
+
}
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'moving node to next position' do
|
33
|
+
before { node_1.move_to_right_of(node_2) }
|
34
|
+
|
35
|
+
expect_tree_to_match {
|
36
|
+
root {
|
37
|
+
node_2
|
38
|
+
node_1
|
39
|
+
node_3 {
|
40
|
+
node_4
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'moving node to same parent lower' do
|
47
|
+
before { node_1.move_to_right_of(node_3) }
|
48
|
+
|
49
|
+
expect_tree_to_match {
|
50
|
+
root {
|
51
|
+
node_2
|
52
|
+
node_3 {
|
53
|
+
node_4
|
54
|
+
}
|
55
|
+
node_1
|
56
|
+
}
|
57
|
+
}
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'moving inner node to right of root node' do
|
61
|
+
before { node_3.move_to_right_of(root) }
|
62
|
+
|
63
|
+
expect_tree_to_match {
|
64
|
+
root {
|
65
|
+
node_1
|
66
|
+
node_2
|
67
|
+
}
|
68
|
+
node_3 {
|
69
|
+
node_4
|
70
|
+
}
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'moving inner node to right of another inner node (shallower)' do
|
75
|
+
before { node_4.move_to_right_of(node_1) }
|
76
|
+
|
77
|
+
expect_tree_to_match {
|
78
|
+
root {
|
79
|
+
node_1
|
80
|
+
node_4
|
81
|
+
node_2
|
82
|
+
node_3
|
83
|
+
}
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'moving inner node to right of another inner node (deeper)' do
|
88
|
+
before { node_1.move_to_right_of(node_4) }
|
89
|
+
|
90
|
+
expect_tree_to_match {
|
91
|
+
root {
|
92
|
+
node_2
|
93
|
+
node_3 {
|
94
|
+
node_4
|
95
|
+
node_1
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'Attempt to perform impossible movement' do
|
102
|
+
it { expect{ root.move_to_right_of(node_1) }.not_to change(current_tree, :all) }
|
103
|
+
it { expect{ node_3.move_to_right_of(node_4) }.not_to change(current_tree, :all) }
|
104
|
+
it { expect{ node_1.move_to_right_of(node_1) }.not_to change(current_tree, :all) }
|
105
|
+
it { expect{ node_3.move_to_right_of(node_3) }.not_to change(current_tree, :all) }
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'when attribute, not related to tree changed' do
|
109
|
+
before { @old_name = node_2.name }
|
110
|
+
before { node_2.name = 'new name' }
|
111
|
+
|
112
|
+
it { expect{node_2.move_to_right_of(node_4)}.to change(node_2, :name).to(@old_name) }
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
include_examples '#move_to_right_of', :default
|
118
|
+
include_examples '#move_to_right_of', :default_with_counter_cache
|
119
|
+
include_examples '#move_to_right_of', :scoped, :scope_type => 's'
|
120
|
+
end
|