compo 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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/CHANGELOG +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +7 -0
- data/compo.gemspec +33 -0
- data/lib/compo/array_composite.rb +103 -0
- data/lib/compo/composite.rb +130 -0
- data/lib/compo/hash_composite.rb +70 -0
- data/lib/compo/leaf.rb +22 -0
- data/lib/compo/movable.rb +53 -0
- data/lib/compo/null_composite.rb +63 -0
- data/lib/compo/parent_tracker.rb +64 -0
- data/lib/compo/version.rb +4 -0
- data/lib/compo.rb +12 -0
- data/spec/array_composite_spec.rb +225 -0
- data/spec/composite_spec.rb +249 -0
- data/spec/hash_composite_spec.rb +184 -0
- data/spec/leaf_spec.rb +14 -0
- data/spec/movable_spec.rb +201 -0
- data/spec/null_composite_spec.rb +67 -0
- data/spec/parent_tracker_spec.rb +63 -0
- data/spec/spec_helper.rb +11 -0
- metadata +192 -0
@@ -0,0 +1,225 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'compo'
|
3
|
+
|
4
|
+
describe Compo::ArrayComposite do
|
5
|
+
let(:child1) { double(:child1) }
|
6
|
+
let(:child2) { double(:child2) }
|
7
|
+
let(:child3) { double(:child3) }
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
allow(child1).to receive(:update_parent)
|
11
|
+
allow(child1).to receive(:remove_parent)
|
12
|
+
|
13
|
+
allow(child2).to receive(:update_parent)
|
14
|
+
allow(child2).to receive(:remove_parent)
|
15
|
+
|
16
|
+
allow(child3).to receive(:update_parent)
|
17
|
+
allow(child3).to receive(:remove_parent)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#add' do
|
21
|
+
context 'when the ID is not Numeric' do
|
22
|
+
specify { expect(subject.add(:mr_flibble, child1)).to be_nil }
|
23
|
+
|
24
|
+
it 'does not add to the list of children' do
|
25
|
+
subject.add(:rimmer, child1)
|
26
|
+
expect(subject.children).to eq({})
|
27
|
+
|
28
|
+
subject.add(0, child1)
|
29
|
+
subject.add(:lister, child2)
|
30
|
+
expect(subject.children).to eq(0 => child1)
|
31
|
+
|
32
|
+
subject.add(1, child2)
|
33
|
+
subject.add(:cat, child3)
|
34
|
+
expect(subject.children).to eq(0 => child1, 1 => child2)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
context 'when the ID is Numeric' do
|
38
|
+
context 'and is equal to the number of children' do
|
39
|
+
it 'returns the child' do
|
40
|
+
expect(subject.add(0, child1)).to eq(child1)
|
41
|
+
expect(subject.add(1, child2)).to eq(child2)
|
42
|
+
expect(subject.add(2, child3)).to eq(child3)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'adds to the end of the list of children' do
|
46
|
+
expect(subject.children).to eq({})
|
47
|
+
|
48
|
+
subject.add(0, child1)
|
49
|
+
expect(subject.children).to eq(0 => child1)
|
50
|
+
|
51
|
+
subject.add(1, child2)
|
52
|
+
expect(subject.children).to eq(0 => child1, 1 => child2)
|
53
|
+
|
54
|
+
subject.add(2, child3)
|
55
|
+
expect(subject.children).to eq(0 => child1, 1 => child2, 2 => child3)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'calls #update_parent on the child with itself and an ID proc' do
|
59
|
+
expect(child1).to receive(:update_parent) do |parent, proc|
|
60
|
+
expect(parent).to eq(subject)
|
61
|
+
expect(proc.call).to eq(0)
|
62
|
+
end
|
63
|
+
subject.add(0, child1)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'and is greater than the number of children' do
|
68
|
+
it 'returns nil' do
|
69
|
+
expect(subject.add(1, child1)).to be_nil
|
70
|
+
subject.add(0, child1)
|
71
|
+
expect(subject.add(2, child2)).to be_nil
|
72
|
+
subject.add(1, child2)
|
73
|
+
expect(subject.add(3, child3)).to be_nil
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'does not add to the list of children' do
|
77
|
+
subject.add(1, child1)
|
78
|
+
expect(subject.children).to eq({})
|
79
|
+
|
80
|
+
subject.add(0, child1)
|
81
|
+
subject.add(2, child2)
|
82
|
+
expect(subject.children).to eq(0 => child1)
|
83
|
+
|
84
|
+
subject.add(1, child2)
|
85
|
+
subject.add(3, child3)
|
86
|
+
expect(subject.children).to eq(0 => child1, 1 => child2)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'and is less than the number of children' do
|
91
|
+
it 'returns the child' do
|
92
|
+
subject.add(0, child1)
|
93
|
+
expect(subject.add(0, child2)).to eq(child2)
|
94
|
+
expect(subject.add(1, child3)).to eq(child3)
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'adds to the list of children at the correct position' do
|
98
|
+
expect(subject.children).to eq({})
|
99
|
+
subject.add(0, child1)
|
100
|
+
expect(subject.children).to eq(0 => child1)
|
101
|
+
subject.add(0, child2)
|
102
|
+
expect(subject.children).to eq(0 => child2, 1 => child1)
|
103
|
+
subject.add(1, child3)
|
104
|
+
expect(subject.children).to eq(0 => child2, 1 => child3, 2 => child1)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'calls #update_parent on the child with itself and an ID proc' do
|
108
|
+
expect(child1).to receive(:update_parent) do |parent, proc|
|
109
|
+
expect(parent).to eq(subject)
|
110
|
+
expect(proc.call).to eq(0)
|
111
|
+
end
|
112
|
+
subject.add(0, child2)
|
113
|
+
subject.add(0, child1)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '#remove' do
|
120
|
+
context 'when the child exists in the list' do
|
121
|
+
before(:each) { subject.add(0, child1) }
|
122
|
+
|
123
|
+
it 'returns the child' do
|
124
|
+
expect(subject.remove(child1)).to eq(child1)
|
125
|
+
end
|
126
|
+
|
127
|
+
it 'calls #remove_parent on the child' do
|
128
|
+
expect(child1).to receive(:remove_parent).once.with(no_args)
|
129
|
+
subject.remove(child1)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'moves succeeding IDs down by one' do
|
133
|
+
subject.add(1, child2)
|
134
|
+
subject.add(2, child3)
|
135
|
+
expect(subject.children).to eq(0 => child1, 1 => child2, 2 => child3)
|
136
|
+
subject.remove(child2)
|
137
|
+
expect(subject.children).to eq(0 => child1, 1 => child3)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
context 'when the child does not exist in the list' do
|
142
|
+
specify { expect(subject.remove(child1)).to be_nil }
|
143
|
+
|
144
|
+
it 'does not change the children' do
|
145
|
+
expect(subject.children).to eq({})
|
146
|
+
subject.remove(child1)
|
147
|
+
expect(subject.children).to eq({})
|
148
|
+
|
149
|
+
subject.add(0, child1)
|
150
|
+
subject.add(1, child2)
|
151
|
+
expect(subject.children).to eq(0 => child1, 1 => child2)
|
152
|
+
subject.remove(child3)
|
153
|
+
expect(subject.children).to eq(0 => child1, 1 => child2)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
describe '#remove_id' do
|
159
|
+
context 'when the ID exists' do
|
160
|
+
before(:each) { subject.add(0, child1) }
|
161
|
+
|
162
|
+
it 'returns the child' do
|
163
|
+
expect(subject.remove_id(0)).to eq(child1)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'calls #remove_parent on the child' do
|
167
|
+
expect(child1).to receive(:remove_parent).once.with(no_args)
|
168
|
+
subject.remove_id(0)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'moves succeeding IDs down by one' do
|
172
|
+
subject.add(1, child2)
|
173
|
+
subject.add(2, child3)
|
174
|
+
expect(subject.children).to eq(0 => child1, 1 => child2, 2 => child3)
|
175
|
+
subject.remove_id(1)
|
176
|
+
expect(subject.children).to eq(0 => child1, 1 => child3)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
context 'when the ID does not exist' do
|
181
|
+
specify { expect(subject.remove_id(0)).to be_nil }
|
182
|
+
|
183
|
+
it 'does not change the children' do
|
184
|
+
expect(subject.children).to eq({})
|
185
|
+
subject.remove_id(0)
|
186
|
+
expect(subject.children).to eq({})
|
187
|
+
|
188
|
+
subject.add(0, child1)
|
189
|
+
subject.add(1, child2)
|
190
|
+
expect(subject.children).to eq(0 => child1, 1 => child2)
|
191
|
+
subject.remove_id(2)
|
192
|
+
expect(subject.children).to eq(0 => child1, 1 => child2)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
describe '#children' do
|
198
|
+
context 'when the list has no children' do
|
199
|
+
it 'returns the empty hash' do
|
200
|
+
expect(subject.children).to eq({})
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context 'when the list has children' do
|
205
|
+
it 'returns a hash mapping their current indices to themselves' do
|
206
|
+
expect(subject.children).to eq({})
|
207
|
+
|
208
|
+
subject.add(0, child1)
|
209
|
+
expect(subject.children).to eq(0 => child1)
|
210
|
+
|
211
|
+
subject.add(1, child2)
|
212
|
+
expect(subject.children).to eq(0 => child1, 1 => child2)
|
213
|
+
|
214
|
+
subject.add(2, child3)
|
215
|
+
expect(subject.children).to eq(0 => child1, 1 => child2, 2 => child3)
|
216
|
+
|
217
|
+
subject.remove(child2)
|
218
|
+
expect(subject.children).to eq(0 => child1, 1 => child3)
|
219
|
+
|
220
|
+
subject.add(0, child2)
|
221
|
+
expect(subject.children).to eq(0 => child2, 1 => child1, 2 => child3)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,249 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'compo'
|
3
|
+
|
4
|
+
# Mock implementation of a Composite
|
5
|
+
class MockComposite
|
6
|
+
include Compo::Composite
|
7
|
+
end
|
8
|
+
|
9
|
+
describe MockComposite do
|
10
|
+
let(:id) { double(:id) }
|
11
|
+
let(:child) { double(:child) }
|
12
|
+
|
13
|
+
describe '#add' do
|
14
|
+
before(:each) { allow(subject).to receive(:add!) }
|
15
|
+
|
16
|
+
context 'when #add! returns nil' do
|
17
|
+
before(:each) { allow(subject).to receive(:add!).and_return(nil) }
|
18
|
+
|
19
|
+
specify { expect(subject.add(id, child)).to be_nil }
|
20
|
+
|
21
|
+
it 'calls #add! with the ID and child given' do
|
22
|
+
expect(subject).to receive(:add!).once.with(id, child)
|
23
|
+
subject.add(id, child)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when #add! returns the child' do
|
28
|
+
before(:each) do
|
29
|
+
allow(subject).to receive(:add!).and_return(child)
|
30
|
+
allow(subject).to receive(:id_function)
|
31
|
+
allow(child).to receive(:update_parent)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'calls #add! with the ID and child given' do
|
35
|
+
expect(subject).to receive(:add!).once.with(id, child)
|
36
|
+
subject.add(id, child)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'calls #id_function with the child given' do
|
40
|
+
expect(subject).to receive(:id_function).once.with(child)
|
41
|
+
subject.add(id, child)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'calls #update_parent on the child with the parent and ID function' do
|
45
|
+
idf = double(:id_function)
|
46
|
+
allow(subject).to receive(:id_function).and_return(idf)
|
47
|
+
expect(child).to receive(:update_parent).once.with(subject, idf)
|
48
|
+
subject.add(id, child)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'returns the given child' do
|
52
|
+
expect(subject.add(id, child)).to eq(child)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe '#remove' do
|
58
|
+
context 'when #remove! is defined' do
|
59
|
+
before(:each) { allow(subject).to receive(:remove!) }
|
60
|
+
|
61
|
+
context 'when #remove! returns nil' do
|
62
|
+
before(:each) { allow(subject).to receive(:remove!).and_return(nil) }
|
63
|
+
|
64
|
+
specify { expect(subject.remove(child)).to be_nil }
|
65
|
+
|
66
|
+
it 'calls #remove! with the child given' do
|
67
|
+
expect(subject).to receive(:remove!).once.with(child)
|
68
|
+
subject.remove(child)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
context 'when #remove! returns the child' do
|
73
|
+
before(:each) do
|
74
|
+
allow(subject).to receive(:remove!).and_return(child)
|
75
|
+
allow(child).to receive(:remove_parent)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'calls #remove! with the child given' do
|
79
|
+
expect(subject).to receive(:remove!).once.with(child)
|
80
|
+
subject.remove(child)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'calls #remove_parent on the child with no arguments' do
|
84
|
+
expect(child).to receive(:remove_parent).once.with(no_args)
|
85
|
+
subject.remove(child)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns the given child' do
|
89
|
+
expect(subject.remove(child)).to eq(child)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'when #remove_id! is defined but #remove! is not' do
|
95
|
+
before(:each) do
|
96
|
+
allow(subject).to receive(:remove_id!)
|
97
|
+
allow(subject).to receive(:children).and_return(id => child)
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when #remove_id! returns nil' do
|
101
|
+
before(:each) do
|
102
|
+
allow(subject).to receive(:remove_id!).and_return(nil)
|
103
|
+
end
|
104
|
+
|
105
|
+
specify { expect(subject.remove(child)).to be_nil }
|
106
|
+
|
107
|
+
it 'calls #remove! with the child given' do
|
108
|
+
expect(subject).to receive(:remove!).once.with(child)
|
109
|
+
subject.remove(child)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'calls #remove_id! with the ID of the child' do
|
113
|
+
expect(subject).to receive(:remove_id!).once.with(id)
|
114
|
+
subject.remove(child)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'calls #children' do
|
118
|
+
expect(subject).to receive(:children).once
|
119
|
+
subject.remove(child)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'when #remove_id! returns the child' do
|
124
|
+
before(:each) do
|
125
|
+
allow(subject).to receive(:remove_id!).and_return(child)
|
126
|
+
allow(child).to receive(:remove_parent)
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'calls #remove_id! with the child given' do
|
130
|
+
expect(subject).to receive(:remove!).once.with(child)
|
131
|
+
subject.remove(child)
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'calls #remove_parent on the child with no arguments' do
|
135
|
+
expect(child).to receive(:remove_parent).once.with(no_args)
|
136
|
+
subject.remove(child)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'returns the given child' do
|
140
|
+
expect(subject.remove(child)).to eq(child)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '#remove_id' do
|
147
|
+
let(:id) { double(:id) }
|
148
|
+
|
149
|
+
context 'when #remove_id! is defined' do
|
150
|
+
before(:each) { allow(subject).to receive(:remove_id!) }
|
151
|
+
|
152
|
+
context 'and #remove_id! returns nil' do
|
153
|
+
before(:each) do
|
154
|
+
allow(subject).to receive(:remove_id!).and_return(nil)
|
155
|
+
end
|
156
|
+
|
157
|
+
specify { expect(subject.remove_id(id)).to be_nil }
|
158
|
+
|
159
|
+
it 'calls #remove_id! with the ID given' do
|
160
|
+
expect(subject).to receive(:remove_id!).once.with(id)
|
161
|
+
subject.remove_id(id)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'and #remove_id! returns the child' do
|
166
|
+
before(:each) do
|
167
|
+
allow(subject).to receive(:remove_id!).and_return(child)
|
168
|
+
allow(child).to receive(:remove_parent)
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'calls #remove_id! with the ID given' do
|
172
|
+
expect(subject).to receive(:remove_id!).once.with(id)
|
173
|
+
subject.remove_id(id)
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'calls #remove_parent on the child with no arguments' do
|
177
|
+
expect(child).to receive(:remove_parent).once.with(no_args)
|
178
|
+
subject.remove_id(id)
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'returns the child' do
|
182
|
+
expect(subject.remove_id(id)).to eq(child)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
context 'when #remove! is defined but #remove_id! is not' do
|
188
|
+
before(:each) { allow(subject).to receive(:remove!) }
|
189
|
+
|
190
|
+
context 'and #remove! returns nil' do
|
191
|
+
before(:each) do
|
192
|
+
allow(subject).to receive(:remove!).and_return(nil)
|
193
|
+
allow(subject).to receive(:get_child).and_return(child)
|
194
|
+
end
|
195
|
+
|
196
|
+
specify { expect(subject.remove_id(id)).to be_nil }
|
197
|
+
|
198
|
+
it 'calls #remove_id! with the ID given' do
|
199
|
+
expect(subject).to receive(:remove_id!).once.with(id)
|
200
|
+
subject.remove_id(id)
|
201
|
+
end
|
202
|
+
|
203
|
+
it 'calls #get_child with the ID given' do
|
204
|
+
expect(subject).to receive(:get_child).once.with(id)
|
205
|
+
subject.remove_id(id)
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'calls #remove! with the child given' do
|
209
|
+
expect(subject).to receive(:remove!).once.with(child)
|
210
|
+
subject.remove_id(id)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
context 'and #remove! returns the child' do
|
215
|
+
before(:each) do
|
216
|
+
allow(subject).to receive(:remove!).and_return(child)
|
217
|
+
allow(subject).to receive(:get_child).and_return(child)
|
218
|
+
allow(child).to receive(:remove_parent)
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'calls #remove! with the child given' do
|
222
|
+
expect(subject).to receive(:remove!).once.with(child)
|
223
|
+
subject.remove_id(id)
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'calls #remove_parent on the child with no arguments' do
|
227
|
+
expect(child).to receive(:remove_parent).once.with(no_args)
|
228
|
+
subject.remove_id(id)
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'returns the given child' do
|
232
|
+
expect(subject.remove_id(id)).to eq(child)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe '#each' do
|
239
|
+
it 'delegates to the #each implementation of the hash from #children' do
|
240
|
+
children = double(:children)
|
241
|
+
|
242
|
+
allow(subject).to receive(:children).and_return(children)
|
243
|
+
expect(subject).to receive(:children).once.with(no_args)
|
244
|
+
expect(children).to receive(:each).once
|
245
|
+
|
246
|
+
subject.each
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'compo'
|
3
|
+
|
4
|
+
describe Compo::HashComposite do
|
5
|
+
let(:child1) { double(:child1) }
|
6
|
+
let(:child2) { double(:child2) }
|
7
|
+
let(:child3) { double(:child3) }
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
allow(child1).to receive(:update_parent)
|
11
|
+
allow(child1).to receive(:remove_parent)
|
12
|
+
|
13
|
+
allow(child2).to receive(:update_parent)
|
14
|
+
allow(child2).to receive(:remove_parent)
|
15
|
+
|
16
|
+
allow(child3).to receive(:update_parent)
|
17
|
+
allow(child3).to receive(:remove_parent)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#add' do
|
21
|
+
context 'when the ID is occupied' do
|
22
|
+
before(:each) { subject.add(:a, child1) }
|
23
|
+
it 'returns the new child' do
|
24
|
+
expect(subject.add(:a, child2)).to eq(child2)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'replaces the old child in the child hash' do
|
28
|
+
expect(subject.children).to eq(a: child1)
|
29
|
+
|
30
|
+
subject.add(:a, child2)
|
31
|
+
expect(subject.children).to eq(a: child2)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'calls #update_parent on the new child with itself and an ID proc' do
|
35
|
+
expect(child2).to receive(:update_parent).once do |parent, proc|
|
36
|
+
expect(parent).to eq(subject)
|
37
|
+
expect(proc.call).to eq(:a)
|
38
|
+
end
|
39
|
+
subject.add(:a, child2)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'calls #remove_parent on the old child' do
|
43
|
+
expect(child1).to receive(:remove_parent).once.with(no_args)
|
44
|
+
subject.add(:a, child2)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when the ID is not occupied' do
|
49
|
+
it 'returns the child' do
|
50
|
+
expect(subject.add(:a, child1)).to eq(child1)
|
51
|
+
expect(subject.add(:b, child2)).to eq(child2)
|
52
|
+
expect(subject.add(:c, child3)).to eq(child3)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'adds to the child hash' do
|
56
|
+
expect(subject.children).to eq({})
|
57
|
+
|
58
|
+
subject.add(:a, child1)
|
59
|
+
expect(subject.children).to eq(a: child1)
|
60
|
+
|
61
|
+
subject.add(:b, child2)
|
62
|
+
expect(subject.children).to eq(a: child1, b: child2)
|
63
|
+
|
64
|
+
subject.add(:c, child3)
|
65
|
+
expect(subject.children).to eq(a: child1, b: child2, c: child3)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'calls #update_parent on the child with itself and an ID proc' do
|
69
|
+
expect(child1).to receive(:update_parent) do |parent, proc|
|
70
|
+
expect(parent).to eq(subject)
|
71
|
+
expect(proc.call).to eq(:a)
|
72
|
+
end
|
73
|
+
subject.add(:a, child1)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#remove' do
|
79
|
+
context 'when the child exists in the hash' do
|
80
|
+
before(:each) { subject.add(:a, child1) }
|
81
|
+
|
82
|
+
it 'returns the child' do
|
83
|
+
expect(subject.remove(child1)).to eq(child1)
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'calls #remove_parent on the child' do
|
87
|
+
expect(child1).to receive(:remove_parent).once.with(no_args)
|
88
|
+
subject.remove(child1)
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'removes the child, and only the child, from the children hash' do
|
92
|
+
subject.add(:b, child2)
|
93
|
+
subject.add(:c, child3)
|
94
|
+
expect(subject.children).to eq(a: child1, b: child2, c: child3)
|
95
|
+
subject.remove(child2)
|
96
|
+
expect(subject.children).to eq(a: child1, c: child3)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when the child does not exist in the hash' do
|
101
|
+
specify { expect(subject.remove(child1)).to be_nil }
|
102
|
+
|
103
|
+
it 'does not change the children' do
|
104
|
+
expect(subject.children).to eq({})
|
105
|
+
subject.remove(child1)
|
106
|
+
expect(subject.children).to eq({})
|
107
|
+
|
108
|
+
subject.add(:a, child1)
|
109
|
+
subject.add(:b, child2)
|
110
|
+
expect(subject.children).to eq(a: child1, b: child2)
|
111
|
+
subject.remove(child3)
|
112
|
+
expect(subject.children).to eq(a: child1, b: child2)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
describe '#remove_id' do
|
118
|
+
context 'when the ID exists' do
|
119
|
+
before(:each) { subject.add(:a, child1) }
|
120
|
+
|
121
|
+
it 'returns the child' do
|
122
|
+
expect(subject.remove_id(:a)).to eq(child1)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'calls #remove_parent on the child' do
|
126
|
+
expect(child1).to receive(:remove_parent).once.with(no_args)
|
127
|
+
subject.remove_id(:a)
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'does not change the IDs of other children' do
|
131
|
+
subject.add(:b, child2)
|
132
|
+
subject.add(:c, child3)
|
133
|
+
expect(subject.children).to eq(a: child1, b: child2, c: child3)
|
134
|
+
subject.remove_id(:b)
|
135
|
+
expect(subject.children).to eq(a: child1, c: child3)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
context 'when the ID does not exist' do
|
140
|
+
specify { expect(subject.remove_id(:a)).to be_nil }
|
141
|
+
|
142
|
+
it 'does not change the children' do
|
143
|
+
expect(subject.children).to eq({})
|
144
|
+
subject.remove_id(:a)
|
145
|
+
expect(subject.children).to eq({})
|
146
|
+
|
147
|
+
subject.add(:a, child1)
|
148
|
+
subject.add(:b, child2)
|
149
|
+
expect(subject.children).to eq(a: child1, b: child2)
|
150
|
+
subject.remove_id(:c)
|
151
|
+
expect(subject.children).to eq(a: child1, b: child2)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#children' do
|
157
|
+
context 'when the hash has no children' do
|
158
|
+
it 'returns the empty hash' do
|
159
|
+
expect(subject.children).to eq({})
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
context 'when the hash has children' do
|
164
|
+
it 'returns the current hash' do
|
165
|
+
expect(subject.children).to eq({})
|
166
|
+
|
167
|
+
subject.add(:a, child1)
|
168
|
+
expect(subject.children).to eq(a: child1)
|
169
|
+
|
170
|
+
subject.add(:b, child2)
|
171
|
+
expect(subject.children).to eq(a: child1, b: child2)
|
172
|
+
|
173
|
+
subject.add(:c, child3)
|
174
|
+
expect(subject.children).to eq(a: child1, b: child2, c: child3)
|
175
|
+
|
176
|
+
subject.remove(child2)
|
177
|
+
expect(subject.children).to eq(a: child1, c: child3)
|
178
|
+
|
179
|
+
subject.add(:a, child2)
|
180
|
+
expect(subject.children).to eq(a: child2, c: child3)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
data/spec/leaf_spec.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'compo'
|
3
|
+
|
4
|
+
describe Compo::Leaf do
|
5
|
+
describe '#initialize' do
|
6
|
+
it 'initialises with no parent' do
|
7
|
+
expect(subject.parent).to be_nil
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'initialises with an ID function returning nil' do
|
11
|
+
expect(subject.id).to be_nil
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|