compo 0.1.5 → 0.2.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.
@@ -0,0 +1,33 @@
1
+ require 'url_referenceable_shared_examples'
2
+ require 'movable_shared_examples'
3
+
4
+ shared_examples 'a branch' do
5
+ it_behaves_like 'a URL referenceable object'
6
+ it_behaves_like 'a movable object'
7
+
8
+ describe '#initialize' do
9
+ it 'initialises with a Parentless as parent' do
10
+ expect(subject.parent).to be_a(Compo::Parentless)
11
+ end
12
+
13
+ it 'initialises with an ID function returning nil' do
14
+ expect(subject.id).to be_nil
15
+ end
16
+ end
17
+
18
+ describe '#url' do
19
+ context 'when the Leaf has no parent' do
20
+ it 'returns the empty string' do
21
+ expect(subject.url).to eq('')
22
+ end
23
+ end
24
+ context 'when the Leaf is the child of a root' do
25
+ let(:parent) { Compo::HashBranch.new }
26
+ before(:each) { subject.move_to(parent, :id) }
27
+
28
+ it 'returns /ID, where ID is the ID of the Leaf' do
29
+ expect(subject.url).to eq('/id')
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,283 @@
1
+ require 'compo'
2
+
3
+ shared_examples 'a removal of a child from its parent' do
4
+ it 'calls #update_parent on the child with a Parentless' do
5
+ expect(child).to receive(:update_parent).once do |parent, _|
6
+ expect(parent).to be_a(Compo::Parentless)
7
+ end
8
+ op.call
9
+ end
10
+
11
+ it 'calls #update_parent on the child with a nil-returning ID proc' do
12
+ expect(child).to receive(:update_parent).once do |_, idp|
13
+ expect(idp.call).to be_nil
14
+ end
15
+ op.call
16
+ end
17
+ end
18
+
19
+ shared_examples 'a composite' do
20
+ let(:id) { double(:id) }
21
+ let(:child) { double(:child) }
22
+
23
+ describe '#each' do
24
+ it 'delegates to the #each implementation of the hash from #children' do
25
+ children = double(:children)
26
+
27
+ allow(subject).to receive(:children).and_return(children)
28
+ expect(subject).to receive(:children).once.with(no_args)
29
+ expect(children).to receive(:each).once
30
+
31
+ subject.each
32
+ end
33
+ end
34
+
35
+ describe '#add' do
36
+ before(:each) { allow(subject).to receive(:add!) }
37
+
38
+ context 'when #add! returns nil' do
39
+ before(:each) { allow(subject).to receive(:add!).and_return(nil) }
40
+
41
+ specify { expect(subject.add(id, child)).to be_nil }
42
+
43
+ it 'calls #add! with the ID and child given' do
44
+ expect(subject).to receive(:add!).once.with(id, child)
45
+ subject.add(id, child)
46
+ end
47
+ end
48
+
49
+ context 'when #add! returns the child' do
50
+ before(:each) do
51
+ allow(subject).to receive(:add!).and_return(child)
52
+ allow(subject).to receive(:id_function)
53
+ allow(child).to receive(:update_parent)
54
+ end
55
+
56
+ it 'calls #add! with the ID and child given' do
57
+ expect(subject).to receive(:add!).once.with(id, child)
58
+ subject.add(id, child)
59
+ end
60
+
61
+ it 'calls #id_function with the child given' do
62
+ expect(subject).to receive(:id_function).once.with(child)
63
+ subject.add(id, child)
64
+ end
65
+
66
+ it 'calls #update_parent on the child with the parent and ID function' do
67
+ idf = double(:id_function)
68
+ allow(subject).to receive(:id_function).and_return(idf)
69
+ expect(child).to receive(:update_parent).once.with(subject, idf)
70
+ subject.add(id, child)
71
+ end
72
+
73
+ it 'returns the given child' do
74
+ expect(subject.add(id, child)).to eq(child)
75
+ end
76
+ end
77
+ end
78
+
79
+ describe '#get_child' do
80
+ let(:child) { double(:child) }
81
+
82
+ before(:each) do
83
+ allow(subject).to receive(:children).and_return(in_children: child)
84
+ end
85
+
86
+ context 'when the argument is in #children' do
87
+ it 'returns the child' do
88
+ expect(subject.get_child(:in_children)).to eq(child)
89
+ end
90
+ end
91
+
92
+ context 'when the argument is not in #children' do
93
+ specify { expect(subject.get_child(:not_in_children)).to be_nil }
94
+ end
95
+ end
96
+ end
97
+
98
+ shared_examples 'a composite with default #remove!' do
99
+ let(:child) { double(:child) }
100
+ let(:id) { double(:id) }
101
+
102
+ describe '#remove' do
103
+ context 'when #remove! is defined' do
104
+ before(:each) { allow(subject).to receive(:remove!) }
105
+
106
+ context 'when #remove! returns nil' do
107
+ before(:each) { allow(subject).to receive(:remove!).and_return(nil) }
108
+
109
+ specify { expect(subject.remove(child)).to be_nil }
110
+
111
+ it 'calls #remove! with the child given' do
112
+ expect(subject).to receive(:remove!).once.with(child)
113
+ subject.remove(child)
114
+ end
115
+ end
116
+
117
+ context 'when #remove! returns the child' do
118
+ before(:each) do
119
+ allow(subject).to receive(:remove!).and_return(child)
120
+ allow(child).to receive(:update_parent)
121
+ end
122
+
123
+ it 'calls #remove! with the child given' do
124
+ expect(subject).to receive(:remove!).once.with(child)
125
+ subject.remove(child)
126
+ end
127
+
128
+ it_behaves_like 'a removal of a child from its parent' do
129
+ let(:op) { -> { subject.remove(child) } }
130
+ end
131
+
132
+ it 'returns the given child' do
133
+ expect(subject.remove(child)).to eq(child)
134
+ end
135
+ end
136
+ end
137
+
138
+ context 'when #remove_id! is defined but #remove! is not' do
139
+ before(:each) do
140
+ allow(subject).to receive(:remove_id!)
141
+ allow(subject).to receive(:children).and_return(id => child)
142
+ end
143
+
144
+ context 'when #remove_id! returns nil' do
145
+ before(:each) do
146
+ allow(subject).to receive(:remove_id!).and_return(nil)
147
+ end
148
+
149
+ specify { expect(subject.remove(child)).to be_nil }
150
+
151
+ it 'calls #remove! with the child given' do
152
+ expect(subject).to receive(:remove!).once.with(child)
153
+ subject.remove(child)
154
+ end
155
+
156
+ it 'calls #remove_id! with the ID of the child' do
157
+ expect(subject).to receive(:remove_id!).once.with(id)
158
+ subject.remove(child)
159
+ end
160
+
161
+ it 'calls #children' do
162
+ expect(subject).to receive(:children).once
163
+ subject.remove(child)
164
+ end
165
+ end
166
+
167
+ context 'when #remove_id! returns the child' do
168
+ before(:each) do
169
+ allow(subject).to receive(:remove_id!).and_return(child)
170
+ allow(child).to receive(:update_parent)
171
+ end
172
+
173
+ it 'calls #remove_id! with the child given' do
174
+ expect(subject).to receive(:remove!).once.with(child)
175
+ subject.remove(child)
176
+ end
177
+
178
+ it_behaves_like 'a removal of a child from its parent' do
179
+ let(:op) { -> { subject.remove(child) } }
180
+ end
181
+
182
+ it 'returns the given child' do
183
+ expect(subject.remove(child)).to eq(child)
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
189
+
190
+ shared_examples 'a composite with default #remove_id!' do
191
+ let(:child) { double(:child) }
192
+ let(:id) { double(:id) }
193
+
194
+ describe '#remove_id' do
195
+ let(:id) { double(:id) }
196
+
197
+ context 'when #remove_id! is defined' do
198
+ before(:each) { allow(subject).to receive(:remove_id!) }
199
+
200
+ context 'and #remove_id! returns nil' do
201
+ before(:each) do
202
+ allow(subject).to receive(:remove_id!).and_return(nil)
203
+ end
204
+
205
+ specify { expect(subject.remove_id(id)).to be_nil }
206
+
207
+ it 'calls #remove_id! with the ID given' do
208
+ expect(subject).to receive(:remove_id!).once.with(id)
209
+ subject.remove_id(id)
210
+ end
211
+ end
212
+
213
+ context 'and #remove_id! returns the child' do
214
+ before(:each) do
215
+ allow(subject).to receive(:remove_id!).and_return(child)
216
+ allow(child).to receive(:update_parent)
217
+ end
218
+
219
+ it 'calls #remove_id! with the ID given' do
220
+ expect(subject).to receive(:remove_id!).once.with(id)
221
+ subject.remove_id(id)
222
+ end
223
+
224
+ it_behaves_like 'a removal of a child from its parent' do
225
+ let(:op) { -> { subject.remove_id(id) } }
226
+ end
227
+
228
+ it 'returns the child' do
229
+ expect(subject.remove_id(id)).to eq(child)
230
+ end
231
+ end
232
+ end
233
+
234
+ context 'when #remove! is defined but #remove_id! is not' do
235
+ before(:each) { allow(subject).to receive(:remove!) }
236
+
237
+ context 'and #remove! returns nil' do
238
+ before(:each) do
239
+ allow(subject).to receive(:remove!).and_return(nil)
240
+ allow(subject).to receive(:get_child).and_return(child)
241
+ end
242
+
243
+ specify { expect(subject.remove_id(id)).to be_nil }
244
+
245
+ it 'calls #remove_id! with the ID given' do
246
+ expect(subject).to receive(:remove_id!).once.with(id)
247
+ subject.remove_id(id)
248
+ end
249
+
250
+ it 'calls #get_child with the ID given' do
251
+ expect(subject).to receive(:get_child).once.with(id)
252
+ subject.remove_id(id)
253
+ end
254
+
255
+ it 'calls #remove! with the child given' do
256
+ expect(subject).to receive(:remove!).once.with(child)
257
+ subject.remove_id(id)
258
+ end
259
+ end
260
+
261
+ context 'and #remove! returns the child' do
262
+ before(:each) do
263
+ allow(subject).to receive(:remove!).and_return(child)
264
+ allow(subject).to receive(:get_child).and_return(child)
265
+ allow(child).to receive(:update_parent)
266
+ end
267
+
268
+ it 'calls #remove! with the child given' do
269
+ expect(subject).to receive(:remove!).once.with(child)
270
+ subject.remove_id(id)
271
+ end
272
+
273
+ it_behaves_like 'a removal of a child from its parent' do
274
+ let(:op) { -> { subject.remove_id(id) } }
275
+ end
276
+
277
+ it 'returns the given child' do
278
+ expect(subject.remove_id(id)).to eq(child)
279
+ end
280
+ end
281
+ end
282
+ end
283
+ end
@@ -1,5 +1,6 @@
1
1
  require 'spec_helper'
