mongoid-tree-rational 0.1.0
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.
- data/.rspec +2 -0
- data/.travis.yml +12 -0
- data/Gemfile +23 -0
- data/Guardfile +6 -0
- data/LICENSE +21 -0
- data/README.md +287 -0
- data/Rakefile +63 -0
- data/VERSION +1 -0
- data/lib/mongoid/locale/en.yml +11 -0
- data/lib/mongoid/locale/nb.yml +8 -0
- data/lib/mongoid/tree.rb +443 -0
- data/lib/mongoid/tree/ordering.rb +236 -0
- data/lib/mongoid/tree/rational_numbering.rb +805 -0
- data/lib/mongoid/tree/traversal.rb +122 -0
- data/mongoid-tree-rational.gemspec +103 -0
- data/spec/mongoid/tree/ordering_spec.rb +342 -0
- data/spec/mongoid/tree/rational_numbering_spec.rb +765 -0
- data/spec/mongoid/tree/traversal_spec.rb +177 -0
- data/spec/mongoid/tree_spec.rb +444 -0
- data/spec/spec_helper.rb +31 -0
- data/spec/support/macros/tree_macros.rb +53 -0
- data/spec/support/models/node.rb +47 -0
- metadata +320 -0
@@ -0,0 +1,765 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongoid::Tree::RationalNumbering do
|
4
|
+
|
5
|
+
subject { RationalNumberedNode }
|
6
|
+
|
7
|
+
it "should verify type of initial rational numbers" do
|
8
|
+
f_nv = RationalNumberedNode.fields['rational_number_nv']
|
9
|
+
f_dv = RationalNumberedNode.fields['rational_number_dv']
|
10
|
+
f_snv = RationalNumberedNode.fields['rational_number_snv']
|
11
|
+
f_sdv = RationalNumberedNode.fields['rational_number_sdv']
|
12
|
+
f_value = RationalNumberedNode.fields['rational_number_value']
|
13
|
+
expect(f_nv).not_to be_nil
|
14
|
+
expect(f_nv.options[:type]).to eq(Integer)
|
15
|
+
expect(f_dv).not_to be_nil
|
16
|
+
expect(f_dv.options[:type]).to eq(Integer)
|
17
|
+
expect(f_snv).not_to be_nil
|
18
|
+
expect(f_snv.options[:type]).to eq(Integer)
|
19
|
+
expect(f_sdv).not_to be_nil
|
20
|
+
expect(f_sdv.options[:type]).to eq(Integer)
|
21
|
+
expect(f_value).not_to be_nil
|
22
|
+
expect(f_value.options[:type]).to eq(BigDecimal)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should have same numbers as in the paper for rational number in nested sets theory' do
|
26
|
+
setup_tree <<-ENDTREE
|
27
|
+
- node_1
|
28
|
+
- node_2:
|
29
|
+
- node_2_1
|
30
|
+
- node_2_2
|
31
|
+
- node_2_3
|
32
|
+
- node_2_4:
|
33
|
+
- node_2_4_1
|
34
|
+
- node_2_4_2
|
35
|
+
- node_2_4_3
|
36
|
+
ENDTREE
|
37
|
+
|
38
|
+
expect(node(:node_1).rational_number).to eq(RationalNumber.new(1,1))
|
39
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(2,1))
|
40
|
+
expect(node(:node_2_1).rational_number).to eq(RationalNumber.new(5,2))
|
41
|
+
expect(node(:node_2_2).rational_number).to eq(RationalNumber.new(8,3))
|
42
|
+
expect(node(:node_2_3).rational_number).to eq(RationalNumber.new(11,4))
|
43
|
+
expect(node(:node_2_4).rational_number).to eq(RationalNumber.new(14,5))
|
44
|
+
expect(node(:node_2_4_1).rational_number).to eq(RationalNumber.new(31,11))
|
45
|
+
expect(node(:node_2_4_2).rational_number).to eq(RationalNumber.new(48,17))
|
46
|
+
expect(node(:node_2_4_3).rational_number).to eq(RationalNumber.new(65,23))
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "for roots" do
|
50
|
+
it "should create a root node with initial rational numbers" do
|
51
|
+
a = RationalNumberedNode.create(:name => "a")
|
52
|
+
expect(a.rational_number).to eq(RationalNumber.new(1,1,2,1))
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should create two root nodes with initial rational numbers" do
|
56
|
+
a = RationalNumberedNode.create(:name => "a")
|
57
|
+
expect(a.rational_number).to eq(RationalNumber.new(1,1,2,1))
|
58
|
+
b = RationalNumberedNode.create(:name => "b")
|
59
|
+
expect(b.rational_number).to eq(RationalNumber.new(2,1,3,1))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
describe "when setting parent/children" do
|
65
|
+
|
66
|
+
it "should set the parent of a node after creating the object" do
|
67
|
+
a = RationalNumberedNode.create(:name => "a")
|
68
|
+
b = RationalNumberedNode.create(:name => "b")
|
69
|
+
b.parent = a
|
70
|
+
b.save!
|
71
|
+
expect(a.rational_number).to eq(RationalNumber.new(1,1,2,1))
|
72
|
+
expect(b.rational_number).to eq(RationalNumber.new(3,2,5,3))
|
73
|
+
end
|
74
|
+
|
75
|
+
# TODO
|
76
|
+
# it "should set the parent when creating the object" do
|
77
|
+
# end
|
78
|
+
|
79
|
+
it "should add children to an existing node" do
|
80
|
+
a = RationalNumberedNode.create(:name => "a")
|
81
|
+
b = RationalNumberedNode.create(:name => "b")
|
82
|
+
a.children << b
|
83
|
+
expect(a.rational_number).to eq(RationalNumber.new(1,1,2,1))
|
84
|
+
expect(b.rational_number).to eq(RationalNumber.new(3,2,5,3))
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe 'when saved' do
|
89
|
+
before(:each) do
|
90
|
+
|
91
|
+
setup_tree <<-ENDTREE
|
92
|
+
- node_1:
|
93
|
+
- node_1_1:
|
94
|
+
- node_1_1_1:
|
95
|
+
- node_1_1_1_1
|
96
|
+
- node_1_2
|
97
|
+
- node_1_3
|
98
|
+
- node_2:
|
99
|
+
- node_2_1
|
100
|
+
- node_2_2
|
101
|
+
ENDTREE
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should assign a rational number to each node" do
|
105
|
+
expect(node(:node_1).rational_number).to eq(RationalNumber.new(1,1,2,1))
|
106
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(2,1,3,1))
|
107
|
+
expect(node(:node_1_1).rational_number).to eq(RationalNumber.new(3,2,5,3))
|
108
|
+
expect(node(:node_1_2).rational_number).to eq(RationalNumber.new(5,3,7,4))
|
109
|
+
expect(node(:node_2_1).rational_number).to eq(RationalNumber.new(5,2,8,3))
|
110
|
+
expect(node(:node_2_2).rational_number).to eq(RationalNumber.new(8,3,11,4))
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should get the position for each of the nodes" do
|
114
|
+
expect(node(:node_1).position).to eq(1)
|
115
|
+
expect(node(:node_1_1).position).to eq(1)
|
116
|
+
expect(node(:node_1_2).position).to eq(2)
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should move a node to the end of a list when it is moved to a new parent" do
|
120
|
+
original_root = node(:node_1)
|
121
|
+
other_root = node(:node_2)
|
122
|
+
child = node(:node_1_2)
|
123
|
+
expect(child.position).to eq(2)
|
124
|
+
child.parent = other_root
|
125
|
+
child.save
|
126
|
+
child.reload
|
127
|
+
expect(child.position).to eq(3)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should correctly reposition siblings when one of them is removed" do
|
131
|
+
rational_node_1_1 = node(:node_1_1).rational_number
|
132
|
+
node(:node_1_1).destroy
|
133
|
+
expect(node(:node_1_2).position).to eq(1)
|
134
|
+
expect(node(:node_1_2).rational_number).to eq(RationalNumber.new(3,2,5,3))
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should correctly reposition siblings when one of them is added as a child of another parent" do
|
138
|
+
node(:node_2).children << node(:node_1_1)
|
139
|
+
expect(node(:node_1_2).position).to eq(1)
|
140
|
+
expect(node(:node_1_2).rational_number).to eq(RationalNumber.new(3,2,5,3))
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should correctly reposition siblings when the parent is changed" do
|
144
|
+
n = node(:node_1_1)
|
145
|
+
n.parent = node(:node_2)
|
146
|
+
n.save!
|
147
|
+
expect(node(:node_1_2).position).to eq(1)
|
148
|
+
expect(node(:node_1_2).rational_number).to eq(RationalNumber.new(3,2,5,3))
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should not reposition siblings when it's not needed" do
|
152
|
+
new_node = RationalNumberedNode.new(:name => 'new')
|
153
|
+
new_node.parent = node(:node_1)
|
154
|
+
expect(new_node).not_to receive(:rekey_former_siblings)
|
155
|
+
new_node.save!
|
156
|
+
end
|
157
|
+
|
158
|
+
end
|
159
|
+
|
160
|
+
describe 'destroy strategies' do
|
161
|
+
# before(:each) do
|
162
|
+
# setup_tree <<-ENDTREE
|
163
|
+
# - root:
|
164
|
+
# - child:
|
165
|
+
# - subchild
|
166
|
+
# - other_child
|
167
|
+
# - other_root
|
168
|
+
# ENDTREE
|
169
|
+
# end
|
170
|
+
|
171
|
+
# describe ':move_children_to_parent' do
|
172
|
+
# it "should set its childen's parent_id to the documents parent_id" do
|
173
|
+
# node(:child).move_children_to_parent
|
174
|
+
# node(:child).should be_leaf
|
175
|
+
# node(:root).children.to_a.should == [node(:child), node(:other_child), node(:subchild)]
|
176
|
+
# end
|
177
|
+
# end
|
178
|
+
end
|
179
|
+
|
180
|
+
describe 'utility methods' do
|
181
|
+
before(:each) do
|
182
|
+
setup_tree <<-ENDTREE
|
183
|
+
- node_1:
|
184
|
+
- node_1_1:
|
185
|
+
- node_1_1_1:
|
186
|
+
- node_1_1_1_1
|
187
|
+
- node_1_2
|
188
|
+
- node_1_3
|
189
|
+
- node_2:
|
190
|
+
- node_2_1
|
191
|
+
- node_2_2
|
192
|
+
- node_3
|
193
|
+
ENDTREE
|
194
|
+
end
|
195
|
+
|
196
|
+
describe '#lower_siblings' do
|
197
|
+
it "should return a collection of siblings lower on the list" do
|
198
|
+
expect(node(:node_1).lower_siblings.to_a).to eq([node(:node_2), node(:node_3)])
|
199
|
+
expect(node(:node_2).lower_siblings.to_a).to eq([node(:node_3)])
|
200
|
+
expect(node(:node_3).lower_siblings.to_a).to eq([])
|
201
|
+
expect(node(:node_1_1).lower_siblings.to_a).to eq([node(:node_1_2), node(:node_1_3)])
|
202
|
+
expect(node(:node_2_2).lower_siblings.to_a).to eq([])
|
203
|
+
expect(node(:node_1_1_1).lower_siblings.to_a).to eq([])
|
204
|
+
expect(node(:node_1_1_1_1).lower_siblings.to_a).to eq([])
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
describe '#higher_siblings' do
|
209
|
+
it "should return a collection of siblings lower on the list" do
|
210
|
+
expect(node(:node_1).higher_siblings.to_a).to eq([])
|
211
|
+
expect(node(:node_2).higher_siblings.to_a).to eq([node(:node_1)])
|
212
|
+
expect(node(:node_3).higher_siblings.to_a).to eq([node(:node_1), node(:node_2)])
|
213
|
+
expect(node(:node_1_1).higher_siblings.to_a).to eq([])
|
214
|
+
expect(node(:node_1_2).higher_siblings.to_a).to eq([node(:node_1_1)])
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe '#at_top?' do
|
219
|
+
it "should return true when the node is first in the list" do
|
220
|
+
expect(node(:node_1)).to be_at_top
|
221
|
+
expect(node(:node_1_1)).to be_at_top
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should return false when the node is not first in the list" do
|
225
|
+
expect(node(:node_2)).not_to be_at_top
|
226
|
+
expect(node(:node_3)).not_to be_at_top
|
227
|
+
expect(node(:node_1_2)).not_to be_at_top
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
describe '#at_bottom?' do
|
232
|
+
it "should return true when the node is last in the list" do
|
233
|
+
expect(node(:node_3)).to be_at_bottom
|
234
|
+
expect(node(:node_1_3)).to be_at_bottom
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should return false when the node is not last in the list" do
|
238
|
+
expect(node(:node_1)).not_to be_at_bottom
|
239
|
+
expect(node(:node_2)).not_to be_at_bottom
|
240
|
+
expect(node(:node_1_1)).not_to be_at_bottom
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
describe '#last_sibling_in_list' do
|
245
|
+
it "should return the last sibling in the list containing the current sibling" do
|
246
|
+
expect(node(:node_1).last_sibling_in_list).to eq(node(:node_3))
|
247
|
+
expect(node(:node_2).last_sibling_in_list).to eq(node(:node_3))
|
248
|
+
expect(node(:node_3).last_sibling_in_list).to eq(node(:node_3))
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
describe '#first_sibling_in_list' do
|
253
|
+
it "should return the first sibling in the list containing the current sibling" do
|
254
|
+
expect(node(:node_1).first_sibling_in_list).to eq(node(:node_1))
|
255
|
+
expect(node(:node_2).first_sibling_in_list).to eq(node(:node_1))
|
256
|
+
expect(node(:node_3).first_sibling_in_list).to eq(node(:node_1))
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
describe '#ancestors' do
|
261
|
+
it "should be returned in the correct order" do
|
262
|
+
setup_tree <<-ENDTREE
|
263
|
+
- root:
|
264
|
+
- level_1_a
|
265
|
+
- level_1_b:
|
266
|
+
- level_2_a:
|
267
|
+
- leaf
|
268
|
+
ENDTREE
|
269
|
+
|
270
|
+
expect(node(:leaf).ancestors.to_a).to eq([node(:root), node(:level_1_b), node(:level_2_a)])
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should return the ancestors in correct order after rearranging" do
|
274
|
+
setup_tree <<-ENDTREE
|
275
|
+
- node_1:
|
276
|
+
- node_1_1:
|
277
|
+
- node_1_1_1
|
278
|
+
ENDTREE
|
279
|
+
|
280
|
+
node_1_1 = node(:node_1_1)
|
281
|
+
node_1_1.parent = nil
|
282
|
+
node_1_1.save!
|
283
|
+
|
284
|
+
node_1 = node(:node_1)
|
285
|
+
node_1.parent = node(:node_1_1)
|
286
|
+
node_1.save!
|
287
|
+
|
288
|
+
node_1_1_1 = node(:node_1_1_1)
|
289
|
+
node_1_1_1.parent = node_1
|
290
|
+
node_1_1_1.save!
|
291
|
+
|
292
|
+
expect(node_1_1_1.ancestors.to_a).to eq([node_1_1, node_1])
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
describe 'moving nodes with large tree' do
|
298
|
+
before(:each) do
|
299
|
+
|
300
|
+
# setup_tree <<-ENDTREE
|
301
|
+
# - node_1:
|
302
|
+
# - node_1_1:
|
303
|
+
# - node_1_1_1:
|
304
|
+
# - node_1_1_1_1
|
305
|
+
# - node_1_2
|
306
|
+
# - node_1_3
|
307
|
+
# - node_2:
|
308
|
+
# - node_2_1
|
309
|
+
# - node_2_2
|
310
|
+
# - node_3
|
311
|
+
# ENDTREE
|
312
|
+
|
313
|
+
setup_tree <<-ENDTREE
|
314
|
+
- node_1:
|
315
|
+
- node_1_1
|
316
|
+
- node_1_2:
|
317
|
+
- node_1_2_1:
|
318
|
+
- node_1_2_1_1
|
319
|
+
- node_1_2_1_2
|
320
|
+
- node_1_2_2:
|
321
|
+
- node_1_2_2_1
|
322
|
+
- node_1_2_2_2
|
323
|
+
- node_1_2_2_3
|
324
|
+
- node_2:
|
325
|
+
- node_2_1
|
326
|
+
- node_2_2
|
327
|
+
- node_2_3
|
328
|
+
- node_2_4:
|
329
|
+
- node_2_4_1
|
330
|
+
- node_2_4_2
|
331
|
+
- node_2_4_3
|
332
|
+
- node_3:
|
333
|
+
- node_3_1
|
334
|
+
- node_3_2
|
335
|
+
- node_3_3
|
336
|
+
ENDTREE
|
337
|
+
end
|
338
|
+
|
339
|
+
describe '#move_below' do
|
340
|
+
|
341
|
+
it 'should verify rational numbers after moving' do
|
342
|
+
expect(node(:node_1).position).to eq(1)
|
343
|
+
expect(node(:node_2).position).to eq(2)
|
344
|
+
expect(node(:node_3).position).to eq(3)
|
345
|
+
node_to_move = node(:node_1)
|
346
|
+
node_to_move.move_below(node(:node_2))
|
347
|
+
expect(node(:node_1).position).to eq(2)
|
348
|
+
expect(node(:node_2).position).to eq(1)
|
349
|
+
expect(node(:node_3).position).to eq(3)
|
350
|
+
expect(node(:node_1).rational_number).to eq(RationalNumber.new(2,1))
|
351
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(1,1))
|
352
|
+
expect(node(:node_3).rational_number).to eq(RationalNumber.new(3,1))
|
353
|
+
end
|
354
|
+
|
355
|
+
it 'should fix positions within the current list when moving an sibling away from its current parent' do
|
356
|
+
node_to_move = node(:node_1_1)
|
357
|
+
node_to_move.move_below(node(:node_2_1))
|
358
|
+
expect(node(:node_1_2).position).to eq(1)
|
359
|
+
expect(node(:node_1_2).rational_number).to eq(RationalNumber.new(3,2))
|
360
|
+
end
|
361
|
+
|
362
|
+
it 'should work when moving to a different parent' do
|
363
|
+
node_to_move = node(:node_1_1)
|
364
|
+
new_parent = node(:node_2)
|
365
|
+
node_to_move.move_below(node(:node_2_1))
|
366
|
+
node_to_move.reload
|
367
|
+
expect(node_to_move.position).to eq(2)
|
368
|
+
# expect(node_to_move.rational_number).to eq(RationalNumber.new(14,5))
|
369
|
+
# expect(node(:node_2_1).rational_number).to eq(RationalNumber.new(17,6))
|
370
|
+
expect(node(:node_1_2)).to be_at_top
|
371
|
+
expect(node(:node_2_1)).to be_at_top
|
372
|
+
end
|
373
|
+
|
374
|
+
it 'should be able to move the first node below the second node' do
|
375
|
+
first_node = node(:node_1)
|
376
|
+
second_node = node(:node_2)
|
377
|
+
first_node.move_below(second_node)
|
378
|
+
first_node.reload
|
379
|
+
second_node.reload
|
380
|
+
expect(second_node).to be_at_top
|
381
|
+
expect(first_node.higher_siblings.to_a).to eq([second_node])
|
382
|
+
end
|
383
|
+
|
384
|
+
it 'should be able to move the last node below the first node' do
|
385
|
+
first_node = node(:node_1)
|
386
|
+
last_node = node(:node_3)
|
387
|
+
last_node.move_below(first_node)
|
388
|
+
first_node.reload
|
389
|
+
last_node.reload
|
390
|
+
expect(last_node).not_to be_at_bottom
|
391
|
+
expect(node(:node_2)).to be_at_bottom
|
392
|
+
expect(last_node.higher_siblings.to_a).to eq([first_node])
|
393
|
+
end
|
394
|
+
|
395
|
+
it 'should rekey the children of a node when moving to a new parent' do
|
396
|
+
node_1_2_1_prev_keys = node(:node_1_2_1).rational_number
|
397
|
+
node_1_2_1_2_prev_keys = node(:node_1_2_1_2).rational_number
|
398
|
+
node_2_4_1_prev_keys = node(:node_2_4_1).rational_number
|
399
|
+
node_2_4_2_prev_keys = node(:node_2_4_2).rational_number
|
400
|
+
node_1_2 = node(:node_1_2)
|
401
|
+
node_1_2.move_below(node(:node_2_3))
|
402
|
+
|
403
|
+
expect(node(:node_1_2_1).rational_number).not_to eq(node_1_2_1_prev_keys)
|
404
|
+
expect(node(:node_1_2_1_2).rational_number).not_to eq(node_1_2_1_2_prev_keys)
|
405
|
+
|
406
|
+
# As these takes "over" the positions for former nodes, check equality of previous positions
|
407
|
+
expect(node(:node_1_2_1).rational_number).to eq(node_2_4_1_prev_keys)
|
408
|
+
expect(node(:node_1_2_2).rational_number).to eq(node_2_4_2_prev_keys)
|
409
|
+
expect(node(:node_1_2_1_2).rational_number).to eq(RationalNumber.new(127,45))
|
410
|
+
end
|
411
|
+
end
|
412
|
+
|
413
|
+
describe '#move_above' do
|
414
|
+
it 'should verify rational numbers after moving' do
|
415
|
+
expect(node(:node_1).position).to eq(1)
|
416
|
+
expect(node(:node_2).position).to eq(2)
|
417
|
+
expect(node(:node_3).position).to eq(3)
|
418
|
+
node_to_move = node(:node_1)
|
419
|
+
node_to_move.move_above(node(:node_3))
|
420
|
+
expect(node(:node_1).position).to eq(2)
|
421
|
+
expect(node(:node_2).position).to eq(1)
|
422
|
+
expect(node(:node_3).position).to eq(3)
|
423
|
+
expect(node(:node_1).rational_number).to eq(RationalNumber.new(2,1))
|
424
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(1,1))
|
425
|
+
expect(node(:node_3).rational_number).to eq(RationalNumber.new(3,1))
|
426
|
+
end
|
427
|
+
|
428
|
+
it 'should fix positions within the current list when moving an sibling away from its current parent' do
|
429
|
+
node_to_move = node(:node_1_1)
|
430
|
+
node_to_move.move_above(node(:node_2_1))
|
431
|
+
expect(node(:node_1_2).position).to eq(1)
|
432
|
+
expect(node(:node_1_1).position).to eq(1)
|
433
|
+
expect(node(:node_2_1).position).to eq(2)
|
434
|
+
end
|
435
|
+
|
436
|
+
it 'should work when moving to a different parent' do
|
437
|
+
# store children rational numbers before move
|
438
|
+
node_to_move = node(:node_1_1)
|
439
|
+
node_to_move.move_above(node(:node_2_4))
|
440
|
+
node_to_move.reload
|
441
|
+
expect(node_to_move.position).to eq(4)
|
442
|
+
expect(node_to_move.rational_number).to eq(RationalNumber.new(14,5))
|
443
|
+
expect(node(:node_2_4).rational_number).to eq(RationalNumber.new(17,6))
|
444
|
+
expect(node(:node_2_4)).to be_at_bottom
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'should move children when a node is moved due to insert of another node above' do
|
448
|
+
# store children rational numbers before move
|
449
|
+
expect(node(:node_2_4_1).rational_number).to eq(RationalNumber.new(31,11))
|
450
|
+
expect(node(:node_2_4_2).rational_number).to eq(RationalNumber.new(48,17))
|
451
|
+
expect(node(:node_2_4_3).rational_number).to eq(RationalNumber.new(65,23))
|
452
|
+
prev_2_4_1 = node(:node_2_4_1).rational_number
|
453
|
+
prev_2_4_2 = node(:node_2_4_2).rational_number
|
454
|
+
prev_2_4_3 = node(:node_2_4_3).rational_number
|
455
|
+
node_to_move = node(:node_1_1)
|
456
|
+
node_to_move.move_above(node(:node_2_4))
|
457
|
+
node_to_move.reload
|
458
|
+
|
459
|
+
# verify that children of 2.4 is moved to new position
|
460
|
+
expect(node(:node_2_4_1).rational_number).not_to eq(prev_2_4_1)
|
461
|
+
expect(node(:node_2_4_2).rational_number).not_to eq(prev_2_4_2)
|
462
|
+
expect(node(:node_2_4_3).rational_number).not_to eq(prev_2_4_3)
|
463
|
+
|
464
|
+
expect(node(:node_2_4_1).rational_number).to eq(RationalNumber.new(37,13))
|
465
|
+
expect(node(:node_2_4_2).rational_number).to eq(RationalNumber.new(57,20))
|
466
|
+
expect(node(:node_2_4_3).rational_number).to eq(RationalNumber.new(77,27))
|
467
|
+
end
|
468
|
+
|
469
|
+
it 'should be able to move the last node above the second node' do
|
470
|
+
last_node = node(:node_3)
|
471
|
+
second_node = node(:node_2)
|
472
|
+
last_node.move_above(second_node)
|
473
|
+
last_node.reload
|
474
|
+
second_node.reload
|
475
|
+
expect(second_node).to be_at_bottom
|
476
|
+
expect(last_node.higher_siblings.to_a).to eq([node(:node_1)])
|
477
|
+
end
|
478
|
+
|
479
|
+
it 'should be able to move the first node above the last node' do
|
480
|
+
first_node = node(:node_1)
|
481
|
+
last_node = node(:node_3)
|
482
|
+
first_node.move_above(last_node)
|
483
|
+
first_node.reload
|
484
|
+
last_node.reload
|
485
|
+
expect(node(:node_2)).to be_at_top
|
486
|
+
expect(first_node.higher_siblings.to_a).to eq([node(:node_2)])
|
487
|
+
end
|
488
|
+
|
489
|
+
it 'should rekey the children of a node when moving to a new parent' do
|
490
|
+
node_1_2_1_prev_keys = node(:node_1_2_1).rational_number
|
491
|
+
node_1_2_1_2_prev_keys = node(:node_1_2_1_2).rational_number
|
492
|
+
node_2_4_1_prev_keys = node(:node_2_4_1).rational_number
|
493
|
+
node_2_4_2_prev_keys = node(:node_2_4_2).rational_number
|
494
|
+
node_1_2 = node(:node_1_2)
|
495
|
+
node_1_2.move_above(node(:node_2_4))
|
496
|
+
|
497
|
+
expect(node(:node_1_2_1).rational_number).not_to eq(node_1_2_1_prev_keys)
|
498
|
+
expect(node(:node_1_2_1_2).rational_number).not_to eq(node_1_2_1_2_prev_keys)
|
499
|
+
|
500
|
+
# As these takes "over" the positions for former nodes, check equality of previous positions
|
501
|
+
expect(node(:node_1_2_1).rational_number).to eq(node_2_4_1_prev_keys)
|
502
|
+
expect(node(:node_1_2_2).rational_number).to eq(node_2_4_2_prev_keys)
|
503
|
+
expect(node(:node_1_2_1_2).rational_number).to eq(RationalNumber.new(127,45))
|
504
|
+
end
|
505
|
+
end
|
506
|
+
end # moving nodes with large tree
|
507
|
+
|
508
|
+
describe 'moving nodes with small tree' do
|
509
|
+
before(:each) do
|
510
|
+
|
511
|
+
setup_tree <<-ENDTREE
|
512
|
+
- node_1:
|
513
|
+
- node_1_1
|
514
|
+
- node_1_2
|
515
|
+
- node_2:
|
516
|
+
- node_2_1
|
517
|
+
- node_2_2
|
518
|
+
- node_2_3
|
519
|
+
- node_2_4:
|
520
|
+
- node_2_4_1
|
521
|
+
- node_2_4_2
|
522
|
+
- node_2_4_3
|
523
|
+
- node_3
|
524
|
+
ENDTREE
|
525
|
+
end
|
526
|
+
|
527
|
+
# THIS IS NOT IMPLEMENTED, as it should NOT be used this way
|
528
|
+
describe "setting position or nv/dv values directly" do
|
529
|
+
it "should move conflicting nodes and their children when using attribs to set nv/dv (first test)" do
|
530
|
+
node_2_1 = node(:node_2_1)
|
531
|
+
node_2_1.rational_number_nv = 2
|
532
|
+
node_2_1.rational_number_dv = 1
|
533
|
+
node_2_1.save!
|
534
|
+
expect(node(:node_1).rational_number).to eq(RationalNumber.new(1,1))
|
535
|
+
expect(node(:node_2_1).rational_number).to eq(RationalNumber.new(2,1))
|
536
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(3,1))
|
537
|
+
expect(node(:node_2_2).rational_number).to eq(RationalNumber.new(7,2))
|
538
|
+
expect(node(:node_3).rational_number).to eq(RationalNumber.new(4,1))
|
539
|
+
end
|
540
|
+
|
541
|
+
it "should move conflicting nodes and their children when using attribs to set nv/dv (second test)" do
|
542
|
+
node_2_1 = node(:node_2_1)
|
543
|
+
node_2_1.rational_number_nv = 1
|
544
|
+
node_2_1.rational_number_dv = 1
|
545
|
+
node_2_1.save!
|
546
|
+
expect(node(:node_2_1).rational_number).to eq(RationalNumber.new(1,1))
|
547
|
+
expect(node(:node_1).rational_number).to eq(RationalNumber.new(2,1))
|
548
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(3,1))
|
549
|
+
expect(node(:node_3).rational_number).to eq(RationalNumber.new(4,1))
|
550
|
+
end
|
551
|
+
|
552
|
+
it "should move conflicting nodes and their children when setting position" do
|
553
|
+
node_2 = node(:node_2)
|
554
|
+
node_2.move_to_position(1)
|
555
|
+
node_2.save!
|
556
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(1,1))
|
557
|
+
expect(node(:node_1).rational_number).to eq(RationalNumber.new(2,1))
|
558
|
+
expect(node(:node_3).rational_number).to eq(RationalNumber.new(3,1))
|
559
|
+
end
|
560
|
+
|
561
|
+
it "should move conflicting nodes and their children when setting nv/dv trough function" do
|
562
|
+
node_2 = node(:node_2)
|
563
|
+
node_2.move_to_rational_number(1,1)
|
564
|
+
node_2.save!
|
565
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(1,1))
|
566
|
+
expect(node(:node_1).rational_number).to eq(RationalNumber.new(2,1))
|
567
|
+
expect(node(:node_3).rational_number).to eq(RationalNumber.new(3,1))
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
describe "#move_to_top" do
|
572
|
+
it "should return true when attempting to move the first sibling" do
|
573
|
+
expect(node(:node_1).move_to_top).to eq(true)
|
574
|
+
expect(node(:node_1_1).move_to_top).to eq(true)
|
575
|
+
end
|
576
|
+
|
577
|
+
it "should be able to move the last sibling to the top" do
|
578
|
+
first_node = node(:node_1)
|
579
|
+
last_node = node(:node_3)
|
580
|
+
last_node.move_to_top
|
581
|
+
first_node.reload
|
582
|
+
expect(last_node).to be_at_top
|
583
|
+
expect(first_node).not_to be_at_top
|
584
|
+
expect(first_node.higher_siblings.to_a).to eq([last_node])
|
585
|
+
expect(last_node.lower_siblings.to_a).to eq([first_node, node(:node_2)])
|
586
|
+
|
587
|
+
expect(first_node.rational_number).to eq(RationalNumber.new(2,1))
|
588
|
+
expect(last_node.rational_number).to eq(RationalNumber.new(1,1))
|
589
|
+
end
|
590
|
+
|
591
|
+
it 'should rekey the children of a node when moving the node' do
|
592
|
+
node_2_4_1_prev_keys = node(:node_2_4_1).rational_number
|
593
|
+
node_2_4_2_prev_keys = node(:node_2_4_2).rational_number
|
594
|
+
node_2 = node(:node_2)
|
595
|
+
node_2.move_to_top
|
596
|
+
node_2.reload
|
597
|
+
expect(node_2).to be_at_top
|
598
|
+
|
599
|
+
expect(node(:node_2_4_1).rational_number).not_to eq(node_2_4_1_prev_keys)
|
600
|
+
expect(node(:node_2_4_2).rational_number).not_to eq(node_2_4_2_prev_keys)
|
601
|
+
expect(node(:node_2_4_1).rational_number).to eq(RationalNumber.new(20,11))
|
602
|
+
expect(node(:node_2_4_2).rational_number).to eq(RationalNumber.new(31,17))
|
603
|
+
end
|
604
|
+
|
605
|
+
end
|
606
|
+
|
607
|
+
describe "#move_to_bottom" do
|
608
|
+
it "should return true when attempting to move the last sibling" do
|
609
|
+
expect(node(:node_3).move_to_bottom).to eq(true)
|
610
|
+
expect(node(:node_1_2).move_to_bottom).to eq(true)
|
611
|
+
end
|
612
|
+
|
613
|
+
it "should be able to move the first sibling to the bottom" do
|
614
|
+
first_node = node(:node_1)
|
615
|
+
middle_node = node(:node_2)
|
616
|
+
last_node = node(:node_3)
|
617
|
+
first_node.move_to_bottom
|
618
|
+
middle_node.reload
|
619
|
+
last_node.reload
|
620
|
+
expect(first_node).not_to be_at_top
|
621
|
+
expect(first_node).to be_at_bottom
|
622
|
+
expect(last_node).not_to be_at_bottom
|
623
|
+
expect(last_node).not_to be_at_top
|
624
|
+
expect(middle_node).to be_at_top
|
625
|
+
expect(first_node.lower_siblings.to_a).to eq([])
|
626
|
+
expect(last_node.higher_siblings.to_a).to eq([middle_node])
|
627
|
+
|
628
|
+
expect(middle_node.rational_number).to eq(RationalNumber.new(1,1))
|
629
|
+
expect(last_node.rational_number).to eq(RationalNumber.new(2,1))
|
630
|
+
expect(first_node.rational_number).to eq(RationalNumber.new(3,1))
|
631
|
+
end
|
632
|
+
|
633
|
+
it 'should rekey the children of a node when moving the node' do
|
634
|
+
node_2_4_1_prev_keys = node(:node_2_4_1).rational_number
|
635
|
+
node_2_4_2_prev_keys = node(:node_2_4_2).rational_number
|
636
|
+
node_2 = node(:node_2)
|
637
|
+
node_2.move_to_bottom
|
638
|
+
node_2.reload
|
639
|
+
expect(node_2).to be_at_bottom
|
640
|
+
|
641
|
+
expect(node(:node_2_4_1).rational_number).not_to eq(node_2_4_1_prev_keys)
|
642
|
+
expect(node(:node_2_4_2).rational_number).not_to eq(node_2_4_2_prev_keys)
|
643
|
+
expect(node(:node_2_4_1).rational_number).to eq(RationalNumber.new(42,11))
|
644
|
+
expect(node(:node_2_4_2).rational_number).to eq(RationalNumber.new(65,17))
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
describe "#move_up" do
|
649
|
+
it "should correctly move nodes up" do
|
650
|
+
node(:node_2_3).move_up
|
651
|
+
expect(node(:node_2).children).to eq([node(:node_2_1), node(:node_2_3), node(:node_2_2), node(:node_2_4)])
|
652
|
+
end
|
653
|
+
end
|
654
|
+
|
655
|
+
describe "#move_down" do
|
656
|
+
it "should correctly move nodes down" do
|
657
|
+
node(:node_2_3).move_down
|
658
|
+
expect(node(:node_2).children).to eq([node(:node_2_1), node(:node_2_2), node(:node_2_4), node(:node_2_3)])
|
659
|
+
end
|
660
|
+
end
|
661
|
+
end # moving nodes with small tree
|
662
|
+
|
663
|
+
describe "querying the tree" do
|
664
|
+
before(:each) do
|
665
|
+
setup_tree <<-ENDTREE
|
666
|
+
- node_1:
|
667
|
+
- node_1_1
|
668
|
+
- node_1_2:
|
669
|
+
- node_1_2_1:
|
670
|
+
- node_1_2_1_1
|
671
|
+
- node_1_2_1_2
|
672
|
+
- node_1_2_2:
|
673
|
+
- node_1_2_2_1
|
674
|
+
- node_2:
|
675
|
+
- node_2_1:
|
676
|
+
- node_2_1_1
|
677
|
+
- node_3:
|
678
|
+
- node_3_1
|
679
|
+
- node_3_2
|
680
|
+
ENDTREE
|
681
|
+
end
|
682
|
+
it "should get the tree under the given node" do
|
683
|
+
expect(node(:node_1).tree.all).to eq([node(:node_1_1), node(:node_1_2), node(:node_1_2_1), node(:node_1_2_1_1), node(:node_1_2_1_2), node(:node_1_2_2), node(:node_1_2_2_1)])
|
684
|
+
expect(node(:node_2).tree.all).to eq([node(:node_2_1), node(:node_2_1_1)])
|
685
|
+
expect(node(:node_3).tree.all).to eq([node(:node_3_1), node(:node_3_2)])
|
686
|
+
|
687
|
+
expect(node(:node_1).tree_and_self.all).to eq([node(:node_1), node(:node_1_1), node(:node_1_2), node(:node_1_2_1), node(:node_1_2_1_1), node(:node_1_2_1_2), node(:node_1_2_2), node(:node_1_2_2_1)])
|
688
|
+
expect(node(:node_2).tree_and_self.all).to eq([node(:node_2), node(:node_2_1), node(:node_2_1_1)])
|
689
|
+
expect(node(:node_3).tree_and_self.all).to eq([node(:node_3), node(:node_3_1), node(:node_3_2)])
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
describe "when rekeying" do
|
694
|
+
before(:each) do
|
695
|
+
setup_tree <<-ENDTREE
|
696
|
+
- node_1
|
697
|
+
- node_2:
|
698
|
+
- node_2_1
|
699
|
+
- node_2_2
|
700
|
+
- node_2_3
|
701
|
+
- node_2_4:
|
702
|
+
- node_2_4_1
|
703
|
+
- node_2_4_2
|
704
|
+
- node_2_4_3
|
705
|
+
- node_3
|
706
|
+
ENDTREE
|
707
|
+
end
|
708
|
+
it "should rekey the entire tree" do
|
709
|
+
# Force two gaps in the order
|
710
|
+
node_3 = node(:node_3)
|
711
|
+
node_3.move_to_position(8, {:force => true})
|
712
|
+
node_3.save_with_force_rational_numbers!
|
713
|
+
expect(node(:node_3).rational_number).to eq(RationalNumber.new(8,1))
|
714
|
+
|
715
|
+
node_2 = node(:node_2)
|
716
|
+
node_2.move_to_position(4, {:force => true})
|
717
|
+
node_2.save_with_force_rational_numbers!
|
718
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(4,1))
|
719
|
+
|
720
|
+
RationalNumberedNode.rekey_all!
|
721
|
+
|
722
|
+
# all nodes should still have their respective positions
|
723
|
+
|
724
|
+
expect(node(:node_1).rational_number).to eq(RationalNumber.new(1,1))
|
725
|
+
expect(node(:node_2).rational_number).to eq(RationalNumber.new(2,1))
|
726
|
+
expect(node(:node_3).rational_number).to eq(RationalNumber.new(3,1))
|
727
|
+
expect(node(:node_2_1).rational_number).to eq(RationalNumber.new(5,2))
|
728
|
+
expect(node(:node_2_2).rational_number).to eq(RationalNumber.new(8,3))
|
729
|
+
expect(node(:node_2_3).rational_number).to eq(RationalNumber.new(11,4))
|
730
|
+
expect(node(:node_2_4).rational_number).to eq(RationalNumber.new(14,5))
|
731
|
+
expect(node(:node_2_4_1).rational_number).to eq(RationalNumber.new(31,11))
|
732
|
+
expect(node(:node_2_4_2).rational_number).to eq(RationalNumber.new(48,17))
|
733
|
+
expect(node(:node_2_4_3).rational_number).to eq(RationalNumber.new(65,23))
|
734
|
+
end
|
735
|
+
end
|
736
|
+
|
737
|
+
describe "testing validations" do
|
738
|
+
before(:each) do
|
739
|
+
setup_tree <<-ENDTREE
|
740
|
+
- node_1
|
741
|
+
- node_2:
|
742
|
+
- node_2_1
|
743
|
+
- node_3
|
744
|
+
ENDTREE
|
745
|
+
end
|
746
|
+
|
747
|
+
it "should fail validation when trying to set invalid nv/dv (parent not found)" do
|
748
|
+
node_to_move = node(:node_2_1)
|
749
|
+
node_to_move.rational_number_nv = 65
|
750
|
+
node_to_move.rational_number_dv = 23
|
751
|
+
node_to_move.save
|
752
|
+
expect(node_to_move).not_to be_valid
|
753
|
+
end
|
754
|
+
|
755
|
+
it "should fail validation when trying to nv/dv resulting in cyclic relation" do
|
756
|
+
node_to_move = node(:node_2)
|
757
|
+
node_to_move.rational_number_nv = 13
|
758
|
+
node_to_move.rational_number_dv = 15
|
759
|
+
node_to_move.save
|
760
|
+
expect(node_to_move).not_to be_valid
|
761
|
+
end
|
762
|
+
|
763
|
+
end # describe "testing validations"
|
764
|
+
|
765
|
+
end # Mongoid::Tree::RationalNumbering
|