parallel_ancestry 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,359 @@
1
+
2
+ require_relative '../lib/parallel_ancestry.rb'
3
+
4
+ describe ::ParallelAncestry do
5
+
6
+ before :all do
7
+ module ::ParallelAncestry::Mock
8
+ extend ::ParallelAncestry
9
+ end
10
+ class ::ParallelAncestry::ModuleSubclassMock < ::Module
11
+ include ::ParallelAncestry
12
+ end
13
+ ::ParallelAncestry::ModuleSubclassInstanceMock = ::ParallelAncestry::ModuleSubclassMock.new
14
+ end
15
+
16
+ ##############
17
+ # children #
18
+ ##############
19
+
20
+ it 'tracks an array of children' do
21
+ [ ::ParallelAncestry::Mock, ::ParallelAncestry::ModuleSubclassInstanceMock ].each do |this_test|
22
+ this_test.module_eval do
23
+ configuration_instance = ::Module.new
24
+ children_instance = children( configuration_instance )
25
+ children_instance.should == []
26
+ children_instance.should == children( configuration_instance )
27
+ end
28
+ end
29
+ end
30
+
31
+ #############
32
+ # parents #
33
+ #############
34
+
35
+ it 'tracks an array of children' do
36
+ [ ::ParallelAncestry::Mock, ::ParallelAncestry::ModuleSubclassInstanceMock ].each do |this_test|
37
+ this_test.module_eval do
38
+ configuration_instance = ::Module.new
39
+ parents_instance = parents( configuration_instance )
40
+ parents_instance.should == []
41
+ parents_instance.should == parents( configuration_instance )
42
+ end
43
+ end
44
+ end
45
+
46
+ ###############################
47
+ # register_child_for_parent #
48
+ ###############################
49
+
50
+ it 'can register children for a given instance so that migration is possible' do
51
+ [ ::ParallelAncestry::Mock, ::ParallelAncestry::ModuleSubclassInstanceMock ].each do |this_test|
52
+ this_test.module_eval do
53
+ parent = ::Module.new
54
+ child = ::Module.new
55
+ register_child_for_parent( child, parent )
56
+ children( parent ).should == [ child ]
57
+ end
58
+ end
59
+ end
60
+
61
+ ##############
62
+ # ancestor #
63
+ ##############
64
+
65
+ it 'can return the next ancestor for instance for configuration name' do
66
+ [ ::ParallelAncestry::Mock, ::ParallelAncestry::ModuleSubclassInstanceMock ].each do |this_test|
67
+ this_test.module_eval do
68
+ parent = ::Module.new do
69
+ # we have to mock the method bc that's how the module determines if it has a configuration defined
70
+ # since we don't know whether a configuration value has been set yet
71
+ attr_accessor :some_configuration
72
+ end
73
+ child = ::Module.new
74
+ register_child_for_parent( child, parent )
75
+ ancestor( child ) { |this_parent| this_parent == parent } .should == parent
76
+ end
77
+ end
78
+ end
79
+
80
+ ####################
81
+ # ancestor_chain #
82
+ ####################
83
+
84
+ it 'can return a chain of instances corresponding to the configuration inheritance chain' do
85
+ [ ::ParallelAncestry::Mock, ::ParallelAncestry::ModuleSubclassInstanceMock ].each do |this_test|
86
+ this_test.module_eval do
87
+ # set up hierarchy
88
+ instance_A = ::Module.new do
89
+ # we have to mock the method bc that's how the module determines if it has a configuration defined
90
+ # since we don't know whether a configuration value has been set yet
91
+ attr_accessor :some_configuration
92
+ end
93
+ instance_B = ::Module.new do
94
+ # we have to mock the method bc that's how the module determines if it has a configuration defined
95
+ # since we don't know whether a configuration value has been set yet
96
+ attr_accessor :some_other_configuration
97
+ include instance_A
98
+ end
99
+ register_child_for_parent( instance_B, instance_A )
100
+ instance_C1 = ::Module.new do
101
+ include instance_B
102
+ attr_accessor :yet_another_configuration
103
+ end
104
+ register_child_for_parent( instance_C1, instance_B )
105
+ instance_C2 = ::Module.new do
106
+ include instance_B
107
+ end
108
+ register_child_for_parent( instance_C2, instance_B )
109
+ instance_D = ::Module.new do
110
+ include instance_C1
111
+ include instance_C2
112
+ end
113
+ register_child_for_parent( instance_D, instance_C1 )
114
+ register_child_for_parent( instance_D, instance_C2 )
115
+ # test ancestor hierarchy for each
116
+ ancestor_proc = ::Proc.new do |this_parent|
117
+ this_parent.method_defined?( :some_configuration )
118
+ end
119
+ ancestor_chain( instance_A, & ancestor_proc ).should == [ instance_A ]
120
+ ancestor_chain( instance_B, & ancestor_proc ).should == [ instance_B, instance_A ]
121
+ ancestor_chain( instance_C1, & ancestor_proc ).should == [ instance_C1, instance_B, instance_A ]
122
+ ancestor_chain( instance_C2, & ancestor_proc ).should == [ instance_C2, instance_B, instance_A ]
123
+ ancestor_chain( instance_D, & ancestor_proc ).should == [ instance_D, instance_C2, instance_B, instance_A ]
124
+
125
+ ancestor_proc = ::Proc.new do |this_parent|
126
+ this_parent.method_defined?( :some_other_configuration )
127
+ end
128
+ ancestor_chain( instance_B, & ancestor_proc ).should == [ instance_B ]
129
+ ancestor_chain( instance_C1, & ancestor_proc ).should == [ instance_C1, instance_B ]
130
+ ancestor_chain( instance_C2, & ancestor_proc ).should == [ instance_C2, instance_B ]
131
+
132
+ ancestor_proc = ::Proc.new do |this_parent|
133
+ this_parent.method_defined?( :yet_another_configuration )
134
+ end
135
+ ancestor_chain( instance_C1, & ancestor_proc ).should == [ instance_C1 ]
136
+ ancestor_chain( instance_D, & ancestor_proc ).should == [ instance_D, instance_C1 ]
137
+ end
138
+ end
139
+ end
140
+
141
+ ####################
142
+ # lowest_parents #
143
+ ####################
144
+
145
+ it 'can return the first ancestor on each parent tree matching block condition' do
146
+ [ ::ParallelAncestry::Mock, ::ParallelAncestry::ModuleSubclassInstanceMock ].each do |this_test|
147
+ this_test.module_eval do
148
+ # set up hierarchy
149
+ instance_A = ::Module.new do
150
+ # we have to mock the method bc that's how the module determines if it has a configuration defined
151
+ # since we don't know whether a configuration value has been set yet
152
+ attr_accessor :some_configuration
153
+ end
154
+ instance_B1 = ::Module.new do
155
+ # we have to mock the method bc that's how the module determines if it has a configuration defined
156
+ # since we don't know whether a configuration value has been set yet
157
+ attr_accessor :some_other_configuration
158
+ include instance_A
159
+ end
160
+ register_child_for_parent( instance_B1, instance_A )
161
+ instance_B2 = ::Module.new do
162
+ include instance_A
163
+ end
164
+ register_child_for_parent( instance_B2, instance_A )
165
+ instance_C1 = ::Module.new do
166
+ include instance_B1
167
+ attr_accessor :yet_another_configuration
168
+ end
169
+ register_child_for_parent( instance_C1, instance_B1 )
170
+ instance_C2 = ::Module.new do
171
+ include instance_B1
172
+ end
173
+ register_child_for_parent( instance_C2, instance_B1 )
174
+ instance_D = ::Module.new do
175
+ include instance_B2
176
+ include instance_C1
177
+ include instance_C2
178
+ end
179
+ instance_E = ::Class.new do
180
+ include instance_B2
181
+ include instance_C1
182
+ include instance_C2
183
+ include instance_D
184
+ end
185
+ register_child_for_parent( instance_D, instance_B2 )
186
+ register_child_for_parent( instance_D, instance_C1 )
187
+ register_child_for_parent( instance_D, instance_C2 )
188
+ register_child_for_parent( instance_E, instance_D )
189
+ register_child_for_parent( instance_E, instance_B1 )
190
+ match_proc = ::Proc.new do |this_parent|
191
+ this_parent.method_defined?( :some_configuration )
192
+ end
193
+ lowest_parents( instance_D, & match_proc ).should == [ instance_C2, instance_C1, instance_B2 ]
194
+ lowest_parents( instance_C2, & match_proc ).should == [ instance_B1 ]
195
+ lowest_parents( instance_C1, & match_proc ).should == [ instance_B1 ]
196
+ lowest_parents( instance_B1, & match_proc ).should == [ instance_A ]
197
+ lowest_parents( instance_B2, & match_proc ).should == [ instance_A ]
198
+ lowest_parents( instance_E, & match_proc ).should == [ instance_B1, instance_D ]
199
+ end
200
+ end
201
+ end
202
+
203
+ ######################
204
+ # highest_children #
205
+ ######################
206
+
207
+ it 'can return the first ancestor on each child tree matching block condition' do
208
+ [ ::ParallelAncestry::Mock, ::ParallelAncestry::ModuleSubclassInstanceMock ].each do |this_test|
209
+ this_test.module_eval do
210
+ # set up hierarchy
211
+ instance_A = ::Module.new do
212
+ # we have to mock the method bc that's how the module determines if it has a configuration defined
213
+ # since we don't know whether a configuration value has been set yet
214
+ attr_accessor :some_configuration
215
+ end
216
+ instance_B1 = ::Module.new do
217
+ # we have to mock the method bc that's how the module determines if it has a configuration defined
218
+ # since we don't know whether a configuration value has been set yet
219
+ attr_accessor :some_other_configuration
220
+ extend instance_A
221
+ end
222
+ register_child_for_parent( instance_B1, instance_A )
223
+ instance_B2 = ::Module.new do
224
+ extend instance_A
225
+ end
226
+ register_child_for_parent( instance_B2, instance_A )
227
+ instance_C1 = ::Module.new do
228
+ extend instance_B1
229
+ extend instance_A
230
+ attr_accessor :yet_another_configuration
231
+ end
232
+ register_child_for_parent( instance_C1, instance_B1 )
233
+ instance_C2 = ::Module.new do
234
+ extend instance_B2
235
+ extend instance_A
236
+ end
237
+ register_child_for_parent( instance_C2, instance_B1 )
238
+ instance_D = ::Module.new do
239
+ extend instance_B2
240
+ extend instance_C1
241
+ extend instance_A
242
+ end
243
+ instance_E = ::Class.new do
244
+ extend instance_C2
245
+ end
246
+ register_child_for_parent( instance_D, instance_B2 )
247
+ register_child_for_parent( instance_D, instance_C1 )
248
+ register_child_for_parent( instance_D, instance_C2 )
249
+ register_child_for_parent( instance_E, instance_D )
250
+ register_child_for_parent( instance_E, instance_B1 )
251
+ match_proc = ::Proc.new do |this_parent|
252
+ this_parent.respond_to?( :some_configuration )
253
+ end
254
+ highest_children( instance_E, & match_proc ).empty?.should == true
255
+ highest_children( instance_D, & match_proc ).empty?.should == true
256
+ highest_children( instance_C2, & match_proc ).should == [ instance_D ]
257
+ highest_children( instance_C1, & match_proc ).should == [ instance_D ]
258
+ highest_children( instance_B1, & match_proc ).should == [ instance_C1, instance_C2 ]
259
+ highest_children( instance_B2, & match_proc ).should == [ instance_D ]
260
+ highest_children( instance_A, & match_proc ).should == [ instance_B1, instance_B2 ]
261
+ end
262
+ end
263
+ end
264
+
265
+ #####################################
266
+ # match_ancestor #
267
+ #####################################
268
+
269
+ it 'can get the first defined configuration searching up the module configuration inheritance chain' do
270
+ [ ::ParallelAncestry::Mock, ::ParallelAncestry::ModuleSubclassInstanceMock ].each do |this_test|
271
+ this_test.module_eval do
272
+ # set up hierarchy
273
+ instance_A = ::Module.new do
274
+ # we have to mock the method bc that's how the module determines if it has a configuration defined
275
+ # since we don't know whether a configuration value has been set yet
276
+ class << self
277
+ attr_accessor :some_configuration
278
+ end
279
+ end
280
+ instance_B = ::Module.new do
281
+ # we have to mock the method bc that's how the module determines if it has a configuration defined
282
+ # since we don't know whether a configuration value has been set yet
283
+ include instance_A
284
+ class << self
285
+ attr_accessor :some_configuration
286
+ attr_accessor :some_other_configuration
287
+ end
288
+ end
289
+ register_child_for_parent( instance_B, instance_A )
290
+ instance_C1 = ::Module.new do
291
+ include instance_B
292
+ class << self
293
+ attr_accessor :some_configuration
294
+ attr_accessor :some_other_configuration
295
+ attr_accessor :yet_another_configuration
296
+ end
297
+ end
298
+ register_child_for_parent( instance_C1, instance_B )
299
+ instance_C2 = ::Module.new do
300
+ include instance_B
301
+ class << self
302
+ attr_accessor :some_configuration
303
+ attr_accessor :some_other_configuration
304
+ attr_accessor :yet_another_configuration
305
+ end
306
+ end
307
+ register_child_for_parent( instance_C2, instance_B )
308
+ instance_D = ::Module.new do
309
+ include instance_C1
310
+ include instance_C2
311
+ class << self
312
+ attr_accessor :some_configuration
313
+ attr_accessor :some_other_configuration
314
+ attr_accessor :yet_another_configuration
315
+ end
316
+ end
317
+ register_child_for_parent( instance_D, instance_C1 )
318
+ register_child_for_parent( instance_D, instance_C2 )
319
+
320
+ configuration_method = :some_configuration
321
+
322
+ # test ancestor hierarchy for each
323
+ match_proc = ::Proc.new do |this_parent|
324
+ this_parent.__send__( configuration_method )
325
+ end
326
+
327
+ match_ancestor_proc = ::Proc.new do |this_parent|
328
+ this_parent.respond_to?( configuration_method )
329
+ end
330
+
331
+ instance_A.some_configuration = :some_value
332
+ instance_B.some_other_configuration = :some_other_value
333
+
334
+ match_ancestor( instance_B, match_ancestor_proc, & match_proc ).should == instance_A
335
+ match_ancestor( instance_C1, match_ancestor_proc, & match_proc ).should == instance_A
336
+
337
+ configuration_method = :some_other_configuration
338
+ match_ancestor( instance_B, match_ancestor_proc, & match_proc ).should == instance_B
339
+ match_ancestor( instance_C1, match_ancestor_proc, & match_proc ).should == instance_B
340
+
341
+ instance_C2.yet_another_configuration = :another_value
342
+
343
+ configuration_method = :yet_another_configuration
344
+ match_ancestor( instance_C1, match_ancestor_proc, & match_proc ).should == nil
345
+ match_ancestor( instance_D, match_ancestor_proc, & match_proc ).should == instance_C2
346
+
347
+ configuration_method = :some_configuration
348
+ match_ancestor( instance_C2, match_ancestor_proc, & match_proc ).should == instance_A
349
+ match_ancestor( instance_D, match_ancestor_proc, & match_proc ).should == instance_A
350
+
351
+ configuration_method = :some_other_configuration
352
+ match_ancestor( instance_C2, match_ancestor_proc, & match_proc ).should == instance_B
353
+ match_ancestor( instance_D, match_ancestor_proc, & match_proc ).should == instance_B
354
+
355
+ end
356
+ end
357
+ end
358
+
359
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: parallel_ancestry
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Asher
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: module-cluster
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: array-unique
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: Create and track parallel inheritance hierarchies. Hook parallel hierarchies
47
+ (by including a module) to automatically update/register ancestry at include and
48
+ extend, or update/register only manually. Manual registration permits definitions
49
+ of ancestry across, for example, instances of the same type or instances of entirely
50
+ different types. Implementation is provided by simple child/parent trees with an
51
+ block to choose which parent. This permits a simple multiple inheritance model very
52
+ similar to how Ruby handles modules. Conflicts for multiple inheritance are resolved
53
+ by the parent most recently named for the block match. Used heavily by CascadingConfiguration
54
+ gem (cascading-configuration) as well as by forthcoming Persistence and Magnets
55
+ gems (persistence and magnets).
56
+ email: asher@ridiculouspower.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/parallel_ancestry/parallel_ancestry/inheritance/module_subclass_inheritance.rb
62
+ - lib/parallel_ancestry/parallel_ancestry/inheritance.rb
63
+ - lib/parallel_ancestry/parallel_ancestry/module_subclass_inheritance.rb
64
+ - lib/parallel_ancestry/parallel_ancestry.rb
65
+ - lib/parallel_ancestry.rb
66
+ - spec/parallel_ancestry/inheritance_spec.rb
67
+ - spec/parallel_ancestry_spec.rb
68
+ - README.md
69
+ - README.rdoc
70
+ - CHANGELOG.rdoc
71
+ homepage: http://rubygems.org/gems/parallel_ancestry
72
+ licenses: []
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project: parallel_ancestry
91
+ rubygems_version: 1.8.23
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Provides parallel implementations of inheritance hierarchies. This is useful
95
+ both for tracking the existing inheritance tree and for creating trees that function
96
+ independently of inheritance models determined internal to Ruby.
97
+ test_files: []
98
+ has_rdoc: