callbacks_attachable 1.2.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 81a1654f014d9e55c862d04cddc2220b77d08fc2
4
- data.tar.gz: 38e878bb95354ecbc13fcae519e8a35dc70c0779
3
+ metadata.gz: 8b3cbb8d4bd7ce32583ce955de64c50b6c573df8
4
+ data.tar.gz: 9f7a8fa43ff82a24fad63277df0a8966fff4bc9e
5
5
  SHA512:
6
- metadata.gz: 41df492f40cc6746035513c53a4e503d647359db01bd3b88697eb324b258a5d500178b90a26db91ecff10e4ee4b3814a7fed0f2b5f4df16cf4c907714f4e3fae
7
- data.tar.gz: 9dc191acaa137a6478b245039b7586c7ca30d73ebbfce741207ff64e4105078d54bc0075223f4f4315af37cab71837aac1882437de343c699a3f90aebc34e3d3
6
+ metadata.gz: 04afd03c6c374d2cbd40052dafd3c92f9884d8a77303643aec0b91dec3a4655887e27d5d881d5eeb78419765313040cf2e658b6f2e842a33a82a92cf7cc228b6
7
+ data.tar.gz: 48e973e7699b8ead7d098afb8589b261cdf481340a757693a9e629ed4a9906fbe1c42df06349318f6d0f47c906319f5bdbbc9581e9925857a5344e38489cf4e4
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015, 2016 Christopher Aue
3
+ Copyright (c) 2015 - 2017 Christopher Aue
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,22 +1,21 @@
1
1
  # CallbacksAttachable
2
2
 
3
- Attach callbacks to a class and trigger them for all its instances or just one
4
- particular instance. Additionally, instances can also have their own set of
5
- individual callbacks.
3
+ Attach callbacks to classes to be triggered for all instances or attach them
4
+ to an individual instance to be triggered only for this instance.
6
5
 
7
6
  ## Installation
8
7
 
9
8
  Add this line to your application's Gemfile:
10
9
 
11
10
  ```ruby
12
- gem 'callbacks_attachable'
11
+ gem 'callbacks_attachable', '~> 2.0'
13
12
  ```
14
13
 
15
14
  And then execute:
16
15
 
17
16
  $ bundle
18
17
 
19
- Or install it yourself as:
18
+ Or install it yourself:
20
19
 
21
20
  $ gem install callbacks_attachable
22
21
 
@@ -32,90 +31,72 @@ end
32
31
 
33
32
  ### Callbacks attached to the class
34
33
 
35
- Attach callbacks for an event to the class with:
34
+ Attach callbacks for an event for all instances of a class with:
36
35
 
37
36
  ```ruby
38
- callback = AClass.on(:event) do |method|
39
- puts self.__send__(method)
37
+ callback = AClass.on(:event) do |instance, method|
38
+ puts instance.__send__(method)
40
39
  end
41
- ```
42
40
 
43
- Callbacks attached to a class are executed in the context of each existing
44
- instance. To trigger all `:event` callbacks for all instances of `AClass`, use:
41
+ instance0 = AClass.new(value: 0)
42
+ instance1 = AClass.new(value: 1)
45
43
 
46
- ```ruby
47
- AClass.trigger(:event, :name) # => puts 'AClass'
44
+ AClass.trigger(:event, :value) # => 0
45
+ # 1
48
46
  ```
49
47
 
50
- The second and other arguments given to `.trigger` are passed to the callback.
51
-
52
- Callbacks attached to a class can also be triggered for just one of its
53
- instances with `.trigger_for`:
54
-
55
- ```ruby
56
- an_instance = AClass.new
57
- AClass.trigger_for(an_instance, :event, :__id__)
58
- # => puts the result of an_instance.__id__
59
- ```
48
+ The first argument of the callback is the instance the callback is executed
49
+ for. The second and further arguments given to `.trigger` are passed to the
50
+ callback as additional arguments.
60
51
 
61
- To detach a callback call `.off` with the event's name and the callback handle
62
- returned by `.on`:
52
+ Registering a callback returns a `Callback` object. To cancel the callback use
53
+ `#cancel` on that object.
63
54
 
64
55
  ```ruby
65
56
  callback = AClass.on(:event) { do_something }
66
- AClass.off(:event, callback)
57
+ callback.cancel
67
58
  ```
68
59
 
69
60
  If you want to execute a callback just a single time attach it with `.once_on`:
70
61
 
