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,67 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Movements, '#move_to_root', :transactional do
|
6
|
+
shared_examples '#move_to_root' do |factory, attrs = {}|
|
7
|
+
describe "#move_to_root #{factory}" do
|
8
|
+
tree :factory => factory, :attributes => attrs do
|
9
|
+
root_1 {
|
10
|
+
node_1
|
11
|
+
node_2
|
12
|
+
node_3 {
|
13
|
+
node_4
|
14
|
+
}
|
15
|
+
}
|
16
|
+
root_2 {
|
17
|
+
node_5
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'moving root node to root' do
|
22
|
+
before { root_2.move_to_root }
|
23
|
+
|
24
|
+
expect_tree_to_match {
|
25
|
+
root_1 {
|
26
|
+
node_1
|
27
|
+
node_2
|
28
|
+
node_3 {
|
29
|
+
node_4
|
30
|
+
}
|
31
|
+
}
|
32
|
+
root_2 {
|
33
|
+
node_5
|
34
|
+
}
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'moving inner node to root' do
|
39
|
+
before { node_3.move_to_root }
|
40
|
+
|
41
|
+
expect_tree_to_match {
|
42
|
+
root_1 {
|
43
|
+
node_1
|
44
|
+
node_2
|
45
|
+
}
|
46
|
+
root_2 {
|
47
|
+
node_5
|
48
|
+
}
|
49
|
+
node_3 {
|
50
|
+
node_4
|
51
|
+
}
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when attribute, not related to tree changed' do
|
56
|
+
before { @old_name = node_2.name }
|
57
|
+
before { node_2.name = 'new name' }
|
58
|
+
|
59
|
+
it { expect{node_2.move_to_root}.to change(node_2, :name).to(@old_name) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
include_examples '#move_to_root', :default
|
65
|
+
include_examples '#move_to_root', :default_with_counter_cache
|
66
|
+
include_examples '#move_to_root', :scoped, :scope_type => 's'
|
67
|
+
end
|
@@ -0,0 +1,211 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Predicates, :transactional do
|
6
|
+
shared_examples 'ActsAsOrderedTree::Node predicates' do |model, attrs = {}|
|
7
|
+
describe model do
|
8
|
+
let!(:root) { create model, attrs }
|
9
|
+
let!(:child) { create model, attrs.merge(:parent => root) }
|
10
|
+
let!(:grandchild) { create model, attrs.merge(:parent => child) }
|
11
|
+
|
12
|
+
let(:counter_cached?) { root.class.ordered_tree.columns.counter_cache? }
|
13
|
+
|
14
|
+
before { [root, child, grandchild].each(&:reload) }
|
15
|
+
|
16
|
+
describe '#root?' do
|
17
|
+
it { expect(root).to be_root }
|
18
|
+
it { expect(child).not_to be_root }
|
19
|
+
it { expect(grandchild).not_to be_root }
|
20
|
+
|
21
|
+
it { expect{root.root?}.not_to query_database }
|
22
|
+
it { expect{child.root?}.not_to query_database }
|
23
|
+
it { expect{grandchild.root?}.not_to query_database }
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#has_parent?' do
|
27
|
+
it { expect(root).not_to have_parent }
|
28
|
+
it { expect(child).to have_parent }
|
29
|
+
it { expect(grandchild).to have_parent }
|
30
|
+
|
31
|
+
it { expect{root.has_parent?}.not_to query_database }
|
32
|
+
it { expect{child.has_parent?}.not_to query_database }
|
33
|
+
it { expect{grandchild.has_parent?}.not_to query_database }
|
34
|
+
|
35
|
+
it 'should be aliased but deprecated as #child?' do
|
36
|
+
expect(ActiveSupport::Deprecation).to receive(:warn)
|
37
|
+
expect(root).to receive(:has_parent?)
|
38
|
+
ActiveSupport::Deprecation.silence{root.child?}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#leaf?' do
|
43
|
+
it { expect(root).not_to be_leaf }
|
44
|
+
it { expect(child).not_to be_leaf }
|
45
|
+
it { expect(grandchild).to be_leaf }
|
46
|
+
|
47
|
+
context 'when new record given' do
|
48
|
+
let(:record) { build model, attrs }
|
49
|
+
|
50
|
+
it { expect(record).not_to be_leaf }
|
51
|
+
it { expect{record.leaf?}.not_to query_database }
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'when :children association is loaded' do
|
55
|
+
before { root.children << build(model, attrs) }
|
56
|
+
before { root.children.reload }
|
57
|
+
|
58
|
+
it { expect(root).not_to be_leaf }
|
59
|
+
it { expect{root.leaf?}.not_to query_database }
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when :children association is not loaded' do
|
63
|
+
before { root.children << build(model, attrs) }
|
64
|
+
before { root.reload }
|
65
|
+
|
66
|
+
it { expect(root).not_to be_leaf }
|
67
|
+
it do
|
68
|
+
if counter_cached?
|
69
|
+
expect{root.leaf?}.not_to query_database
|
70
|
+
else
|
71
|
+
# we must check that #leaf? is optimized
|
72
|
+
expect{root.leaf?}.not_to query_database(/COUNT/)
|
73
|
+
expect{root.leaf?}.to query_database(/LIMIT 1/i)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#has_children?' do
|
80
|
+
# opposite of #leaf?
|
81
|
+
it { expect(root).to have_children }
|
82
|
+
it { expect(child).to have_children }
|
83
|
+
it { expect(grandchild).not_to have_children }
|
84
|
+
|
85
|
+
it 'should be aliased but deprecated as #branch?' do
|
86
|
+
expect(ActiveSupport::Deprecation).to receive(:warn)
|
87
|
+
expect(root).to receive(:has_children?)
|
88
|
+
ActiveSupport::Deprecation.silence{root.branch?}
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#is_descendant_of?' do
|
93
|
+
it { expect(root) }
|
94
|
+
end
|
95
|
+
|
96
|
+
describe '#is_(or_is)_(descendant|ancestor)_of?' do
|
97
|
+
matrix3d = Hash[
|
98
|
+
:is_descendant_of? => Hash[
|
99
|
+
:root => {:root => false, :child => false, :grandchild => false},
|
100
|
+
:child => {:root => true, :child => false, :grandchild => false},
|
101
|
+
:grandchild => {:root => true, :child => true, :grandchild => false}
|
102
|
+
],
|
103
|
+
:is_or_is_descendant_of? => Hash[
|
104
|
+
:root => {:root => true, :child => false, :grandchild => false},
|
105
|
+
:child => {:root => true, :child => true, :grandchild => false},
|
106
|
+
:grandchild => {:root => true, :child => true, :grandchild => true}
|
107
|
+
],
|
108
|
+
:is_ancestor_of? => Hash[
|
109
|
+
:root => {:root => false, :child => true, :grandchild => true},
|
110
|
+
:child => {:root => false, :child => false, :grandchild => true},
|
111
|
+
:grandchild => {:root => false, :child => false, :grandchild => false}
|
112
|
+
],
|
113
|
+
:is_or_is_ancestor_of? => Hash[
|
114
|
+
:root => {:root => true, :child => true, :grandchild => true},
|
115
|
+
:child => {:root => false, :child => true, :grandchild => true},
|
116
|
+
:grandchild => {:root => false, :child => false, :grandchild => true}
|
117
|
+
]
|
118
|
+
]
|
119
|
+
|
120
|
+
matrix3d.each do |method, matrix|
|
121
|
+
matrix.each do |node, examples|
|
122
|
+
examples.each do |target, expectation|
|
123
|
+
it "expect that #{node}.#{method}(#{target}) == #{expectation.inspect}" do
|
124
|
+
expect(send(node).send(method, send(target))).to eq expectation
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
describe model do
|
134
|
+
let!(:list) { create_list model, 3, attrs }
|
135
|
+
let(:first) { list[0] }
|
136
|
+
let(:second) { list[1] }
|
137
|
+
let(:third) { list[2] }
|
138
|
+
|
139
|
+
describe '#first?' do
|
140
|
+
it { expect(first).to be_first }
|
141
|
+
it { expect(second).not_to be_first }
|
142
|
+
it { expect(third).not_to be_first }
|
143
|
+
|
144
|
+
it 'does not query database' do
|
145
|
+
list.each do |node|
|
146
|
+
expect{node.first?}.not_to query_database
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe '#last?' do
|
152
|
+
it { expect(first).not_to be_last }
|
153
|
+
it { expect(second).not_to be_last }
|
154
|
+
it { expect(third).to be_last }
|
155
|
+
|
156
|
+
it { expect{first.last?}.to query_database(/LIMIT 1/i).once }
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
include_examples 'ActsAsOrderedTree::Node predicates', :default
|
162
|
+
include_examples 'ActsAsOrderedTree::Node predicates', :default_with_counter_cache do
|
163
|
+
describe '#last?' do
|
164
|
+
context 'when node is child' do
|
165
|
+
let(:root) { create :default_with_counter_cache }
|
166
|
+
let!(:node) { create :default_with_counter_cache, :parent => root }
|
167
|
+
|
168
|
+
context 'when parent is loaded' do
|
169
|
+
before { node.association(:parent).reload }
|
170
|
+
|
171
|
+
it { expect(node).to be_last }
|
172
|
+
it { expect{node.last?}.not_to query_database }
|
173
|
+
end
|
174
|
+
|
175
|
+
context 'when parent is not loaded' do
|
176
|
+
before { node.reload }
|
177
|
+
it { expect(node).to be_last }
|
178
|
+
it { expect{node.last?}.to query_database.once }
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
include_examples 'ActsAsOrderedTree::Node predicates', :scoped, :scope_type => 's' do
|
185
|
+
describe '#is_(or_is)_(descendant|ancestor)_of?' do
|
186
|
+
context 'when nodes belong to different scopes' do
|
187
|
+
let(:root) { create :scoped, :scope_type => 'a' }
|
188
|
+
let(:child) { create :scoped, :parent => root }
|
189
|
+
# hack it
|
190
|
+
before { child.scope_type = 'b' }
|
191
|
+
before { child.class.where(:id => child.id).update_all(['scope_type = ?', 'b']) }
|
192
|
+
|
193
|
+
context 'when parent association is cached and cache is stale' do
|
194
|
+
it { expect(root.is_ancestor_of?(child)).to be false }
|
195
|
+
it { expect(root.is_or_is_ancestor_of?(child)).to be false }
|
196
|
+
it { expect(child.is_descendant_of?(root)).to be false }
|
197
|
+
it { expect(child.is_or_is_descendant_of?(root)).to be false }
|
198
|
+
end
|
199
|
+
|
200
|
+
context 'when parent association is not loaded' do
|
201
|
+
before { child.reload }
|
202
|
+
|
203
|
+
it { expect(root.is_ancestor_of?(child)).to be false }
|
204
|
+
it { expect(root.is_or_is_ancestor_of?(child)).to be false }
|
205
|
+
it { expect(child.is_descendant_of?(root)).to be false }
|
206
|
+
it { expect(child.is_or_is_descendant_of?(root)).to be false }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Reloading, :transactional do
|
6
|
+
shared_examples 'ActsAsOrderedTree::Node#reload' do |model, attrs = {}|
|
7
|
+
describe model.to_s.camelize, '#reload' do
|
8
|
+
let(:record) { create model, attrs }
|
9
|
+
let(:node) { record.ordered_tree_node }
|
10
|
+
|
11
|
+
# change all attributes
|
12
|
+
before { node.parent_id = create(model, attrs).id }
|
13
|
+
before { node.position = 3 }
|
14
|
+
before { node.depth = 2 if record.ordered_tree.columns.depth? }
|
15
|
+
before { record[record.ordered_tree.columns.counter_cache] = 5 if record.ordered_tree.columns.counter_cache? }
|
16
|
+
before { record.name = 'another name' }
|
17
|
+
|
18
|
+
it 'reloads attributes related to tree' do
|
19
|
+
node.reload
|
20
|
+
|
21
|
+
expect(node.parent_id).to eq nil
|
22
|
+
expect(node.position).to eq 1
|
23
|
+
|
24
|
+
if record.ordered_tree.columns.depth?
|
25
|
+
expect(node.depth).to eq 0
|
26
|
+
end
|
27
|
+
|
28
|
+
if record.class.ordered_tree.columns.counter_cache?
|
29
|
+
expect(record.children.size).to eq 0
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'does not reload another attributes' do
|
34
|
+
expect{node.reload}.not_to change(record, :name)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
include_examples 'ActsAsOrderedTree::Node#reload', :default
|
40
|
+
include_examples 'ActsAsOrderedTree::Node#reload', :default_with_counter_cache
|
41
|
+
include_examples 'ActsAsOrderedTree::Node#reload', :scoped
|
42
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Siblings, :transactional do
|
6
|
+
shared_examples 'siblings' do |model|
|
7
|
+
# silence pending examples
|
8
|
+
#
|
9
|
+
# @todo fix all xits
|
10
|
+
def self.xit(*) end
|
11
|
+
|
12
|
+
let(:root) { create model }
|
13
|
+
let(:items) { create_list model, 3, :parent => root }
|
14
|
+
|
15
|
+
# first
|
16
|
+
it { expect(items.first.self_and_siblings).to eq items }
|
17
|
+
it { expect(items.first.siblings).to eq [items.second, items.last] }
|
18
|
+
|
19
|
+
it { expect(items.first.left_sibling).to be nil }
|
20
|
+
it { expect(items.first.right_sibling).to eq items.second }
|
21
|
+
|
22
|
+
it { expect(items.first.left_siblings).to be_empty }
|
23
|
+
it { expect(items.first.right_siblings).to eq [items.second, items.last] }
|
24
|
+
|
25
|
+
# second
|
26
|
+
it { expect(items.second.self_and_siblings).to eq items }
|
27
|
+
it { expect(items.second.siblings).to eq [items.first, items.last] }
|
28
|
+
|
29
|
+
it { expect(items.second.left_sibling).to eq items.first }
|
30
|
+
it { expect(items.second.right_sibling).to eq items.last }
|
31
|
+
|
32
|
+
it { expect(items.second.left_siblings).to eq [items.first] }
|
33
|
+
it { expect(items.second.right_siblings).to eq [items.last] }
|
34
|
+
|
35
|
+
# last
|
36
|
+
it { expect(items.last.self_and_siblings).to eq items }
|
37
|
+
it { expect(items.last.siblings).to eq [items.first, items.second] }
|
38
|
+
|
39
|
+
it { expect(items.last.left_sibling).to eq items.second }
|
40
|
+
it { expect(items.last.right_sibling).to be nil }
|
41
|
+
|
42
|
+
it { expect(items.last.left_siblings).to eq [items.first, items.second] }
|
43
|
+
it { expect(items.last.right_siblings).to be_empty }
|
44
|
+
|
45
|
+
context 'trying to set left or right sibling with random object' do
|
46
|
+
def self.expect_type_mismatch_on(value)
|
47
|
+
it "throws error when #{value.class} given" do
|
48
|
+
expect {
|
49
|
+
items.first.left_sibling = value
|
50
|
+
}.to raise_error ActiveRecord::AssociationTypeMismatch
|
51
|
+
|
52
|
+
expect {
|
53
|
+
items.first.right_sibling = value
|
54
|
+
}.to raise_error ActiveRecord::AssociationTypeMismatch
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.generate_class
|
59
|
+
Class.new(ActiveRecord::Base){ self.table_name = 'categories' }
|
60
|
+
end
|
61
|
+
|
62
|
+
expect_type_mismatch_on(generate_class.new)
|
63
|
+
expect_type_mismatch_on(nil)
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when left sibling is set' do
|
67
|
+
context 'and new left sibling has same parent' do
|
68
|
+
context 'and new left sibling is higher' do
|
69
|
+
let(:item) { items.last }
|
70
|
+
before { item.left_sibling = items.first }
|
71
|
+
|
72
|
+
it { expect(item.parent).to eq items.first.parent }
|
73
|
+
it { expect(item.position).to eq 2 }
|
74
|
+
|
75
|
+
xit { expect(item.left_sibling).to eq items.first }
|
76
|
+
xit { expect(item.right_siblings).to eq [items.second] }
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'and new left sibling is lower' do
|
80
|
+
let(:item) { items.first }
|
81
|
+
before { item.left_sibling = items.last }
|
82
|
+
|
83
|
+
it { expect(item.parent).to eq items.first.parent }
|
84
|
+
it { expect(item.position).to eq 3 }
|
85
|
+
|
86
|
+
xit { expect(item.left_sibling).to eq items.last }
|
87
|
+
xit { expect(item.left_siblings).to eq [items.second, items.last] }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
context 'and new left sibling has other parent' do
|
92
|
+
let(:item) { items.first }
|
93
|
+
before { item.left_sibling = root }
|
94
|
+
|
95
|
+
it { expect(item.parent).to be nil }
|
96
|
+
it { expect(item.position).to eq 2 }
|
97
|
+
|
98
|
+
xit { expect(item.left_sibling).to eq root }
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'via #left_sibling_id=' do
|
102
|
+
let(:item) { items.first }
|
103
|
+
|
104
|
+
it 'throws error when non-existent ID given' do
|
105
|
+
expect {
|
106
|
+
item.left_sibling_id = -1
|
107
|
+
}.to raise_error ActiveRecord::RecordNotFound
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'delegates to #left_sibling=' do
|
111
|
+
new_sibling = items.last
|
112
|
+
|
113
|
+
expect(item.ordered_tree_node).to receive(:left_sibling=).with(new_sibling)
|
114
|
+
item.left_sibling_id = new_sibling.id
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'when right sibling is set' do
|
120
|
+
context 'and new right sibling has same parent' do
|
121
|
+
context 'and new right sibling is higher' do
|
122
|
+
let(:item) { items.last }
|
123
|
+
before { item.right_sibling = items.first }
|
124
|
+
|
125
|
+
it { expect(item.parent).to eq items.first.parent }
|
126
|
+
it { expect(item.position).to eq 1 }
|
127
|
+
|
128
|
+
xit { expect(item.right_sibling).to eq item.first }
|
129
|
+
xit { expect(item.left_siblings).to be_empty }
|
130
|
+
xit { expect(item.right_siblings).to eq [items.first, items.second] }
|
131
|
+
end
|
132
|
+
|
133
|
+
context 'and new right sibling is lower' do
|
134
|
+
let(:item) { items.first }
|
135
|
+
before { item.right_sibling = items.last }
|
136
|
+
|
137
|
+
it { expect(item.parent).to eq items.first.parent }
|
138
|
+
it { expect(item.position).to eq 2 }
|
139
|
+
|
140
|
+
xit { expect(item.right_sibling).to eq items.last }
|
141
|
+
xit { expect(item.right_siblings).to eq [items.last] }
|
142
|
+
|
143
|
+
xit { expect(item.left_sibling).to eq items.first }
|
144
|
+
xit { expect(item.left_siblings).to eq [items.first] }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'and new right sibling has other parent' do
|
149
|
+
let(:item) { items.first }
|
150
|
+
before { item.right_sibling = root }
|
151
|
+
|
152
|
+
it { expect(item.parent).to be nil }
|
153
|
+
it { expect(item.position).to eq 1 }
|
154
|
+
|
155
|
+
xit { expect(item.right_sibling).to eq root }
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'via #right_sibling_id=' do
|
159
|
+
let(:item) { items.first }
|
160
|
+
|
161
|
+
it 'throws error when non-existent ID given' do
|
162
|
+
expect {
|
163
|
+
item.right_sibling_id = -1
|
164
|
+
}.to raise_error ActiveRecord::RecordNotFound
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'delegates to #right_sibling=' do
|
168
|
+
new_sibling = items.last
|
169
|
+
|
170
|
+
expect(item.ordered_tree_node).to receive(:right_sibling=).with(new_sibling)
|
171
|
+
item.right_sibling_id = new_sibling.id
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'Tree without scopes' do
|
178
|
+
include_examples 'siblings', :default
|
179
|
+
include_examples 'siblings', :default_with_counter_cache
|
180
|
+
end
|
181
|
+
|
182
|
+
context 'Tree with scope' do
|
183
|
+
let!(:items_1) { create_list :scoped, 3, :scope_type => 's1' }
|
184
|
+
let!(:items_2) { create_list :scoped, 3, :scope_type => 's2' }
|
185
|
+
|
186
|
+
include_examples 'siblings', :scoped do
|
187
|
+
let(:items) { items_1 }
|
188
|
+
end
|
189
|
+
include_examples 'siblings', :scoped do
|
190
|
+
let(:items) { items_2 }
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|