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.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/lib/acts_as_ordered_tree.rb +22 -100
  3. data/lib/acts_as_ordered_tree/adapters.rb +17 -0
  4. data/lib/acts_as_ordered_tree/adapters/abstract.rb +23 -0
  5. data/lib/acts_as_ordered_tree/adapters/postgresql.rb +150 -0
  6. data/lib/acts_as_ordered_tree/adapters/recursive.rb +157 -0
  7. data/lib/acts_as_ordered_tree/compatibility.rb +22 -0
  8. data/lib/acts_as_ordered_tree/compatibility/active_record/association_scope.rb +9 -0
  9. data/lib/acts_as_ordered_tree/compatibility/active_record/default_scoped.rb +19 -0
  10. data/lib/acts_as_ordered_tree/compatibility/active_record/null_relation.rb +71 -0
  11. data/lib/acts_as_ordered_tree/compatibility/features.rb +153 -0
  12. data/lib/acts_as_ordered_tree/deprecate.rb +24 -0
  13. data/lib/acts_as_ordered_tree/hooks.rb +38 -0
  14. data/lib/acts_as_ordered_tree/hooks/update.rb +86 -0
  15. data/lib/acts_as_ordered_tree/instance_methods.rb +92 -453
  16. data/lib/acts_as_ordered_tree/iterators/arranger.rb +35 -0
  17. data/lib/acts_as_ordered_tree/iterators/level_calculator.rb +52 -0
  18. data/lib/acts_as_ordered_tree/iterators/orphans_pruner.rb +58 -0
  19. data/lib/acts_as_ordered_tree/node.rb +78 -0
  20. data/lib/acts_as_ordered_tree/node/attributes.rb +48 -0
  21. data/lib/acts_as_ordered_tree/node/movement.rb +62 -0
  22. data/lib/acts_as_ordered_tree/node/movements.rb +111 -0
  23. data/lib/acts_as_ordered_tree/node/predicates.rb +98 -0
  24. data/lib/acts_as_ordered_tree/node/reloading.rb +49 -0
  25. data/lib/acts_as_ordered_tree/node/siblings.rb +139 -0
  26. data/lib/acts_as_ordered_tree/node/traversals.rb +53 -0
  27. data/lib/acts_as_ordered_tree/persevering_transaction.rb +93 -0
  28. data/lib/acts_as_ordered_tree/position.rb +143 -0
  29. data/lib/acts_as_ordered_tree/relation/arrangeable.rb +33 -0
  30. data/lib/acts_as_ordered_tree/relation/iterable.rb +41 -0
  31. data/lib/acts_as_ordered_tree/relation/preloaded.rb +46 -11
  32. data/lib/acts_as_ordered_tree/transaction/base.rb +57 -0
  33. data/lib/acts_as_ordered_tree/transaction/callbacks.rb +67 -0
  34. data/lib/acts_as_ordered_tree/transaction/create.rb +68 -0
  35. data/lib/acts_as_ordered_tree/transaction/destroy.rb +34 -0
  36. data/lib/acts_as_ordered_tree/transaction/dsl.rb +214 -0
  37. data/lib/acts_as_ordered_tree/transaction/factory.rb +67 -0
  38. data/lib/acts_as_ordered_tree/transaction/move.rb +70 -0
  39. data/lib/acts_as_ordered_tree/transaction/passthrough.rb +12 -0
  40. data/lib/acts_as_ordered_tree/transaction/reorder.rb +42 -0
  41. data/lib/acts_as_ordered_tree/transaction/save.rb +64 -0
  42. data/lib/acts_as_ordered_tree/transaction/update.rb +78 -0
  43. data/lib/acts_as_ordered_tree/tree.rb +148 -0
  44. data/lib/acts_as_ordered_tree/tree/association.rb +20 -0
  45. data/lib/acts_as_ordered_tree/tree/callbacks.rb +57 -0
  46. data/lib/acts_as_ordered_tree/tree/children_association.rb +120 -0
  47. data/lib/acts_as_ordered_tree/tree/columns.rb +102 -0
  48. data/lib/acts_as_ordered_tree/tree/deprecated_columns_accessors.rb +24 -0
  49. data/lib/acts_as_ordered_tree/tree/parent_association.rb +31 -0
  50. data/lib/acts_as_ordered_tree/tree/perseverance.rb +19 -0
  51. data/lib/acts_as_ordered_tree/tree/scopes.rb +56 -0
  52. data/lib/acts_as_ordered_tree/validators.rb +1 -1
  53. data/lib/acts_as_ordered_tree/version.rb +1 -1
  54. data/spec/acts_as_ordered_tree_spec.rb +80 -909
  55. data/spec/adapters/postgresql_spec.rb +14 -0
  56. data/spec/adapters/recursive_spec.rb +12 -0
  57. data/spec/adapters/shared.rb +272 -0
  58. data/spec/callbacks_spec.rb +177 -0
  59. data/spec/counter_cache_spec.rb +31 -0
  60. data/spec/create_spec.rb +110 -0
  61. data/spec/destroy_spec.rb +57 -0
  62. data/spec/inheritance_spec.rb +176 -0
  63. data/spec/move_spec.rb +94 -0
  64. data/spec/node/movements/concurrent_movements_spec.rb +354 -0
  65. data/spec/node/movements/move_higher_spec.rb +46 -0
  66. data/spec/node/movements/move_lower_spec.rb +46 -0
  67. data/spec/node/movements/move_to_child_of_spec.rb +147 -0
  68. data/spec/node/movements/move_to_child_with_index_spec.rb +124 -0
  69. data/spec/node/movements/move_to_child_with_position_spec.rb +85 -0
  70. data/spec/node/movements/move_to_left_of_spec.rb +120 -0
  71. data/spec/node/movements/move_to_right_of_spec.rb +120 -0
  72. data/spec/node/movements/move_to_root_spec.rb +67 -0
  73. data/spec/node/predicates_spec.rb +211 -0
  74. data/spec/node/reloading_spec.rb +42 -0
  75. data/spec/node/siblings_spec.rb +193 -0
  76. data/spec/node/traversals_spec.rb +71 -0
  77. data/spec/persevering_transaction_spec.rb +98 -0
  78. data/spec/relation/arrangeable_spec.rb +88 -0
  79. data/spec/relation/iterable_spec.rb +104 -0
  80. data/spec/relation/preloaded_spec.rb +57 -0
  81. data/spec/reorder_spec.rb +83 -0
  82. data/spec/spec_helper.rb +30 -38
  83. data/spec/support/db/boot.rb +22 -0
  84. data/spec/{db → support/db}/config.travis.yml +2 -0
  85. data/spec/{db → support/db}/config.yml +1 -0
  86. data/spec/{db → support/db}/schema.rb +9 -0
  87. data/spec/support/factories.rb +2 -2
  88. data/spec/support/matchers.rb +67 -58
  89. data/spec/support/models.rb +6 -14
  90. data/spec/support/tree_factory.rb +315 -0
  91. data/spec/tree/children_association_spec.rb +72 -0
  92. data/spec/tree/columns_spec.rb +65 -0
  93. data/spec/tree/scopes_spec.rb +39 -0
  94. metadata +161 -43
  95. data/lib/acts_as_ordered_tree/adapters/postgresql_adapter.rb +0 -104
  96. data/lib/acts_as_ordered_tree/arrangeable.rb +0 -80
  97. data/lib/acts_as_ordered_tree/class_methods.rb +0 -72
  98. data/lib/acts_as_ordered_tree/relation/base.rb +0 -26
  99. data/lib/acts_as_ordered_tree/tenacious_transaction.rb +0 -30
  100. 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