arrayfu 0.2.4 → 1.0.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 +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:
|