2
2
  require 'compo'
3
+ require 'composite_shared_examples'
3
4
 
4
5
  # Mock implementation of a Composite
5
6
  class MockComposite
@@ -7,263 +8,21 @@ class MockComposite
7
8
  end
8
9
 
9
10
  describe MockComposite do
10
- let(:id) { double(:id) }
11
+ before(:each) { allow(subject).to receive(:children).and_return(children) }
12
+ let(:children) { { in_children: child } }
11
13
  let(:child) { double(:child) }
12
14
 
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
15
+ it_behaves_like 'a composite'
16
+ it_behaves_like 'a composite with default #remove!'
17
+ it_behaves_like 'a composite with default #remove_id!'
249
18
 
19
+ #
20
+ # Specifications for Composite's default behaviour.
21
+ #
250
22
  describe '#get_child' do
251
- before(:each) { allow(subject).to receive(:children).and_return(children) }
252
- let(:children) { { in_children: child } }
253
-
254
23
  it 'calls #children' do
255
24
  expect(subject).to receive(:children).once
256
25
  subject.get_child(:in_children)
257
26
  end
258
-
259
- context 'when the argument is in #children' do
260
- it 'returns the child' do
261
- expect(subject.get_child(:in_children)).to eq(child)
262
- end
263
- end
264
-
265
- context 'when the argument is in #children' do
266
- specify { expect(subject.get_child(:not_in_children)).to be_nil }
267
- end
268
27
  end
269
28
  end
@@ -1,14 +1,9 @@
1
1
  require 'spec_helper'
2
2
  require 'compo'
3
+ require 'branch_shared_examples'
4
+ require 'hash_composite_shared_examples'
3
5
 
4
6
  describe Compo::HashBranch 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
7
+ it_behaves_like 'a branch'
8
+ it_behaves_like 'a hash composite'
14
9
  end