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,354 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Movements, :non_transactional, :unless => ENV['DB'] == 'sqlite3' do
|
6
|
+
class ConcurrentTasks < Array
|
7
|
+
def task(&block)
|
8
|
+
push block
|
9
|
+
end
|
10
|
+
|
11
|
+
def spawn(suite)
|
12
|
+
map do |task|
|
13
|
+
thread { suite.instance_eval(&task) }
|
14
|
+
end.each(&:join)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def thread(&block)
|
19
|
+
Thread.start do
|
20
|
+
ActiveRecord::Base.connection_pool.with_connection(&block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.concurrent(&block)
|
26
|
+
tasks = ConcurrentTasks.new
|
27
|
+
tasks.instance_eval(&block)
|
28
|
+
|
29
|
+
before do
|
30
|
+
tasks.spawn(self)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
shared_examples 'Concurrency support' do |factory, attrs = {}|
|
35
|
+
context 'create root nodes in empty tree simultaneously' do
|
36
|
+
let(:current_tree) { FactoryGirl.factory_by_name(factory).build_class }
|
37
|
+
|
38
|
+
concurrent do
|
39
|
+
3.times { task { create factory, attrs } }
|
40
|
+
end
|
41
|
+
|
42
|
+
expect_tree_to_match {
|
43
|
+
any
|
44
|
+
any
|
45
|
+
any
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'add root nodes to existing tree simultaneously' do
|
50
|
+
tree :factory => factory, :attributes => attrs do
|
51
|
+
root
|
52
|
+
end
|
53
|
+
|
54
|
+
concurrent do
|
55
|
+
3.times { task { create factory, attrs } }
|
56
|
+
end
|
57
|
+
|
58
|
+
expect_tree_to_match {
|
59
|
+
root
|
60
|
+
any
|
61
|
+
any
|
62
|
+
any
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'create nodes on the same level simultaneously' do
|
67
|
+
tree :factory => factory do
|
68
|
+
root
|
69
|
+
end
|
70
|
+
|
71
|
+
concurrent do
|
72
|
+
3.times do
|
73
|
+
task { create factory, :parent => root }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
expect_tree_to_match {
|
78
|
+
root {
|
79
|
+
any
|
80
|
+
any
|
81
|
+
any
|
82
|
+
}
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'move same node simultaneously' do
|
87
|
+
tree :factory => factory, :attributes => attrs do
|
88
|
+
node_1
|
89
|
+
node_2
|
90
|
+
node_3
|
91
|
+
node_4
|
92
|
+
end
|
93
|
+
|
94
|
+
# node itself isn't thread safe
|
95
|
+
def moved_node
|
96
|
+
current_tree.find(node_2.id)
|
97
|
+
end
|
98
|
+
|
99
|
+
concurrent do
|
100
|
+
task { moved_node.move_higher }
|
101
|
+
task { moved_node.move_lower }
|
102
|
+
task { moved_node.move_to_right_of(node_4) }
|
103
|
+
end
|
104
|
+
|
105
|
+
expect_tree_to_match {
|
106
|
+
any
|
107
|
+
any
|
108
|
+
any
|
109
|
+
any
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'move nodes to same parent simultaneously' do
|
114
|
+
tree :factory => factory, :attributes => attrs do
|
115
|
+
root
|
116
|
+
node_1
|
117
|
+
node_2
|
118
|
+
node_3
|
119
|
+
end
|
120
|
+
|
121
|
+
concurrent do
|
122
|
+
task { node_1.move_to_child_of(root) }
|
123
|
+
task { node_2.move_to_child_of(root) }
|
124
|
+
task { node_3.move_to_child_of(root) }
|
125
|
+
end
|
126
|
+
|
127
|
+
expect_tree_to_match {
|
128
|
+
root {
|
129
|
+
any
|
130
|
+
any
|
131
|
+
any
|
132
|
+
}
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'move nodes to left of same root node simultaneously' do
|
137
|
+
tree :factory => factory, :attributes => attrs do
|
138
|
+
root_1
|
139
|
+
root_2 {
|
140
|
+
node_1
|
141
|
+
node_2
|
142
|
+
node_3
|
143
|
+
}
|
144
|
+
end
|
145
|
+
|
146
|
+
concurrent do
|
147
|
+
task { node_1.move_to_left_of(root_2) }
|
148
|
+
task { node_2.move_to_left_of(root_2) }
|
149
|
+
task { node_3.move_to_left_of(root_2) }
|
150
|
+
end
|
151
|
+
|
152
|
+
expect_tree_to_match {
|
153
|
+
root_1
|
154
|
+
any
|
155
|
+
any
|
156
|
+
any
|
157
|
+
root_2
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'move nodes to left of same non-root node simultaneously' do
|
162
|
+
tree :factory => factory do
|
163
|
+
root {
|
164
|
+
child_1
|
165
|
+
child_2 {
|
166
|
+
node_1
|
167
|
+
node_2
|
168
|
+
node_3
|
169
|
+
}
|
170
|
+
}
|
171
|
+
end
|
172
|
+
|
173
|
+
concurrent do
|
174
|
+
task { node_1.move_to_left_of(child_2) }
|
175
|
+
task { node_2.move_to_left_of(child_2) }
|
176
|
+
task { node_3.move_to_left_of(child_2) }
|
177
|
+
end
|
178
|
+
|
179
|
+
expect_tree_to_match {
|
180
|
+
root {
|
181
|
+
child_1
|
182
|
+
any
|
183
|
+
any
|
184
|
+
any
|
185
|
+
child_2
|
186
|
+
}
|
187
|
+
}
|
188
|
+
end
|
189
|
+
|
190
|
+
context 'move node to right of same root node simultaneously' do
|
191
|
+
tree :factory => factory, :attributes => attrs do
|
192
|
+
root_1 {
|
193
|
+
node_1
|
194
|
+
node_2
|
195
|
+
node_3
|
196
|
+
}
|
197
|
+
root_2
|
198
|
+
end
|
199
|
+
|
200
|
+
concurrent do
|
201
|
+
task { node_1.move_to_right_of(root_1) }
|
202
|
+
task { node_2.move_to_right_of(root_1) }
|
203
|
+
task { node_3.move_to_right_of(root_1) }
|
204
|
+
end
|
205
|
+
|
206
|
+
expect_tree_to_match {
|
207
|
+
root_1
|
208
|
+
any
|
209
|
+
any
|
210
|
+
any
|
211
|
+
root_2
|
212
|
+
}
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'move nodes to right of same non-root node simultaneously' do
|
216
|
+
tree :factory => factory do
|
217
|
+
root {
|
218
|
+
child_1 {
|
219
|
+
node_1
|
220
|
+
node_2
|
221
|
+
node_3
|
222
|
+
}
|
223
|
+
child_2
|
224
|
+
}
|
225
|
+
end
|
226
|
+
|
227
|
+
concurrent do
|
228
|
+
task { node_1.move_to_right_of(child_1) }
|
229
|
+
task { node_2.move_to_right_of(child_1) }
|
230
|
+
task { node_3.move_to_right_of(child_1) }
|
231
|
+
end
|
232
|
+
|
233
|
+
expect_tree_to_match {
|
234
|
+
root {
|
235
|
+
child_1
|
236
|
+
any
|
237
|
+
any
|
238
|
+
any
|
239
|
+
child_2
|
240
|
+
}
|
241
|
+
}
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'move nodes to root simultaneously' do
|
245
|
+
tree :factory => factory do
|
246
|
+
root {
|
247
|
+
node_1
|
248
|
+
node_2
|
249
|
+
node_3
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
concurrent do
|
254
|
+
task { node_1.move_to_root }
|
255
|
+
task { node_2.move_to_root }
|
256
|
+
task { node_3.move_to_root }
|
257
|
+
end
|
258
|
+
|
259
|
+
expect_tree_to_match {
|
260
|
+
root
|
261
|
+
any
|
262
|
+
any
|
263
|
+
any
|
264
|
+
}
|
265
|
+
end
|
266
|
+
|
267
|
+
context 'move nodes left simultaneously' do
|
268
|
+
tree :factory => factory do
|
269
|
+
root {
|
270
|
+
node_1
|
271
|
+
node_2
|
272
|
+
node_3
|
273
|
+
node_4
|
274
|
+
}
|
275
|
+
end
|
276
|
+
|
277
|
+
concurrent do
|
278
|
+
task { node_2.move_left }
|
279
|
+
task { node_3.move_left }
|
280
|
+
end
|
281
|
+
|
282
|
+
expect_tree_to_match {
|
283
|
+
root {
|
284
|
+
any
|
285
|
+
any
|
286
|
+
any
|
287
|
+
node_4
|
288
|
+
}
|
289
|
+
}
|
290
|
+
end
|
291
|
+
|
292
|
+
context 'move nodes right simultaneously' do
|
293
|
+
tree :factory => factory do
|
294
|
+
root {
|
295
|
+
node_1
|
296
|
+
node_2
|
297
|
+
node_3
|
298
|
+
node_4
|
299
|
+
}
|
300
|
+
end
|
301
|
+
|
302
|
+
concurrent do
|
303
|
+
task { node_2.move_right }
|
304
|
+
task { node_3.move_right }
|
305
|
+
end
|
306
|
+
|
307
|
+
expect_tree_to_match {
|
308
|
+
root {
|
309
|
+
node_1
|
310
|
+
any
|
311
|
+
any
|
312
|
+
any
|
313
|
+
}
|
314
|
+
}
|
315
|
+
end
|
316
|
+
|
317
|
+
context 'swap nodes between different branches simultaneously' do
|
318
|
+
tree :factory => factory do
|
319
|
+
root {
|
320
|
+
child_1 {
|
321
|
+
swap_1
|
322
|
+
other_1
|
323
|
+
}
|
324
|
+
child_2 {
|
325
|
+
other_2
|
326
|
+
swap_2
|
327
|
+
}
|
328
|
+
}
|
329
|
+
end
|
330
|
+
|
331
|
+
concurrent do
|
332
|
+
task { swap_1.move_to_child_with_position(child_2, 2) }
|
333
|
+
task { swap_2.move_to_child_with_position(child_1, 1) }
|
334
|
+
end
|
335
|
+
|
336
|
+
expect_tree_to_match {
|
337
|
+
root {
|
338
|
+
child_1 {
|
339
|
+
swap_2
|
340
|
+
other_1
|
341
|
+
}
|
342
|
+
child_2 {
|
343
|
+
other_2
|
344
|
+
swap_1
|
345
|
+
}
|
346
|
+
}
|
347
|
+
}
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
include_examples 'Concurrency support', :default
|
352
|
+
include_examples 'Concurrency support', :default_with_counter_cache
|
353
|
+
include_examples 'Concurrency support', :scoped, :scope_type => 's'
|
354
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Movements, '#move_higher', :transactional do
|
6
|
+
shared_examples '#move_higher' do |factory, attrs = {}|
|
7
|
+
describe "#move_higher #{factory}" do
|
8
|
+
tree :factory => factory, :attributes => attrs do
|
9
|
+
node_1
|
10
|
+
node_2
|
11
|
+
node_3
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'trying to move highest node up' do
|
15
|
+
before { node_1.move_higher }
|
16
|
+
|
17
|
+
expect_tree_to_match {
|
18
|
+
node_1
|
19
|
+
node_2
|
20
|
+
node_3
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'trying to move node with position > 1' do
|
25
|
+
before { node_2.move_higher }
|
26
|
+
|
27
|
+
expect_tree_to_match {
|
28
|
+
node_2
|
29
|
+
node_1
|
30
|
+
node_3
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when attribute, not related to tree changed' do
|
35
|
+
before { @old_name = node_3.name }
|
36
|
+
before { node_3.name = 'new name' }
|
37
|
+
|
38
|
+
it { expect{node_3.move_higher}.to change(node_3, :name).to(@old_name) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
include_examples '#move_higher', :default
|
44
|
+
include_examples '#move_higher', :default_with_counter_cache
|
45
|
+
include_examples '#move_higher', :scoped, :scope_type => 's'
|
46
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Movements, '#move_lower', :transactional do
|
6
|
+
shared_examples '#move_lower' do |factory, attrs = {}|
|
7
|
+
describe "#move_lower #{factory}" do
|
8
|
+
tree :factory => factory, :attributes => attrs do
|
9
|
+
node_1
|
10
|
+
node_2
|
11
|
+
node_3
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'trying to lowest node down' do
|
15
|
+
before { node_3.move_lower }
|
16
|
+
|
17
|
+
expect_tree_to_match {
|
18
|
+
node_1
|
19
|
+
node_2
|
20
|
+
node_3
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'trying to move node with not lowest position' do
|
25
|
+
before { node_2.move_lower }
|
26
|
+
|
27
|
+
expect_tree_to_match {
|
28
|
+
node_1
|
29
|
+
node_3
|
30
|
+
node_2
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when attribute, not related to tree changed' do
|
35
|
+
before { @old_name = node_2.name }
|
36
|
+
before { node_2.name = 'new name' }
|
37
|
+
|
38
|
+
it { expect{node_2.move_lower}.to change(node_2, :name).to(@old_name) }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
include_examples '#move_lower', :default
|
44
|
+
include_examples '#move_lower', :default_with_counter_cache
|
45
|
+
include_examples '#move_lower', :scoped, :scope_type => 's'
|
46
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ActsAsOrderedTree::Node::Movements, '#move_to_child_of', :transactional do
|
6
|
+
shared_examples '#move_to_child_of' do |factory|
|
7
|
+
describe "#move_to_child_of #{factory}" do
|
8
|
+
tree :factory => factory do
|
9
|
+
root {
|
10
|
+
child_1
|
11
|
+
child_2
|
12
|
+
child_3 {
|
13
|
+
child_4
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'when AR object given' do
|
19
|
+
it 'moves node' do
|
20
|
+
expect {
|
21
|
+
child_3.move_to_child_of(child_1)
|
22
|
+
}.to change(child_3, :parent).from(root).to(child_1)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'does not change attributes unrelated to tree' do
|
26
|
+
old, child_4.name = child_4.name, 'new name'
|
27
|
+
|
28
|
+
expect {
|
29
|
+
child_4.move_to_child_of(root)
|
30
|
+
}.to change(child_4, :name).to(old)
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'moving to child of self' do
|
34
|
+
it { expect(child_3.move_to_child_of(child_3)).to be false }
|
35
|
+
|
36
|
+
it 'does not move node' do
|
37
|
+
expect {
|
38
|
+
child_3.move_to_child_of(child_3)
|
39
|
+
}.not_to change(child_3, :reload)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'invalidates node' do
|
43
|
+
expect {
|
44
|
+
child_3.move_to_child_of(child_3)
|
45
|
+
}.to change(child_3, :valid?).from(true).to(false)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'moving to child of current parent' do
|
50
|
+
it 'does not move node' do
|
51
|
+
expect {
|
52
|
+
child_2.move_to_child_of(root)
|
53
|
+
}.not_to change(child_2, :reload)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'moving to child of descendant' do
|
58
|
+
it { expect(root.move_to_child_of(child_1)).to be false }
|
59
|
+
|
60
|
+
it 'does node move node' do
|
61
|
+
expect {
|
62
|
+
root.move_to_child_of(child_1)
|
63
|
+
}.not_to change(root, :reload)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'invalidates node' do
|
67
|
+
expect {
|
68
|
+
root.move_to_child_of(child_1)
|
69
|
+
}.to change(root, :valid?).from(true).to(false)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'moving node deeper' do
|
74
|
+
before { child_3.move_to_child_of(child_2) }
|
75
|
+
|
76
|
+
expect_tree_to_match {
|
77
|
+
root {
|
78
|
+
child_1
|
79
|
+
child_2 {
|
80
|
+
child_3 {
|
81
|
+
child_4
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'moving node upper' do
|
89
|
+
before { child_4.move_to_child_of(root) }
|
90
|
+
|
91
|
+
expect_tree_to_match {
|
92
|
+
root {
|
93
|
+
child_1
|
94
|
+
child_2
|
95
|
+
child_3
|
96
|
+
child_4
|
97
|
+
}
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
context 'when ID given' do
|
103
|
+
it 'moves node' do
|
104
|
+
expect {
|
105
|
+
child_3.move_to_child_of(child_1.id)
|
106
|
+
}.to change(child_3, :parent).from(root).to(child_1)
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'does not move node if parent was not changed' do
|
110
|
+
expect {
|
111
|
+
child_2.move_to_child_of(root.id)
|
112
|
+
}.not_to change(child_2, :reload)
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'moving to non-existent ID' do
|
116
|
+
before { allow(child_3).to receive(:valid?).and_return(false) }
|
117
|
+
|
118
|
+
it { expect(child_3.move_to_child_of(-1)).to be false }
|
119
|
+
|
120
|
+
it 'does not move node' do
|
121
|
+
expect {
|
122
|
+
child_3.move_to_child_of(-1)
|
123
|
+
}.not_to change(child_3, :reload)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
context 'when nil given' do
|
129
|
+
before { child_2.move_to_child_of(nil) }
|
130
|
+
|
131
|
+
expect_tree_to_match {
|
132
|
+
root {
|
133
|
+
child_1
|
134
|
+
child_3 {
|
135
|
+
child_4
|
136
|
+
}
|
137
|
+
}
|
138
|
+
child_2
|
139
|
+
}
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
include_examples '#move_to_child_of', :default
|
145
|
+
include_examples '#move_to_child_of', :default_with_counter_cache
|
146
|
+
include_examples '#move_to_child_of', :scoped
|
147
|
+
end
|