ducktape 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -188,7 +188,7 @@ class X
188
188
  bindable :name, validate: [String, Symbol]
189
189
 
190
190
  def initialize(name)
191
- self.name = name
191
+ self.name = name
192
192
  end
193
193
  end
194
194
  ```
@@ -202,11 +202,35 @@ class X
202
202
  bindable :name, validate: ->(value){ !value.nil? }
203
203
 
204
204
  def initialize(name)
205
- self.name = name
205
+ self.name = name
206
206
  end
207
207
  end
208
208
  ```
209
209
 
210
+ Additionally, it has built-in support for regular expressions:
211
+
212
+ ```ruby
213
+ class X
214
+ include Ducktape::Bindable
215
+
216
+ bindable :name, validate: /ruby/
217
+
218
+ def initialize(name)
219
+ self.name = name
220
+ end
221
+ end
222
+
223
+ #passes
224
+ X.new('rubygems')
225
+
226
+ #fails
227
+ begin
228
+ X.new('diamonds')
229
+ rescue => e
230
+ puts e.message
231
+ end
232
+ ```
233
+
210
234
  Validation also works with any kind of objects. For example, to make an enumerable:
211
235
 
212
236
  ```ruby
@@ -266,12 +290,12 @@ class X
266
290
  bindable :points, validate: Integer
267
291
 
268
292
  def initialize(name, age, points)
269
- self.name = name
270
- self.age = age
271
- self.points = points
293
+ self.name = name
294
+ self.age = age
295
+ self.points = points
272
296
 
273
- # You can hook for any method available
274
- %w'name age points'.each { |k, v| on_changed k, &method(:attribute_changed) }
297
+ # You can hook for any method available
298
+ %w'name age points'.each { |k, v| on_changed k, &method(:attribute_changed) }
275
299
  end
276
300
  end
277
301
 
@@ -315,16 +339,18 @@ class X
315
339
  def_hook :on_loaded #define one or more hooks
316
340
 
317
341
  def load
318
- call_hooks(:on_loaded)
342
+ # do other stuff here
343
+
344
+ call_hooks(:on_loaded)
319
345
  end
320
346
  end
321
347
 
322
348
  x = X.new
323
349
 
324
- x.on_loaded &method(:called_load)
350
+ x.on_loaded method(:called_load)
325
351
 
326
352
  #if we didn't create a hook with def_hook we could still use:
327
- #x.add_hook :on_loaded, &method(:called_load)
353
+ #x.add_hook :on_loaded, method(:called_load)
328
354
 
329
355
  x.load
330
356
  ```
@@ -334,9 +360,62 @@ The output should be something like:
334
360
  => "X<14e35b4> called \"on_loaded\""
335
361
  ```
336
362
 
363
+ ### Named hooks
364
+
365
+ It is possible to define a hook by providing a method name. This makes it possible to separate logic from definition.
366
+ Note that the method must exist for the instance that calls the hooks (through `call_hooks` or `call_handlers`).
367
+
368
+ ```ruby
369
+ #class logic file
370
+
371
+ class Y
372
+ def called_load(event, owner)
373
+ puts "loaded #{self}" #self == owner
374
+ end
375
+
376
+ def load
377
+ #do some stuff here
378
+
379
+ call_hooks(:on_loaded)
380
+ end
381
+ end
382
+ ```
383
+
384
+ ```ruby
385
+ #instance definition file
386
+
387
+ x = Y.tap do |y|
388
+ y.on_loaded :called_load
389
+ end
390
+
391
+ x.load
392
+ ```
393
+
394
+ The output should be something like:
395
+ ```ruby
396
+ => "loaded Y<3539af>"
397
+ ```
398
+
399
+ This also allows to dynamically bind the hook by overriding the method.
400
+
401
+ ```ruby
402
+ #taking the same instance from before
403
+
404
+ x.define_singleton_method(:called_load) { puts "singleton #{self} has loaded" }
405
+ ```
406
+
407
+ The output should now be:
408
+ ```ruby
409
+ => "singleton Y<3539af> has loaded"
410
+ ```
411
+
337
412
  ### Removing hooks
338
413
 
339
- To remove all hooks from an object call the `#clear_hooks` method. To select a single hook, pass the name of the hook as a parameter. The next section has an example of this.
414
+ To remove all hooks from an object call the `#clear_hooks` method. To remove all hooks from a single event, pass the name of the event as a parameter. The next section has an example of this.
415
+
416
+ To remove a single hook from an event, call the `#remove_hook` with the name of the event, and the hook name or hook proc corresponding with how the hook was added.
417
+
418
+ ### Handlers
340
419
 
341
420
  ### Hookable arrays and hashes
342
421
 
@@ -396,6 +475,6 @@ The output will only be for the `on_changed` hook, which wasn't removed:
396
475
 
397
476
  Future work
398
477
  ===========
399
- * Pass a hook by method name. This will provide a more dynamic binding if the method is overriden.
400
478
  * Multi-sourced BA's.
