arrayfu 0.2.4 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +423 -0
- data/arrayfu.gemspec +1 -0
- data/lib/arrayfu/array_definition.rb +160 -8
- data/lib/arrayfu/arrayfu.rb +66 -0
- data/lib/arrayfu/generate_writers.rb +1 -1
- data/lib/arrayfu/version.rb +1 -1
- data/spec/examples/usage_spec.rb +138 -74
- data/spec/specs/generate_writers_step_spec.rb +1 -1
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25afe24f24b068f40630cbfaeac49fb1de9c21d7
|
4
|
+
data.tar.gz: 87b6a78fb88a4fe163e4e3d18d98d879ddfa67a2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c3dfab3890ef09fa8db15fc4a93b27231d3c022e50fd02f1db3931852380441a4beb28a8996b3b322e42c11defcf35484a9f6b011d8ced698ab7f74fd1e2309f
|
7
|
+
data.tar.gz: 4519bc52d05189b69813c72c50e5823998e44f9b2868a5a02131d9d20da77acfcf9834bf791d6cb46c71e9ba95e1468716f9b75bff0ae66cdd29a7553b02ac21
|
data/.gitignore
CHANGED
data/README.md
ADDED
@@ -0,0 +1,423 @@
|
|
1
|
+
#ArrayFu
|
2
|
+
|
3
|
+
One of the first ruby projects I. It is a simple dsl for declaritive arrays. Hopefully the examples below show how it can be used!
|
4
|
+
|
5
|
+
##Examples
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
example "Basic" do
|
9
|
+
class Example1
|
10
|
+
include ArrayFu
|
11
|
+
|
12
|
+
array :names
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
example 'Allow the array to have a read accessor' do
|
17
|
+
class Example2
|
18
|
+
include ArrayFu
|
19
|
+
|
20
|
+
array(:names) { readable }
|
21
|
+
end
|
22
|
+
Example2.new.names.should_not be_nil
|
23
|
+
end
|
24
|
+
|
25
|
+
example 'Allow the array to have a write accessor' do
|
26
|
+
class Example3
|
27
|
+
include ArrayFu
|
28
|
+
|
29
|
+
array(:names) { writeable }
|
30
|
+
end
|
31
|
+
instance = Example3.new
|
32
|
+
new_names = []
|
33
|
+
instance.names = new_names
|
34
|
+
instance.instance_eval do
|
35
|
+
@names.should == new_names
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
example 'Allow the array to have a read and write accessor' do
|
40
|
+
class Example4
|
41
|
+
include ArrayFu
|
42
|
+
|
43
|
+
array(:names) { read_and_write }
|
44
|
+
end
|
45
|
+
Example4.new.names.should_not be_nil
|
46
|
+
end
|
47
|
+
|
48
|
+
example 'Add a mutator method to the class that stores the array' do
|
49
|
+
class Example5
|
50
|
+
include ArrayFu
|
51
|
+
|
52
|
+
array(:names) { mutator :add_item }
|
53
|
+
end
|
54
|
+
|
55
|
+
instance = Example5.new
|
56
|
+
instance.add_item("JP")
|
57
|
+
instance.instance_eval do
|
58
|
+
@names.count.should == 1
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
example 'Add multiple mutators to the class that stores the array' do
|
63
|
+
class Example6
|
64
|
+
include ArrayFu
|
65
|
+
|
66
|
+
array :names do
|
67
|
+
mutator :add_item, :add_it, :push_it
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
instance = Example6.new
|
72
|
+
instance.add_item("JP")
|
73
|
+
instance.add_it("JP")
|
74
|
+
instance.push_it("JP")
|
75
|
+
instance.instance_eval do
|
76
|
+
@names.count.should == 3
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
example 'Add a mutator that ignores addition' do
|
81
|
+
class Example7
|
82
|
+
include ArrayFu
|
83
|
+
|
84
|
+
array :names do
|
85
|
+
mutator :add_item do|item|
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
instance = Example7.new
|
91
|
+
instance.add_item("JP")
|
92
|
+
instance.instance_eval do
|
93
|
+
@names.count.should == 0
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
example 'Add a mutator that does other custom logic as well as addition' do
|
98
|
+
class Example8
|
99
|
+
include ArrayFu
|
100
|
+
|
101
|
+
array(:secondary) { readable }
|
102
|
+
|
103
|
+
array :names do
|
104
|
+
readable
|
105
|
+
mutator :add_item do|item|
|
106
|
+
@secondary.push item
|
107
|
+
@names.push item
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
instance = Example8.new
|
113
|
+
instance.add_item("JP")
|
114
|
+
instance.names.count.should == 1
|
115
|
+
instance.secondary.count.should == 1
|
116
|
+
end
|
117
|
+
|
118
|
+
example 'Add a singular constraint and failure condition to each of the mutators' do
|
119
|
+
module NotBeJP
|
120
|
+
extend self
|
121
|
+
|
122
|
+
def matches?(item)
|
123
|
+
return item != "JP"
|
124
|
+
end
|
125
|
+
|
126
|
+
def name
|
127
|
+
return "The value should not be JP"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
module CriteriaViolation
|
132
|
+
extend self
|
133
|
+
|
134
|
+
def run(description,value)
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
class Example9
|
140
|
+
include ArrayFu
|
141
|
+
|
142
|
+
array :names do
|
143
|
+
readable
|
144
|
+
mutator :add_item,:add_it
|
145
|
+
new_item_must NotBeJP, CriteriaViolation
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
instance = Example9.new
|
150
|
+
instance.add_item("JP")
|
151
|
+
instance.add_it("JP")
|
152
|
+
instance.names.count.should == 0
|
153
|
+
end
|
154
|
+
|
155
|
+
example 'Add multiple constraints and a failure condition to each of the mutators' do
|
156
|
+
module NotBeJP
|
157
|
+
extend self
|
158
|
+
|
159
|
+
def matches?(item)
|
160
|
+
return item != "JP"
|
161
|
+
end
|
162
|
+
|
163
|
+
def name
|
164
|
+
return "The value should not be JP"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
module NotBeNil
|
169
|
+
extend self
|
170
|
+
|
171
|
+
def matches?(item)
|
172
|
+
return item != nil
|
173
|
+
end
|
174
|
+
|
175
|
+
def name
|
176
|
+
return "The value should not be nil"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
module CriteriaViolation
|
181
|
+
extend self
|
182
|
+
|
183
|
+
def run(description,value)
|
184
|
+
# puts "Criteria violated - #{description} - #{value}"
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class Example10
|
189
|
+
include ArrayFu
|
190
|
+
|
191
|
+
array :names do
|
192
|
+
readable
|
193
|
+
mutator :add_item,:add_it
|
194
|
+
addition_constraint NotBeJP
|
195
|
+
addition_constraint NotBeNil, CriteriaViolation
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
instance = Example10.new
|
200
|
+
instance.add_item("JP")
|
201
|
+
instance.add_it("JP")
|
202
|
+
instance.add_item(nil)
|
203
|
+
instance.names.count.should == 0
|
204
|
+
end
|
205
|
+
|
206
|
+
example 'Add an explicit processing visitor to the array' do
|
207
|
+
class DisplayItem
|
208
|
+
@@number_of_items_displayed = 0
|
209
|
+
class << self
|
210
|
+
def run_using(item)
|
211
|
+
@@number_of_items_displayed += 1
|
212
|
+
end
|
213
|
+
def item_count
|
214
|
+
return @@number_of_items_displayed
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class Example11
|
220
|
+
include ArrayFu
|
221
|
+
|
222
|
+
array :names do
|
223
|
+
mutator :add_item
|
224
|
+
process_using :display_all,DisplayItem
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
instance = Example11.new
|
229
|
+
(1..10).each{|item| instance.add_item(item)}
|
230
|
+
instance.display_all
|
231
|
+
DisplayItem.item_count.should == 10
|
232
|
+
end
|
233
|
+
|
234
|
+
example 'Add an method based processing visitor to the array based on a method that exists on the items in the array' do
|
235
|
+
class Item
|
236
|
+
def process
|
237
|
+
Example12.increment
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
class Example12
|
242
|
+
@@items_visited = 0
|
243
|
+
include ArrayFu
|
244
|
+
|
245
|
+
array :names do
|
246
|
+
mutator :add_item
|
247
|
+
process_using :display_all, :process #the second symbol is the name of a method on an element in the array
|
248
|
+
end
|
249
|
+
|
250
|
+
|
251
|
+
#the process method of the Item class invokes this method (a little bit roundabout, but it hopefully demonstrates the capability
|
252
|
+
def self.increment
|
253
|
+
@@items_visited += 1
|
254
|
+
end
|
255
|
+
def self.number_of_items_visited
|
256
|
+
@@items_visited
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
instance = Example12.new
|
261
|
+
(1..10).each{|item| instance.add_item(Item.new)}
|
262
|
+
instance.display_all
|
263
|
+
Example12.number_of_items_visited.should == 10
|
264
|
+
end
|
265
|
+
|
266
|
+
example 'Augment configuration using configuration block' do
|
267
|
+
class ArrayConfigs
|
268
|
+
def self.add_another_mutator
|
269
|
+
return lambda{|item| item.mutator :another_push}
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
class Example13
|
274
|
+
include ArrayFu
|
275
|
+
|
276
|
+
array :names do
|
277
|
+
readable
|
278
|
+
mutator :add_item
|
279
|
+
configure_using ArrayConfigs.add_another_mutator
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
instance = Example13.new
|
284
|
+
instance.add_item("Yo")
|
285
|
+
instance.another_push("Yo")
|
286
|
+
instance.names.count.should == 2
|
287
|
+
end
|
288
|
+
|
289
|
+
example 'Augment configuration using inline configuration block' do
|
290
|
+
class Example14
|
291
|
+
include ArrayFu
|
292
|
+
|
293
|
+
array :names do
|
294
|
+
readable
|
295
|
+
mutator :add_item
|
296
|
+
configure_using -> (item) do
|
297
|
+
item.mutator :another_pushes
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
instance = Example14.new
|
303
|
+
instance.add_item("Yo")
|
304
|
+
instance.another_pushes("Yo")
|
305
|
+
instance.names.count.should == 2
|
306
|
+
end
|
307
|
+
|
308
|
+
example 'Augment configuration using configuration instance (anything that responds to configure with the array definition as the argument)' do
|
309
|
+
|
310
|
+
module ArrayConfiguration
|
311
|
+
extend self
|
312
|
+
|
313
|
+
def configure(item)
|
314
|
+
item.mutator :once_more
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
class Example15
|
319
|
+
include ArrayFu
|
320
|
+
|
321
|
+
array :names do
|
322
|
+
readable
|
323
|
+
mutator :add_item
|
324
|
+
configure_using ArrayConfiguration
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
instance = Example15.new
|
329
|
+
instance.add_item("Yo")
|
330
|
+
instance.once_more("Yo")
|
331
|
+
instance.names.count.should == 2
|
332
|
+
end
|
333
|
+
|
334
|
+
example 'Augment configuration using configuration block' do
|
335
|
+
|
336
|
+
module ArrayConfiguration
|
337
|
+
extend self
|
338
|
+
|
339
|
+
def configuration_block
|
340
|
+
Proc.new do|array|
|
341
|
+
array.mutator :once_more
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
class Example16
|
347
|
+
include ArrayFu
|
348
|
+
|
349
|
+
array :names do
|
350
|
+
readable
|
351
|
+
mutator :add_item
|
352
|
+
configure_using ArrayConfiguration.configuration_block
|
353
|
+
end
|
354
|
+
end
|
355
|
+
|
356
|
+
instance = Example16.new
|
357
|
+
instance.add_item("Yo")
|
358
|
+
instance.once_more("Yo")
|
359
|
+
instance.names.count.should == 2
|
360
|
+
end
|
361
|
+
|
362
|
+
example 'Augment configuration of an existing array' do
|
363
|
+
|
364
|
+
module ExampleConfig1
|
365
|
+
extend self
|
366
|
+
|
367
|
+
def configuration_block
|
368
|
+
-> (array) { array.mutator :once_more }
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
class Example17
|
373
|
+
include ArrayFu
|
374
|
+
|
375
|
+
array :names do
|
376
|
+
readable
|
377
|
+
mutator :add_item
|
378
|
+
end
|
379
|
+
|
380
|
+
def initialize
|
381
|
+
array :names do
|
382
|
+
configure_using ExampleConfig1.configuration_block
|
383
|
+
end
|
384
|
+
super
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
instance = Example17.new
|
389
|
+
instance.add_item("Yo")
|
390
|
+
instance.once_more("Yo")
|
391
|
+
instance.names.count.should == 2
|
392
|
+
end
|
393
|
+
|
394
|
+
example 'Alternate way to augment configuration of an existing array' do
|
395
|
+
|
396
|
+
module ExampleConfig3
|
397
|
+
extend self
|
398
|
+
|
399
|
+
def configure(array_definition)
|
400
|
+
array_definition.mutator :once_more
|
401
|
+
end
|
402
|
+
end
|
403
|
+
|
404
|
+
class Example18
|
405
|
+
include ArrayFu
|
406
|
+
|
407
|
+
array :names do
|
408
|
+
readable
|
409
|
+
mutator :add_item
|
410
|
+
end
|
411
|
+
|
412
|
+
def initialize(config)
|
413
|
+
config.configure(array(:names))
|
414
|
+
super
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
instance = Example18.new(ExampleConfig3)
|
419
|
+
instance.add_item("Yo")
|
420
|
+
instance.once_more("Yo")
|
421
|
+
instance.names.count.should == 2
|
422
|
+
end
|
423
|
+
```
|
data/arrayfu.gemspec
CHANGED
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
# specify any dependencies here; for example:
|
22
22
|
s.add_development_dependency("rake", "~> 0.9.0")
|
23
|
+
s.add_development_dependency("yard", "~> 0.8.7.4")
|
23
24
|
s.add_development_dependency("guard", "~> 2.6.1")
|
24
25
|
s.add_development_dependency("guard-rspec", "~> 4.2.9")
|
25
26
|
s.add_development_dependency("fakes-rspec", "~> 2.0.0")
|
@@ -1,41 +1,121 @@
|
|
1
1
|
module ArrayFu
|
2
|
+
# A builder for specifying behaviours exposed by a class that defines arrays
|
2
3
|
class ArrayDefinition
|
3
4
|
include Initializer
|
4
5
|
|
5
|
-
|
6
|
-
|
6
|
+
# The name that will be given to this array definition, it will also become a variable named @[name] on the class that defined this array
|
7
|
+
attr_reader :name
|
8
|
+
# Flag for writeability
|
9
|
+
attr_accessor :writeable
|
10
|
+
# Flag for readability
|
7
11
|
attr_accessor :readable
|
12
|
+
# List of mutator definitions for this array
|
8
13
|
attr_accessor :mutators
|
14
|
+
# List of processing visitors
|
9
15
|
attr_accessor :visitors
|
16
|
+
|
17
|
+
# The list of constraints specified for this array definition
|
10
18
|
attr_accessor :constraints
|
11
19
|
|
20
|
+
# Create an array definition with the specified name
|
21
|
+
#
|
22
|
+
# == Parameters:
|
23
|
+
# @name::
|
24
|
+
# Name given to the array definition. This name will also be used to generate a variable on the target class named: @[name]
|
12
25
|
def initialize(name)
|
13
26
|
@name = name
|
14
27
|
initialize_arrays :mutators, :visitors, :constraints
|
15
|
-
initialize_false :
|
28
|
+
initialize_false :writeable, :readable
|
16
29
|
end
|
17
30
|
|
31
|
+
# Flag that the class that is defining this array will expose both a reader and writer for the array variable
|
32
|
+
#
|
33
|
+
# Example:
|
34
|
+
#
|
35
|
+
# class SomeClass
|
36
|
+
# include ArrayFu
|
37
|
+
#
|
38
|
+
# array :names { read_and_write }
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# The above is the same as the following
|
42
|
+
#
|
43
|
+
# class SomeClass
|
44
|
+
# attr_accessor :names
|
45
|
+
#
|
46
|
+
# def initialize
|
47
|
+
# @names = []
|
48
|
+
# end
|
49
|
+
# end
|
18
50
|
def read_and_write
|
19
|
-
|
51
|
+
writeable
|
20
52
|
readable
|
21
53
|
end
|
22
54
|
|
23
|
-
|
24
|
-
|
55
|
+
|
56
|
+
# Flag that the class that is defining this array will expose a writer for the array variable
|
57
|
+
def writeable
|
58
|
+
@writeable = true
|
25
59
|
end
|
26
60
|
|
61
|
+
# Flag that the class that is defining this array will expose a writer for the array variable
|
27
62
|
def readable
|
28
63
|
@readable = true
|
29
64
|
end
|
30
65
|
|
31
|
-
|
32
|
-
|
66
|
+
# Used by internal infrastructure to determine if this arraydefinition should expose a writer for the array variable
|
67
|
+
def writeable?
|
68
|
+
@writeable ||= false
|
33
69
|
end
|
34
70
|
|
71
|
+
# Used by internal infrastructure to determine if this arraydefinition should expose a reader for the array variable
|
35
72
|
def readable?
|
36
73
|
@readable ||= false
|
37
74
|
end
|
38
75
|
|
76
|
+
# This method allows for external configurators to customize the behaviour of this array definition
|
77
|
+
# == Parameters:
|
78
|
+
# configurators::
|
79
|
+
# One or many objects/blocks (can be a mix). If a configurator is an object, it must respond to the following method:
|
80
|
+
# def configure(definition)
|
81
|
+
# Where definition is an {ArrayDefinition}.
|
82
|
+
#
|
83
|
+
# If a configurator is a block, it will be a block that takes a singular parameter which is the {ArrayDefinition}
|
84
|
+
# Examples:
|
85
|
+
#
|
86
|
+
# * Configuring using an object
|
87
|
+
#
|
88
|
+
# class SomeConfigurator
|
89
|
+
# def self.configure(array_definition)
|
90
|
+
# array_definition.mutator :add_it
|
91
|
+
# end
|
92
|
+
# end
|
93
|
+
#
|
94
|
+
# class SomeClass
|
95
|
+
# include ArrayFu
|
96
|
+
#
|
97
|
+
# array :names do
|
98
|
+
# configure_using SomeConfigurator
|
99
|
+
# end
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# instance = SomeClass.new
|
103
|
+
# instance.add_it('JP')
|
104
|
+
#
|
105
|
+
# * Configuring using a lambda
|
106
|
+
#
|
107
|
+
# class SomeClass
|
108
|
+
# include ArrayFu
|
109
|
+
#
|
110
|
+
# array :names do
|
111
|
+
# configure_using -> (item) do
|
112
|
+
# item.mutator :add_it
|
113
|
+
# end
|
114
|
+
# end
|
115
|
+
# end
|
116
|
+
#
|
117
|
+
# instance = SomeClass.new
|
118
|
+
# instance.add_it('JP')
|
39
119
|
def configure_using(*configurators)
|
40
120
|
configurators.each do|configurator|
|
41
121
|
method = configurator.respond_to?(:configure) ? :configure : 'call'.to_sym
|
@@ -43,12 +123,70 @@ module ArrayFu
|
|
43
123
|
end
|
44
124
|
end
|
45
125
|
|
126
|
+
# Method used to specify a list of methods that will be exposed on the class that is defining this array. The methods are write methods that will push data back to the underlying array
|
127
|
+
#
|
128
|
+
# == Parameters:
|
129
|
+
# names::
|
130
|
+
# Method names that will be used to expose push methods to this array
|
131
|
+
# &block::
|
132
|
+
# If provided, this block will be run anytime the mutator method is invoked. It's single parameter is the new item that is attempting to be added to the underlying array
|
133
|
+
# if you provide this block, and dont push the item parameter back to the original array, no changes will happen to the underlying array
|
134
|
+
#
|
135
|
+
# Examples:
|
136
|
+
#
|
137
|
+
# class SomeClass
|
138
|
+
# include ArrayFu
|
139
|
+
#
|
140
|
+
# array :names { mutator :add_item }
|
141
|
+
# end
|
142
|
+
#
|
143
|
+
# The above will generate an instance method named :add_item on the SomeClass class. When you call this method, the names array will have an item pushed to it:
|
144
|
+
#
|
145
|
+
# instance = SomeClass.new
|
146
|
+
# instance.add_item('Hello') #the @names array variable will now contain ['Hello']
|
147
|
+
#
|
148
|
+
# You can specify multiple mutators at once:
|
149
|
+
#
|
150
|
+
# class SomeClass
|
151
|
+
# include ArrayFu
|
152
|
+
#
|
153
|
+
# array :names do
|
154
|
+
# mutator :add_item,
|
155
|
+
# :add_another,
|
156
|
+
# :add_one_more
|
157
|
+
# end
|
158
|
+
# end
|
159
|
+
#
|
160
|
+
# instance = SomeClass.new
|
161
|
+
# instance.add_item('JP')
|
162
|
+
# instance.add_another('Yeah')
|
163
|
+
# instance.add_one_more('Yep')
|
164
|
+
#
|
165
|
+
# Example:
|
166
|
+
#
|
167
|
+
# * A mutator with custom logic in a block
|
168
|
+
#
|
169
|
+
# class SomeClass
|
170
|
+
# include ArrayFu
|
171
|
+
#
|
172
|
+
# array :names do
|
173
|
+
# mutator :add_one do |item|
|
174
|
+
# puts 'About to add one new item #{item}'
|
175
|
+
# @names.push(item) #if this does not happen, no changes will occur to the underlying array
|
176
|
+
# end
|
177
|
+
# end
|
178
|
+
# end
|
179
|
+
#
|
180
|
+
# instance = SomeClass.new
|
181
|
+
# instance.add_one('JP') # at this point we will see a console out
|
182
|
+
#
|
46
183
|
def mutator(*names, &block)
|
47
184
|
names.each do |mutator_name|
|
48
185
|
self.mutators.push(MutatorDefinition.new(mutator_name, block))
|
49
186
|
end
|
50
187
|
end
|
51
188
|
|
189
|
+
# Null object implementation for a constraint failure (No-op)
|
52
190
|
module NoFailure
|
53
191
|
extend self
|
54
192
|
|
@@ -56,18 +194,31 @@ module ArrayFu
|
|
56
194
|
end
|
57
195
|
end
|
58
196
|
|
197
|
+
# Run each of its {ArrayFu::MutatorDefinition} against the provided block
|
59
198
|
def each_mutator(&block)
|
60
199
|
mutators.each &block
|
61
200
|
end
|
62
201
|
|
202
|
+
# Run each of its {ArrayFu::ItemConstraint} against the provided block
|
63
203
|
def each_constraint(&block)
|
64
204
|
constraints.each &block
|
65
205
|
end
|
66
206
|
|
207
|
+
# Run each of its {ArrayFu::VisitorDefinition} against the provided block
|
67
208
|
def each_visitor(&block)
|
68
209
|
visitors.each &block
|
69
210
|
end
|
70
211
|
|
212
|
+
# Adds a constraint that must be met for any new item being passed to a mutator method
|
213
|
+
# == Parameters:
|
214
|
+
# constraint::
|
215
|
+
# An object that responds to the following 2 methods:
|
216
|
+
# name: - Should return a descriptive name for the constraint
|
217
|
+
# matches?(item) - The constraint method, it will be called with any new item about to be added
|
218
|
+
# fail_option (defaults to {ArrayFu::ArrayDefinition::NoFailure})::
|
219
|
+
# An object that responds to the following methods:
|
220
|
+
# run(description, value) - Behaviour to run when the constraint is not met. It is given the description of the failed constraint, and the value
|
221
|
+
# that did not meet the constraint
|
71
222
|
def addition_constraint(constraint, fail_option = NoFailure)
|
72
223
|
self.constraints.push(ItemConstraint.new(constraint, fail_option))
|
73
224
|
end
|
@@ -77,6 +228,7 @@ module ArrayFu
|
|
77
228
|
self.visitors.push(VisitorDefinition.new(name, visitor))
|
78
229
|
end
|
79
230
|
|
231
|
+
# Method used by internal builder mechanism. Specifies the name that will be used for the backing array variable for this array definition
|
80
232
|
def variable_name
|
81
233
|
"@#{@name}"
|
82
234
|
end
|
data/lib/arrayfu/arrayfu.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# Main module that can be mixed in to allow for declaritive array definitions
|
2
|
+
#
|
1
3
|
module ArrayFu
|
2
4
|
include Initializer
|
3
5
|
|
@@ -5,6 +7,27 @@ module ArrayFu
|
|
5
7
|
base.extend ClassMethods
|
6
8
|
end
|
7
9
|
|
10
|
+
# This method is here to ensure that all of the array definitions are expanded and a variable instance is assigned to the variable name specified by the array
|
11
|
+
# If you are mixing in this module and the class has its own constructor definition, make sure you call super to ensure that array initialization occurs correctly as shown:
|
12
|
+
#
|
13
|
+
# class SomeClass
|
14
|
+
# include ArrayFu
|
15
|
+
#
|
16
|
+
# array :names
|
17
|
+
#
|
18
|
+
# def initialize(some_value)
|
19
|
+
# super
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# If your class does not contain custom constructor logic, no extra code is needed:
|
24
|
+
#
|
25
|
+
#
|
26
|
+
# class SomeClass
|
27
|
+
# include ArrayFu
|
28
|
+
#
|
29
|
+
# array :names
|
30
|
+
# end
|
8
31
|
def initialize(*args)
|
9
32
|
self.class.each_array_definition do |array_definition|
|
10
33
|
initialize_arrays(array_definition.name)
|
@@ -12,6 +35,49 @@ module ArrayFu
|
|
12
35
|
end
|
13
36
|
end
|
14
37
|
|
38
|
+
# Array definition dsl entry point
|
39
|
+
#
|
40
|
+
# == Parameters:
|
41
|
+
# name::
|
42
|
+
# A name that will be used to initialize a variable on the class that is including this module.
|
43
|
+
# It will serve as the backing array for the array definition
|
44
|
+
#
|
45
|
+
# &block::
|
46
|
+
# A configuration block that will serve to configure an {ArrayFu::ArrayDefinition}
|
47
|
+
#
|
48
|
+
# Examples:
|
49
|
+
#
|
50
|
+
# * Define a basic array
|
51
|
+
#
|
52
|
+
# class SomeClass
|
53
|
+
# include ArrayFu
|
54
|
+
#
|
55
|
+
# array :names
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# * Define a basic array that supports a read accessor
|
59
|
+
#
|
60
|
+
# class SomeClass
|
61
|
+
# include ArrayFu
|
62
|
+
#
|
63
|
+
# array :names { readable }
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# * Define a basic array that supports a write accessor
|
67
|
+
#
|
68
|
+
# class SomeClass
|
69
|
+
# include ArrayFu
|
70
|
+
#
|
71
|
+
# array :names { writeable }
|
72
|
+
# end
|
73
|
+
#
|
74
|
+
# * Define a basic array that supports both read and write accessors
|
75
|
+
#
|
76
|
+
# class SomeClass
|
77
|
+
# include ArrayFu
|
78
|
+
#
|
79
|
+
# array :names { read_and_write }
|
80
|
+
# end
|
15
81
|
def array(name, &block)
|
16
82
|
self.class.array(name, &block)
|
17
83
|
end
|
data/lib/arrayfu/version.rb
CHANGED
data/spec/examples/usage_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
example "Basic" do
|
4
|
-
class
|
4
|
+
class Example1
|
5
5
|
include ArrayFu
|
6
6
|
|
7
7
|
array :names
|
@@ -9,46 +9,53 @@ example "Basic" do
|
|
9
9
|
end
|
10
10
|
|
11
11
|
example 'Allow the array to have a read accessor' do
|
12
|
-
class
|
12
|
+
class Example2
|
13
13
|
include ArrayFu
|
14
14
|
|
15
15
|
array(:names) { readable }
|
16
16
|
end
|
17
|
-
|
17
|
+
Example2.new.names.should_not be_nil
|
18
18
|
end
|
19
19
|
|
20
20
|
example 'Allow the array to have a write accessor' do
|
21
|
-
class
|
21
|
+
class Example3
|
22
22
|
include ArrayFu
|
23
23
|
|
24
|
-
array(:names) {
|
24
|
+
array(:names) { writeable }
|
25
|
+
end
|
26
|
+
instance = Example3.new
|
27
|
+
new_names = []
|
28
|
+
instance.names = new_names
|
29
|
+
instance.instance_eval do
|
30
|
+
@names.should == new_names
|
25
31
|
end
|
26
|
-
SomeClass.new.names.should_not be_nil
|
27
32
|
end
|
28
33
|
|
29
34
|
example 'Allow the array to have a read and write accessor' do
|
30
|
-
class
|
35
|
+
class Example4
|
31
36
|
include ArrayFu
|
32
37
|
|
33
38
|
array(:names) { read_and_write }
|
34
39
|
end
|
35
|
-
|
40
|
+
Example4.new.names.should_not be_nil
|
36
41
|
end
|
37
42
|
|
38
43
|
example 'Add a mutator method to the class that stores the array' do
|
39
|
-
class
|
44
|
+
class Example5
|
40
45
|
include ArrayFu
|
41
46
|
|
42
47
|
array(:names) { mutator :add_item }
|
43
48
|
end
|
44
49
|
|
45
|
-
|
46
|
-
|
47
|
-
|
50
|
+
instance = Example5.new
|
51
|
+
instance.add_item("JP")
|
52
|
+
instance.instance_eval do
|
53
|
+
@names.count.should == 1
|
54
|
+
end
|
48
55
|
end
|
49
56
|
|
50
57
|
example 'Add multiple mutators to the class that stores the array' do
|
51
|
-
class
|
58
|
+
class Example6
|
52
59
|
include ArrayFu
|
53
60
|
|
54
61
|
array :names do
|
@@ -56,15 +63,17 @@ example 'Add multiple mutators to the class that stores the array' do
|
|
56
63
|
end
|
57
64
|
end
|
58
65
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
66
|
+
instance = Example6.new
|
67
|
+
instance.add_item("JP")
|
68
|
+
instance.add_it("JP")
|
69
|
+
instance.push_it("JP")
|
70
|
+
instance.instance_eval do
|
71
|
+
@names.count.should == 3
|
72
|
+
end
|
64
73
|
end
|
65
74
|
|
66
75
|
example 'Add a mutator that ignores addition' do
|
67
|
-
class
|
76
|
+
class Example7
|
68
77
|
include ArrayFu
|
69
78
|
|
70
79
|
array :names do
|
@@ -73,13 +82,15 @@ example 'Add a mutator that ignores addition' do
|
|
73
82
|
end
|
74
83
|
end
|
75
84
|
|
76
|
-
|
77
|
-
|
78
|
-
|
85
|
+
instance = Example7.new
|
86
|
+
instance.add_item("JP")
|
87
|
+
instance.instance_eval do
|
88
|
+
@names.count.should == 0
|
89
|
+
end
|
79
90
|
end
|
80
91
|
|
81
92
|
example 'Add a mutator that does other custom logic as well as addition' do
|
82
|
-
class
|
93
|
+
class Example8
|
83
94
|
include ArrayFu
|
84
95
|
|
85
96
|
array(:secondary) { readable }
|
@@ -93,10 +104,10 @@ example 'Add a mutator that does other custom logic as well as addition' do
|
|
93
104
|
end
|
94
105
|
end
|
95
106
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
107
|
+
instance = Example8.new
|
108
|
+
instance.add_item("JP")
|
109
|
+
instance.names.count.should == 1
|
110
|
+
instance.secondary.count.should == 1
|
100
111
|
end
|
101
112
|
|
102
113
|
example 'Add a singular constraint and failure condition to each of the mutators' do
|
@@ -120,19 +131,20 @@ example 'Add a singular constraint and failure condition to each of the mutators
|
|
120
131
|
end
|
121
132
|
end
|
122
133
|
|
123
|
-
class
|
134
|
+
class Example9
|
124
135
|
include ArrayFu
|
125
136
|
|
126
137
|
array :names do
|
138
|
+
readable
|
127
139
|
mutator :add_item,:add_it
|
128
140
|
new_item_must NotBeJP, CriteriaViolation
|
129
141
|
end
|
130
142
|
end
|
131
143
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
144
|
+
instance = Example9.new
|
145
|
+
instance.add_item("JP")
|
146
|
+
instance.add_it("JP")
|
147
|
+
instance.names.count.should == 0
|
136
148
|
end
|
137
149
|
|
138
150
|
example 'Add multiple constraints and a failure condition to each of the mutators' do
|
@@ -168,21 +180,22 @@ example 'Add multiple constraints and a failure condition to each of the mutator
|
|
168
180
|
end
|
169
181
|
end
|
170
182
|
|
171
|
-
class
|
183
|
+
class Example10
|
172
184
|
include ArrayFu
|
173
185
|
|
174
186
|
array :names do
|
187
|
+
readable
|
175
188
|
mutator :add_item,:add_it
|
176
189
|
addition_constraint NotBeJP
|
177
190
|
addition_constraint NotBeNil, CriteriaViolation
|
178
191
|
end
|
179
192
|
end
|
180
193
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
194
|
+
instance = Example10.new
|
195
|
+
instance.add_item("JP")
|
196
|
+
instance.add_it("JP")
|
197
|
+
instance.add_item(nil)
|
198
|
+
instance.names.count.should == 0
|
186
199
|
end
|
187
200
|
|
188
201
|
example 'Add an explicit processing visitor to the array' do
|
@@ -198,7 +211,7 @@ example 'Add an explicit processing visitor to the array' do
|
|
198
211
|
end
|
199
212
|
end
|
200
213
|
|
201
|
-
class
|
214
|
+
class Example11
|
202
215
|
include ArrayFu
|
203
216
|
|
204
217
|
array :names do
|
@@ -207,20 +220,20 @@ example 'Add an explicit processing visitor to the array' do
|
|
207
220
|
end
|
208
221
|
end
|
209
222
|
|
210
|
-
|
211
|
-
(1..10).each{|item|
|
212
|
-
|
223
|
+
instance = Example11.new
|
224
|
+
(1..10).each{|item| instance.add_item(item)}
|
225
|
+
instance.display_all
|
213
226
|
DisplayItem.item_count.should == 10
|
214
227
|
end
|
215
228
|
|
216
229
|
example 'Add an method based processing visitor to the array based on a method that exists on the items in the array' do
|
217
230
|
class Item
|
218
231
|
def process
|
219
|
-
|
232
|
+
Example12.increment
|
220
233
|
end
|
221
234
|
end
|
222
235
|
|
223
|
-
class
|
236
|
+
class Example12
|
224
237
|
@@items_visited = 0
|
225
238
|
include ArrayFu
|
226
239
|
|
@@ -239,10 +252,10 @@ example 'Add an method based processing visitor to the array based on a method t
|
|
239
252
|
end
|
240
253
|
end
|
241
254
|
|
242
|
-
|
243
|
-
(1..10).each{|item|
|
244
|
-
|
245
|
-
|
255
|
+
instance = Example12.new
|
256
|
+
(1..10).each{|item| instance.add_item(Item.new)}
|
257
|
+
instance.display_all
|
258
|
+
Example12.number_of_items_visited.should == 10
|
246
259
|
end
|
247
260
|
|
248
261
|
example 'Augment configuration using configuration block' do
|
@@ -252,19 +265,39 @@ example 'Augment configuration using configuration block' do
|
|
252
265
|
end
|
253
266
|
end
|
254
267
|
|
255
|
-
class
|
268
|
+
class Example13
|
256
269
|
include ArrayFu
|
257
270
|
|
258
271
|
array :names do
|
272
|
+
readable
|
259
273
|
mutator :add_item
|
260
274
|
configure_using ArrayConfigs.add_another_mutator
|
261
275
|
end
|
262
276
|
end
|
263
277
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
278
|
+
instance = Example13.new
|
279
|
+
instance.add_item("Yo")
|
280
|
+
instance.another_push("Yo")
|
281
|
+
instance.names.count.should == 2
|
282
|
+
end
|
283
|
+
|
284
|
+
example 'Augment configuration using inline configuration block' do
|
285
|
+
class Example14
|
286
|
+
include ArrayFu
|
287
|
+
|
288
|
+
array :names do
|
289
|
+
readable
|
290
|
+
mutator :add_item
|
291
|
+
configure_using -> (item) do
|
292
|
+
item.mutator :another_pushes
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
instance = Example14.new
|
298
|
+
instance.add_item("Yo")
|
299
|
+
instance.another_pushes("Yo")
|
300
|
+
instance.names.count.should == 2
|
268
301
|
end
|
269
302
|
|
270
303
|
example 'Augment configuration using configuration instance (anything that responds to configure with the array definition as the argument)' do
|
@@ -277,19 +310,20 @@ example 'Augment configuration using configuration instance (anything that respo
|
|
277
310
|
end
|
278
311
|
end
|
279
312
|
|
280
|
-
class
|
313
|
+
class Example15
|
281
314
|
include ArrayFu
|
282
315
|
|
283
316
|
array :names do
|
317
|
+
readable
|
284
318
|
mutator :add_item
|
285
319
|
configure_using ArrayConfiguration
|
286
320
|
end
|
287
321
|
end
|
288
322
|
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
323
|
+
instance = Example15.new
|
324
|
+
instance.add_item("Yo")
|
325
|
+
instance.once_more("Yo")
|
326
|
+
instance.names.count.should == 2
|
293
327
|
end
|
294
328
|
|
295
329
|
example 'Augment configuration using configuration block' do
|
@@ -304,50 +338,80 @@ example 'Augment configuration using configuration block' do
|
|
304
338
|
end
|
305
339
|
end
|
306
340
|
|
307
|
-
class
|
341
|
+
class Example16
|
308
342
|
include ArrayFu
|
309
343
|
|
310
344
|
array :names do
|
345
|
+
readable
|
311
346
|
mutator :add_item
|
312
347
|
configure_using ArrayConfiguration.configuration_block
|
313
348
|
end
|
314
349
|
end
|
315
350
|
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
351
|
+
instance = Example16.new
|
352
|
+
instance.add_item("Yo")
|
353
|
+
instance.once_more("Yo")
|
354
|
+
instance.names.count.should == 2
|
320
355
|
end
|
321
356
|
|
322
357
|
example 'Augment configuration of an existing array' do
|
323
358
|
|
324
|
-
module
|
359
|
+
module ExampleConfig1
|
325
360
|
extend self
|
326
361
|
|
327
362
|
def configuration_block
|
328
|
-
|
329
|
-
array.mutator :once_more
|
330
|
-
end
|
363
|
+
-> (array) { array.mutator :once_more }
|
331
364
|
end
|
332
365
|
end
|
333
366
|
|
334
|
-
class
|
367
|
+
class Example17
|
335
368
|
include ArrayFu
|
336
369
|
|
337
370
|
array :names do
|
371
|
+
readable
|
338
372
|
mutator :add_item
|
339
373
|
end
|
340
374
|
|
341
375
|
def initialize
|
342
|
-
super
|
343
376
|
array :names do
|
344
|
-
configure_using
|
377
|
+
configure_using ExampleConfig1.configuration_block
|
345
378
|
end
|
379
|
+
super
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
instance = Example17.new
|
384
|
+
instance.add_item("Yo")
|
385
|
+
instance.once_more("Yo")
|
386
|
+
instance.names.count.should == 2
|
387
|
+
end
|
388
|
+
|
389
|
+
example 'Alternate way to augment configuration of an existing array' do
|
390
|
+
|
391
|
+
module ExampleConfig3
|
392
|
+
extend self
|
393
|
+
|
394
|
+
def configure(array_definition)
|
395
|
+
array_definition.mutator :once_more
|
396
|
+
end
|
397
|
+
end
|
398
|
+
|
399
|
+
class Example18
|
400
|
+
include ArrayFu
|
401
|
+
|
402
|
+
array :names do
|
403
|
+
readable
|
404
|
+
mutator :add_item
|
405
|
+
end
|
406
|
+
|
407
|
+
def initialize(config)
|
408
|
+
config.configure(array(:names))
|
409
|
+
super
|
346
410
|
end
|
347
411
|
end
|
348
412
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
413
|
+
instance = Example18.new(ExampleConfig3)
|
414
|
+
instance.add_item("Yo")
|
415
|
+
instance.once_more("Yo")
|
416
|
+
instance.names.count.should == 2
|
353
417
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: arrayfu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Develop With Passion®
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 0.9.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: yard
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.8.7.4
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.8.7.4
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: guard
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -77,6 +91,7 @@ files:
|
|
77
91
|
- Gemfile
|
78
92
|
- Guardfile
|
79
93
|
- LICENSE
|
94
|
+
- README.md
|
80
95
|
- Rakefile
|
81
96
|
- arrayfu.gemspec
|
82
97
|
- lib/arrayfu.rb
|
@@ -137,3 +152,4 @@ test_files:
|
|
137
152
|
- spec/specs/generate_writers_step_spec.rb
|
138
153
|
- spec/specs/initializer_spec.rb
|
139
154
|
- spec/specs/item_constraint_spec.rb
|
155
|
+
has_rdoc:
|