71
62
  ```ruby
72
- AClass.once_on(:singularity) { puts 'callback called!' }
73
- AClass.trigger(:singularity) # => puts 'callback called!' and immediately
74
- # detaches the callback
75
- AClass.trigger(:singularity) # => does nothing
63
+ AClass.once_on(:singular) { puts 'callback called!' }
64
+ AClass.trigger(:singular) # => puts 'callback called!' and immediately
65
+ # detaches the callback
66
+ AClass.trigger(:singular) # => does nothing
76
67
  ```
77
68
 
78
- To detach a callback when a condition is met use `.until_true_on`. The callback
79
- will be detached if it has a truthy (!) return value.
69
+ To filter the instances to call the callback for, use the `:if` option:
80
70
 
81
71
  ```ruby
82
- counter = 0
83
- AClass.until_true_on(:count_to_two) do
84
- puts counter
85
- counter >= 2
72
+ instance0 = AClass.new(value: 0)
73
+ instance1 = AClass.new(value: 1)
74
+ instance2 = AClass.new(value: 2)
75
+ AClass.on(:even, if: proc{ |inst| inst.value.even? }) do |instance|
76
+ puts instance.value
86
77
  end
87
78
 
88
- AClass.trigger(:count_to_two) # => puts 0
89
- AClass.trigger(:count_to_two) # => puts 1
90
- AClass.trigger(:count_to_two) # => puts 2 and detaches the callback
91
- AClass.trigger(:count_to_two) # => does nothing
79
+ AClass.trigger(:even) # => 0
80
+ # 2
92
81
  ```
93
82
 
83
+ This is especially useful in combination with `.once_on` to execute the
84
+ callback just for the first instance meeting certain criteria.
85
+
94
86
  ### Callbacks attached to an instance
95
87
 
96
88
  All above mentioned methods on the class level also exist for each instance of
97
- the class. Callbacks for an individual instance are executed by calling
98
- `#trigger` on it. They are also called, when calling `.trigger` or
99
- `.trigger_for(instance, ...)` on its class.
89
+ the class.
100
90
 
101
- Callbacks attached to individual instances are evaluated in their lexical scope.
102
- So, `self` inside and outside the callback is the same object.
91
+ Callbacks for an individual instance are executed by calling `#trigger` on it.
92
+ This also executes callbacks attached to the class.
103
93
 
104
94
  ```ruby
105
- an_instance1 = AClass.new
106
- an_instance2 = AClass.new
107
-
108
- callback1 = an_instance1.on(:event) { puts 'This is #1!' }
109
- callback2 = an_instance2.on(:event) { puts 'This is #2!' }
110
-
111
- an_instance1.trigger(:event) # => puts 'This is #1!'
112
- an_instance2.trigger(:event) # => puts 'This is #2!'
95
+ instance = AClass.new
113
96
 
114
- AClass.trigger(:event) # => puts 'This is #1!' and 'This is #2!'
115
-
116
- an_instance1.off(:event, callback)
117
- an_instance2.off(:event, callback)
118
- ```
97
+ AClass.on(:event) { puts 'class callback' }
98
+ instance.on(:event) { puts 'instance callback' }
119
99
 
120
- The two methods `#once_on` and `#until_true_on` are available for instances,
121
- too. They work as you'd expect.
100
+ instance.trigger(:event) # => 'class callback'
101
+ # 'instance callback'
102
+ ```
@@ -6,9 +6,8 @@ Gem::Specification.new do |spec|
6
6
  spec.version = CallbacksAttachable::VERSION
7
7
  spec.summary = %q{Attach callbacks to classes or individual instances.}
8
8
  spec.description = <<-DESC
9
- Attach callbacks to a class and trigger them for all its instances or just one
10
- particular instance. Additionally, instances can also have their own set of
11
- individual callbacks.
9
+ Attach callbacks to classes to be triggered for all instances or attach them
10
+ to an individual instance to be triggered only for this instance.
12
11
  DESC
13
12
 
14
13
  spec.homepage = "https://github.com/christopheraue/m-ruby-callbacks_attachable"
@@ -1,5 +1,4 @@
1
1
  require_relative "../mrblib/callbacks_attachable"
2
2
  require_relative "../mrblib/version"
3
3
  require_relative "../mrblib/callback_registry"
4
- require_relative "../mrblib/instance_callback"
5
- require_relative "../mrblib/all_instances_callback"
4
+ require_relative "../mrblib/callback"
data/mrbgem.rake CHANGED
@@ -4,9 +4,8 @@ MRuby::Gem::Specification.new('mruby-callbacks_attachable') do |spec|
4
4
  spec.version = CallbacksAttachable::VERSION
5
5
  spec.summary = %q{Attach callbacks to classes or individual instances.}
6
6
  spec.description = <<-DESC
7
- Attach callbacks to a class and trigger them for all its instances or just one
8
- particular instance. Additionally, instances can also have their own set of
9
- individual callbacks.
7
+ Attach callbacks to classes to be triggered for all instances or attach them
8
+ to an individual instance to be triggered only for this instance.
10
9
  DESC
11
10
 
12
11
  spec.homepage = "https://github.com/christopheraue/m-ruby-callbacks_attachable"
@@ -0,0 +1,27 @@
1
+ module CallbacksAttachable
2
+ class Callback
3
+ def initialize(registry, event, opts = {}, callback)
4
+ @registry = registry
5
+ @event = event
6
+ @call_condition = opts.fetch(:if, false)
7
+ @cancel_condition = opts.fetch(:until, false)
8
+ @callback = callback
9
+ end
10
+
11
+ def call(instance, args)
12
+ return if @call_condition and not @call_condition.call instance, *args
13
+ @callback.call(instance, *args)
14
+ cancel if @cancel_condition and @cancel_condition.call instance, *args
15
+ end
16
+
17
+ def on_cancel(&on_cancel)
18
+ @on_cancel = on_cancel
19
+ end
20
+
21
+ def cancel
22
+ @registry.deregister @event, self
23
+ @on_cancel.call if @on_cancel
24
+ true
25
+ end
26
+ end
27
+ end
@@ -1,45 +1,28 @@
1
1
  module CallbacksAttachable
2
2
  class CallbackRegistry
3
- def initialize(object, callback_class)
4
- @object = object
5
- @callback_class = callback_class
3
+ def initialize(owner)
4
+ @owner = owner
6
5
  @callbacks = {}
7
6
  end
8
7
 
9
- def on(event, opts = {}, &callback)
10
- @callbacks[event] ||= []
11
- @callbacks[event] << @callback_class.new(@object, opts, &callback)
12
- @callbacks[event].last
8
+ def register(event, opts, callback)
9
+ @callbacks[event] ||= {}
10
+ callback = Callback.new(self, event, opts, callback)
11
+ @callbacks[event][callback] = true
12
+ callback
13
13
  end
14
14
 
15
- def once_on(event, *opts, &callback)
16
- callback_registry = self
17
- registered_callback = @object.on(event, *opts) do |*args|
18
- callback_registry.off(event, registered_callback)
19
- yield(*args)
20
- end
21
- end
22
-
23
- def until_true_on(event, *opts, &callback)
24
- callback_registry = self
25
- registered_callback = @object.on(event, *opts) do |*args|
26
- yield(*args).tap do |result|
27
- callback_registry.off(event, registered_callback) if result
28
- end
29
- end
15
+ def registered?(event)
16
+ @callbacks.key? event
30
17
  end
31
18
 
32
19
  def trigger(instance, event, args)
33
- return true unless @callbacks[event]
34
-
35
- # dup the callback list so that removing callbacks while iterating does
36
- # still call all callbacks during map.
37
- @callbacks[event].dup.all?{ |callback| callback.call(instance, args) }
20
+ @callbacks[event] and @callbacks[event].keys.each{ |callback| callback.call(instance, args) }
38
21
  end
39
22
 
40
- def off(event, callback)
41
- return unless @callbacks[event]
23
+ def deregister(event, callback)
42
24
  @callbacks[event].delete(callback)
25
+ @callbacks.delete(event) if @callbacks[event].empty?
43
26
  end
44
27
  end
45
28
  end
@@ -1,67 +1,40 @@
1
1
  module CallbacksAttachable
2
- def self.included(klass)
3
- klass.extend ClassMethods
4
- end
5
-
6
- module ClassMethods
7
- def on(*args, &block)
8
- __callback_registry__.on(*args, &block)
2
+ module RegistryOwnable
3
+ def on(event, opts = {}, &callback)
4
+ __callbacks__.register(event, opts, callback)
9
5
  end
10
- alias on_event on
11
6
 
12
- def once_on(*args, &block)
13
- __callback_registry__.once_on(*args, &block)
7
+ def once_on(event, opts = {}, &callback)
8
+ on(event, opts.merge(until: proc{ true }), &callback)
14
9
  end
15
- alias once_on_event once_on
16
10
 
17
- def until_true_on(*args, &block)
18
- __callback_registry__.until_true_on(*args, &block)
19
- end
20
- alias until_true_on_event until_true_on
21
-
22
- def off(*args)
23
- __callback_registry__.off(*args)
24
- end
25
- alias off_event off
26
-
27
- def trigger(event, *args)
28
- ObjectSpace.each_object(self).all?{ |inst| inst.trigger(event, *args) }
11
+ def on?(event)
12
+ __callbacks__.registered? event
29
13
  end
30
- alias trigger_event trigger
31
14
 
32
- def __callback_registry__
33
- @__callback_registry__ ||= CallbackRegistry.new(self, AllInstancesCallback)
15
+ private def __callbacks__
16
+ @__callbacks__ ||= CallbackRegistry.new(self)
34
17
  end
35
18
  end
36
19
 
37
- def on(*args, &block)
38
- __callback_registry__.on(*args, &block)
39
- end
40
- alias on_event on
20
+ include RegistryOwnable
41
21
 
42
- def once_on(*args, &block)
43
- __callback_registry__.once_on(*args, &block)
22
+ def self.included(klass)
23
+ klass.extend ClassMethods
44
24
  end
45
- alias once_on_event once_on
46
25
 
47
- def until_true_on(*args, &block)
48
- __callback_registry__.until_true_on(*args, &block)
49
- end
50
- alias until_true_on_event until_true_on
26
+ module ClassMethods
27
+ include RegistryOwnable
51
28
 
52
- def off(*args)
53
- __callback_registry__.off(*args)
29
+ def trigger(event, *args)
30
+ ObjectSpace.each_object(self).all?{ |inst| inst.trigger(event, *args) }
31
+ end
54
32
  end
55
- alias off_event off
56
33
 
57
34
  def trigger(event, *args)
58
- self.class.__callback_registry__.trigger(self, event, args) and __callback_registry__.trigger(self, event, args)
59
- end
60
- alias trigger_event trigger
61
-
62
- private
63
-
64
- def __callback_registry__
65
- @__callback_registry__ ||= CallbackRegistry.new(self, InstanceCallback)
35
+ @class_callbacks ||= self.class.__send__ :__callbacks__
36
+ @class_callbacks.trigger(self, event, args)
37
+ @__callbacks__ and @__callbacks__.trigger(self, event, args)
38
+ true
66
39
  end
67
40
  end
data/mrblib/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module CallbacksAttachable
2
- VERSION = "1.2.0"
2
+ VERSION = "2.0.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: callbacks_attachable
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Aue
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-18 00:00:00.000000000 Z
11
+ date: 2017-02-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -53,9 +53,8 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.4'
55
55
  description: |
56
- Attach callbacks to a class and trigger them for all its instances or just one
57
- particular instance. Additionally, instances can also have their own set of
58
- individual callbacks.
56
+ Attach callbacks to classes to be triggered for all instances or attach them
57
+ to an individual instance to be triggered only for this instance.
59
58
  email:
60
59
  - rubygems@christopheraue.net
61
60
  executables: []
@@ -70,10 +69,9 @@ files:
70
69
  - callbacks_attachable.gemspec
71
70
  - lib/callbacks_attachable.rb
72
71
  - mrbgem.rake
73
- - mrblib/all_instances_callback.rb
72
+ - mrblib/callback.rb
74
73
  - mrblib/callback_registry.rb
75
74
  - mrblib/callbacks_attachable.rb
76
- - mrblib/instance_callback.rb
77
75
  - mrblib/version.rb
78
76
  homepage: https://github.com/christopheraue/m-ruby-callbacks_attachable
79
77
  licenses:
@@ -1,16 +0,0 @@
1
- module CallbacksAttachable
2
- class AllInstancesCallback
3
- def initialize(klass, opts = {}, &callback)
4
- @class = klass
5
- @skip = opts.fetch(:skip, 0)
6
- @callback = callback
7
- @call_counts = {}
8
- end
9
-
10
- def call(instance, args)
11
- @call_counts[instance.__id__] = @call_counts[instance.__id__].to_i + 1
12
- return true if @call_counts[instance.__id__] <= @skip
13
- false != instance.instance_exec(*args, &@callback)
14
- end
15
- end
16
- end
@@ -1,16 +0,0 @@
1
- module CallbacksAttachable
2
- class InstanceCallback
3
- def initialize(instance, opts = {}, &callback)
4
- @instance = instance
5
- @skip = opts.fetch(:skip, 0)
6
- @callback = callback
7
- @call_count = 0
8
- end
9
-
10
- def call(instance, args)
11
- @call_count += 1
12
- return true if @call_count <= @skip
13
- @callback.call(*args) != false
14
- end
15
- end
16
- end