401
- * More complex binding source paths instead of just the member name (e.g.: ruby like 'a.b.c' or xml like 'a/b/c').
479
+ * More complex binding source paths instead of just the member name (e.g.: ruby like 'a.b.c' or xml like 'a/b/c').
480
+ * Add built-in support for hookable arrays and hashes in bindable attributes.
@@ -51,9 +51,9 @@ module Ducktape
51
51
  nil
52
52
  end
53
53
 
54
- def on_changed(attr_name, &block)
55
- return nil unless block
56
- get_bindable_attr(attr_name.to_s).on_changed(&block)
54
+ def on_changed(attr_name, hook = nil, &block)
55
+ return nil unless block || hook
56
+ get_bindable_attr(attr_name.to_s).on_changed(hook, &block)
57
57
  block
58
58
  end
59
59
 
@@ -4,7 +4,7 @@ module Ducktape
4
4
 
5
5
  class InvalidAttributeValueError < StandardError
6
6
  def initialize(name, value)
7
- super("value #{value.inspect} is invalid for attribute '#{name}'")
7
+ super("value #{value.inspect} is invalid for attribute #{name.to_s.inspect}")
8
8
  end
9
9
  end
10
10
 
@@ -7,7 +7,8 @@ module Ducktape
7
7
 
8
8
  def initialize(name, options = {})
9
9
 
10
- options.each_key { |k| puts "WARNING: invalid option #{k.inspect} for #{name.inspect} attribute. Will be ignored." unless VALID_OPTIONS.member?(k) }
10
+ options.keys.reject { |k| VALID_OPTIONS.member?(k) }.
11
+ each { |k| puts "WARNING: invalid option #{k.inspect} for #{name.inspect} attribute. Will be ignored." }
11
12
 
12
13
  if name.is_a? BindableAttributeMetadata
13
14
  @name = name.name
@@ -39,10 +40,11 @@ module Ducktape
39
40
 
40
41
  def validate(value)
41
42
  return true unless @validation
42
- @validation.each do |validation|
43
- return true if (validation.is_a?(Class) and value.is_a?(validation)) or
44
- (validation.is_a?(Proc) and validation.call(value)) or
45
- value == validation
43
+ @validation.each do |v|
44
+ return true if ( v.is_a?(Class) && value.is_a?(v) ) ||
45
+ ( v.is_a?(Proc) && v.(value) ) ||
46
+ ( v.is_a?(Regexp) && value =~ v ) ||
47
+ value == v
46
48
  end
47
49
  false
48
50
  end
@@ -3,7 +3,7 @@ module Ducktape
3
3
 
4
4
  module ClassMethods
5
5
  def def_hook(*events)
6
- events.each { |e| define_method e, ->(&block){ add_hook(e, &block) } }
6
+ events.each { |e| define_method e, ->(method_name = nil, &block){ add_hook(e, method_name, &block) } }
7
7
  end
8
8
  end
9
9
 
@@ -15,23 +15,25 @@ module Ducktape
15
15
  raise 'Cannot extend, only include.'
16
16
  end
17
17
 
18
- def add_hook(event, &block)
19
- return unless block
20
- self.hooks[event.to_s].unshift block
21
- nil
18
+ def add_hook(event, hook = nil, &block)
19
+ hook = block if block #block has precedence
20
+ return unless hook
21
+ hook = hook.to_s unless hook.is_a?(Proc)
22
+ self.hooks[event.to_s].unshift(hook)
23
+ hook
22
24
  end
23
25
 
24
- def remove_hook(event, block)
25
- self.hooks[event.to_s].delete(block)
26
+ def remove_hook(event, hook)
27
+ hook = hook.to_s unless hook.is_a?(Proc)
28
+ self.hooks[event.to_s].delete(hook)
26
29
  end
27
30
 
28
31
  def clear_hooks(event = nil)
29
32
  if event
30
33
  self.hooks.delete(event.to_s)
31
34
  else
32
- self.hooks.clear
35
+ self.hooks.clear.dup
33
36
  end
34
- nil
35
37
  end
36
38
 
37
39
  protected
@@ -41,14 +43,19 @@ module Ducktape
41
43
 
42
44
  def call_hooks(event, caller, *args)
43
45
  return unless self.hooks.has_key? event.to_s
44
- self.hooks[event.to_s].each { |hook| hook.call(event, caller, *args) }
46
+ self.hooks[event.to_s].each do |hook|
47
+ hook = caller.method(hook) unless hook.is_a?(Proc)
48
+ hook.(event, caller, *args)
49
+ end
45
50
  nil
46
51
  end
47
52
 
53
+ # Similar to `call_hooks`, but stops calling other hooks when a hook returns a value other than nil or false.
48
54
  def call_handlers(event, caller, *args)
49
55
  return unless self.hooks.has_key? event.to_s
50
56
  self.hooks[event.to_s].each do |hook|
51
- handled = hook.call(event, caller, *args)
57
+ hook = caller.method(hook) unless hook.is_a?(Proc)
58
+ handled = hook.(event, caller, *args)
52
59
  return handled if handled
53
60
  end
54
61
  nil
data/lib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ducktape
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ducktape
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: