callbacks_attachable 1.0.3 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 841ea199caa6811569cc442f4bb49848cae85667
4
- data.tar.gz: 559a012545ba5b1721f0c603ff6abceda05920a7
3
+ metadata.gz: 2585bc2a52a1a090b2d8792ce16a1b2b674769d9
4
+ data.tar.gz: b9212eaecc4af017f087bdbc17e0083c1678e048
5
5
  SHA512:
6
- metadata.gz: 0446b729f4bebdff0e3b2c2c304dcc1c54a83807e59c296ed4eb7623fb4e31328a3c94d091154dd8f755618e1846fc98c5024cdfb079d53fd61b039234d7b718
7
- data.tar.gz: eed08c3f04df0b8a8c0908d5da139b6fdfaf814201dfbdd4bb2a481002e78be1c561cb8bdcd73f9d6a4028f9b84db07025f29b8c257709006aebb9674faaabd6
6
+ metadata.gz: 68601c07625b6fb386431b10bab77bae900a91d813aba44b50e7755a9c803e157cfd124d319d0dd133852a547ab3deaccd3e28bff38722a625c0d981329cf70c
7
+ data.tar.gz: 5caa67e516872ba4e4a46bacf92c77d954193517a4d5d062b59a05cbd2e230cc7e4603f1001a5e820470d8473b207c8b67dc56248dd15296850285add0890494
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015 Christopher Aue
3
+ Copyright (c) 2015, 2016 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,8 +1,8 @@
1
1
  # CallbacksAttachable
2
2
 
3
- Attach callbacks to every ruby object including this mixin. Trigger all
4
- callbacks attached under the same namespace and detach callback when you no
5
- longer need them.
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.
6
6
 
7
7
  ## Installation
8
8
 
@@ -25,57 +25,54 @@ Or install it yourself as:
25
25
  ```ruby
26
26
  require 'callbacks_attachable'
27
27
 
28
- class CallbacksHolder
28
+ class AClass
29
29
  include CallbacksAttachable
30
30
  end
31
31
  ```
32
32
 
33
33
  ### Callbacks attached to the class
34
34
 
35
- Attach callbacks to the class:
35
+ Attach callbacks for an event to the class with:
36
36
 
37
37
  ```ruby
38
- callback = CallbacksHolder.on(:event) do |method|
38
+ callback = AClass.on(:event) do |method|
39
39
  puts self.__send__(method)
40
40
  end
41
41
  ```
42
42
 
43
- Callbacks attached to the class are executed in the context of it, i.e. `self`
44
- points to the class.
45
-
46
- Trigger all `:event` callbacks with:
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:
47
45
 
48
46
  ```ruby
49
- CallbacksHolder.trigger(:event, :name) # => puts 'CallbacksHolder'
47
+ AClass.trigger(:event, :name) # => puts 'AClass'
50
48
  ```
51
49
 
52
- The second and further arguments given to `.trigger` are passed down to the
53
- callback.
50
+ The second and other arguments given to `.trigger` are passed to the callback.
54
51
 
55
- Callbacks can be executed in the context of a different context by passing the
56
- `context` option to `.trigger`:
52
+ Callbacks attached to a class can also be triggered for just one of its
53
+ instances with `.trigger_for`:
57
54
 
58
55
  ```ruby
59
- object = Object.new
60
- CallbacksHolder.trigger(:event, :__id__, context: object)
61
- # => puts the result of object.__id__
56
+ an_instance = AClass.new
57
+ AClass.trigger_for(an_instance, :event, :__id__)
58
+ # => puts the result of an_instance.__id__
62
59
  ```
63
60
 
64
- To detach a callback call `.off` with the event namespace and the callback
65
- handle returned by `.on`:
61
+ To detach a callback call `.off` with the event's name and the callback handle
62
+ returned by `.on`:
66
63
 
67
64
  ```ruby
68
- CallbacksHolder.off(:event, callback)
69
- CallbacksHolder.trigger(:event, :name) # => nothing will happen
65
+ callback = AClass.on(:event) { do_something }
66
+ AClass.off(:event, callback)
70
67
  ```
71
68
 
72
69
  If you want to execute a callback just a single time attach it with `.once_on`:
73
70
 
74
71
  ```ruby
75
- CallbacksHolder.once_on(:singularity) { puts 'callback called!' }
76
- CallbacksHolder.trigger(:singularity) # => puts 'callback called!' and immediately
72
+ AClass.once_on(:singularity) { puts 'callback called!' }
73
+ AClass.trigger(:singularity) # => puts 'callback called!' and immediately
77
74
  # detaches the callback
78
- CallbacksHolder.trigger(:singularity) # => does nothing
75
+ AClass.trigger(:singularity) # => does nothing
79
76
  ```
80
77
 
81
78
  To detach a callback when a condition is met use `.until_true_on`. The callback
@@ -83,43 +80,42 @@ will be detached if it has a truthy (!) return value.
83
80
 
84
81
  ```ruby
85
82
  counter = 0
86
- CallbacksHolder.until_true_on(:count_to_two) do
83
+ AClass.until_true_on(:count_to_two) do
87
84
  puts counter
88
85
  counter >= 2
89
86
  end
90
87
 
91
- CallbacksHolder.trigger(:count_to_two) # => puts 0
92
- CallbacksHolder.trigger(:count_to_two) # => puts 1
93
- CallbacksHolder.trigger(:count_to_two) # => puts 2 and detaches the callback
94
- CallbacksHolder.trigger(:count_to_two) # => does nothing
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
95
92
  ```
96
93
 
97
94
  ### Callbacks attached to an instance
98
95
 
99
96
  All above mentioned methods on the class level also exist for each instance of
100
- the class. Callbacks are executed if the instance they are attached to or their
101
- class calls `#trigger`.
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.
102
100
 
103
- Callbacks are called in their lexical scope. So, `self` inside and outside
104
- the callback is the same object. The context of a callback cannot be changed
105
- with the `context` option of the `#trigger` method as it is possible for
106
- class callbacks.
101
+ Callbacks attached to individual instances are evaluated in their lexical scope.
102
+ So, `self` inside and outside the callback is the same object.
107
103
 
108
104
  ```ruby
109
- callbacks_holder1 = CallbacksHolder.new
110
- callbacks_holder2 = CallbacksHolder.new
105
+ an_instance1 = AClass.new
106
+ an_instance2 = AClass.new
111
107
 
112
- callback1 = callbacks_holder1.on(:event) { puts 'This is #1!' }
113
- callback2 = callbacks_holder2.on(:event) { puts 'This is #2!' }
108
+ callback1 = an_instance1.on(:event) { puts 'This is #1!' }
109
+ callback2 = an_instance2.on(:event) { puts 'This is #2!' }
114
110
 
115
- callbacks_holder1.trigger(:event) # => puts 'This is #1!'
116
- callbacks_holder2.trigger(:event) # => puts 'This is #2!'
111
+ an_instance1.trigger(:event) # => puts 'This is #1!'
112
+ an_instance2.trigger(:event) # => puts 'This is #2!'
117
113
 
118
- CallbacksHolder.trigger(:event) # => puts 'This is #1!' and 'This is #2!'
114
+ AClass.trigger(:event) # => puts 'This is #1!' and 'This is #2!'
119
115
 
120
- callbacks_holder1.off(:event, callback)
121
- callbacks_holder2.off(:event, callback)
116
+ an_instance1.off(:event, callback)
117
+ an_instance2.off(:event, callback)
122
118
  ```
123
119
 
124
120
  The two methods `#once_on` and `#until_true_on` are available for instances,
125
- too, and work as you'd expect.
121
+ too. They work as you'd expect.
@@ -1,17 +1,20 @@
1
1
  # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require 'callbacks_attachable/version'
2
+ require_relative 'mrblib/version'
5
3
 
6
4
  Gem::Specification.new do |spec|
7
5
  spec.name = "callbacks_attachable"
8
6
  spec.version = CallbacksAttachable::VERSION
9
- spec.authors = ["Christopher Aue"]
10
- spec.email = ["mail@christopheraue.net"]
7
+ spec.summary = %q{Attach callbacks to classes or individual instances.}
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.
12
+ DESC
11
13
 
12
- spec.summary = %q{Attach callbacks to ruby objects. Then, trigger and detach them.}
13
14
  spec.homepage = "https://github.com/christopheraue/ruby-callbacks_attachable"
14
15
  spec.license = "MIT"
16
+ spec.authors = ["Christopher Aue"]
17
+ spec.email = "rubygems@christopheraue.net"
15
18
 
16
19
  spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
17
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
@@ -20,6 +23,4 @@ Gem::Specification.new do |spec|
20
23
  spec.add_development_dependency "bundler", "~> 1.8"
21
24
  spec.add_development_dependency "rake", "~> 10.0"
22
25
  spec.add_development_dependency "rspec", "~> 3.4"
23
- spec.add_development_dependency "rspec-its"
24
- spec.add_development_dependency "rspec-mocks-matchers-send_message", "~> 0.3"
25
26
  end
@@ -1,64 +1,5 @@
1
- require "callbacks_attachable/version"
2
- require "callbacks_attachable/callback_handler"
3
- require "callbacks_attachable/instance_callback"
4
- require "callbacks_attachable/all_instances_callback"
5
-
6
- module CallbacksAttachable
7
- def self.included(klass)
8
- klass.extend ClassMethods
9
- end
10
-
11
- module ClassMethods
12
- def on(*args, &block)
13
- __callback_handler__.on(*args, &block)
14
- end
15
-
16
- def once_on(*args, &block)
17
- __callback_handler__.once_on(*args, &block)
18
- end
19
-
20
- def until_true_on(*args, &block)
21
- __callback_handler__.until_true_on(*args, &block)
22
- end
23
-
24
- def off(*args)
25
- __callback_handler__.off(*args)
26
- end
27
-
28
- def trigger(*args)
29
- __callback_handler__.trigger(*args)
30
- end
31
-
32
- private
33
-
34
- def __callback_handler__
35
- @__callback_handler__ ||= CallbackHandler.new(self, AllInstancesCallback)
36
- end
37
- end
38
-
39
- def on(*args, &block)
40
- __callback_handler__.on(*args, &block)
41
- end
42
-
43
- def once_on(*args, &block)
44
- __callback_handler__.once_on(*args, &block)
45
- end
46
-
47
- def until_true_on(*args, &block)
48
- __callback_handler__.until_true_on(*args, &block)
49
- end
50
-
51
- def off(*args)
52
- __callback_handler__.off(*args)
53
- end
54
-
55
- def trigger(*args)
56
- self.class.trigger(*args, instance: self) and __callback_handler__.trigger(*args)
57
- end
58
-
59
- private
60
-
61
- def __callback_handler__
62
- @__callback_handler__ ||= CallbackHandler.new(self, InstanceCallback)
63
- end
64
- end
1
+ require_relative "../mrblib/callbacks_attachable"
2
+ require_relative "../mrblib/version"
3
+ require_relative "../mrblib/callback_registry"
4
+ require_relative "../mrblib/instance_callback"
5
+ require_relative "../mrblib/all_instances_callback"
data/mrbgem.rake ADDED
@@ -0,0 +1,16 @@
1
+ require_relative 'mrblib/version'
2
+
3
+ MRuby::Gem::Specification.new('mruby-callbacks_attachable') do |spec|
4
+ spec.version = CallbacksAttachable::VERSION
5
+ spec.summary = %q{Attach callbacks to classes or individual instances.}
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.
10
+ DESC
11
+ spec.homepage = "https://github.com/christopheraue/ruby-callbacks_attachable"
12
+ spec.license = 'MIT'
13
+ spec.authors = ['Christopher Aue']
14
+
15
+ spec.add_dependency 'mruby-objectspace', :core => 'mruby-objectspace'
16
+ end
@@ -1,21 +1,13 @@
1
1
  module CallbacksAttachable
2
2
  class AllInstancesCallback
3
- def initialize(klass, skip: 0, &callback)
3
+ def initialize(klass, opts = {}, &callback)
4
4
  @class = klass
5
- @skip = skip
5
+ @skip = opts.fetch(:skip, 0)
6
6
  @callback = callback
7
7
  @call_counts = {}
8
8
  end
9
9
 
10
- def call(*args, **opts)
11
- if instance = opts[:instance]
12
- call_for_instance(instance, *args)
13
- else
14
- ObjectSpace.each_object(@class).all?{ |inst| call_for_instance(inst, *args) }
15
- end
16
- end
17
-
18
- def call_for_instance(instance, *args)
10
+ def call(instance, args)
19
11
  @call_counts[instance.__id__] = @call_counts[instance.__id__].to_i + 1
20
12
  return true if @call_counts[instance.__id__] <= @skip
21
13
  false != instance.instance_exec(*args, &@callback)
@@ -1,13 +1,13 @@
1
1
  module CallbacksAttachable
2
- class CallbackHandler
2
+ class CallbackRegistry
3
3
  def initialize(object, callback_class)
4
4
  @object = object
5
5
  @callback_class = callback_class
6
6
  end
7
7
 
8
- def on(event, skip: 0, &callback)
8
+ def on(event, opts = {}, &callback)
9
9
  __callbacks__[event] ||= []
10
- __callbacks__[event] << @callback_class.new(@object, skip: skip, &callback)
10
+ __callbacks__[event] << @callback_class.new(@object, opts, &callback)
11
11
  __callbacks__[event].last
12
12
  end
13
13
 
@@ -28,12 +28,12 @@ module CallbacksAttachable
28
28
  end
29
29
  end
30
30
 
31
- def trigger(event, *args, **opts)
31
+ def trigger(instance, event, args)
32
32
  return true if __callbacks__[event].nil?
33
33
 
34
34
  # dup the callback list so that removing callbacks while iterating does
35
35
  # still call all callbacks during map.
36
- __callbacks__[event].dup.all?{ |callback| callback.call(*args, **opts) }
36
+ __callbacks__[event].dup.all?{ |callback| callback.call(instance, args) }
37
37
  end
38
38
 
39
39
  def off(event, callback)
@@ -0,0 +1,59 @@
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)
9
+ end
10
+
11
+ def once_on(*args, &block)
12
+ __callback_registry__.once_on(*args, &block)
13
+ end
14
+
15
+ def until_true_on(*args, &block)
16
+ __callback_registry__.until_true_on(*args, &block)
17
+ end
18
+
19
+ def off(*args)
20
+ __callback_registry__.off(*args)
21
+ end
22
+
23
+ def trigger(event, *args)
24
+ ObjectSpace.each_object(self).all?{ |inst| inst.trigger(event, *args) }
25
+ end
26
+
27
+ private
28
+
29
+ def __callback_registry__
30
+ @__callback_registry__ ||= CallbackRegistry.new(self, AllInstancesCallback)
31
+ end
32
+ end
33
+
34
+ def on(*args, &block)
35
+ __callback_registry__.on(*args, &block)
36
+ end
37
+
38
+ def once_on(*args, &block)
39
+ __callback_registry__.once_on(*args, &block)
40
+ end
41
+
42
+ def until_true_on(*args, &block)
43
+ __callback_registry__.until_true_on(*args, &block)
44
+ end
45
+
46
+ def off(*args)
47
+ __callback_registry__.off(*args)
48
+ end
49
+
50
+ def trigger(event, *args)
51
+ self.class.__send__(:__callback_registry__).trigger(self, event, args) and __callback_registry__.trigger(self, event, args)
52
+ end
53
+
54
+ private
55
+
56
+ def __callback_registry__
57
+ @__callback_registry__ ||= CallbackRegistry.new(self, InstanceCallback)
58
+ end
59
+ end
@@ -1,13 +1,13 @@
1
1
  module CallbacksAttachable
2
2
  class InstanceCallback
3
- def initialize(instance, skip: 0, &callback)
3
+ def initialize(instance, opts = {}, &callback)
4
4
  @instance = instance
5
- @skip = skip
5
+ @skip = opts.fetch(:skip, 0)
6
6
  @callback = callback
7
7
  @call_count = 0
8
8
  end
9
9
 
10
- def call(*args, **opts)
10
+ def call(instance, args)
11
11
  @call_count += 1
12
12
  return true if @call_count <= @skip
13
13
  @callback.call(*args) != false
@@ -1,3 +1,3 @@
1
1
  module CallbacksAttachable
2
- VERSION = "1.0.3"
2
+ VERSION = "1.1.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.0.3
4
+ version: 1.1.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-03-10 00:00:00.000000000 Z
11
+ date: 2016-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,37 +52,11 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.4'
55
- - !ruby/object:Gem::Dependency
56
- name: rspec-its
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - ">="
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - ">="
67
- - !ruby/object:Gem::Version
68
- version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: rspec-mocks-matchers-send_message
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '0.3'
76
- type: :development
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '0.3'
83
- description:
84
- email:
85
- - mail@christopheraue.net
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.
59
+ email: rubygems@christopheraue.net
86
60
  executables: []
87
61
  extensions: []
88
62
  extra_rdoc_files: []
@@ -92,13 +66,14 @@ files:
92
66
  - Gemfile
93
67
  - LICENSE.txt
94
68
  - README.md
95
- - Rakefile
96
69
  - callbacks_attachable.gemspec
97
70
  - lib/callbacks_attachable.rb
98
- - lib/callbacks_attachable/all_instances_callback.rb
99
- - lib/callbacks_attachable/callback_handler.rb
100
- - lib/callbacks_attachable/instance_callback.rb
101
- - lib/callbacks_attachable/version.rb
71
+ - mrbgem.rake
72
+ - mrblib/all_instances_callback.rb
73
+ - mrblib/callback_registry.rb
74
+ - mrblib/callbacks_attachable.rb
75
+ - mrblib/instance_callback.rb
76
+ - mrblib/version.rb
102
77
  homepage: https://github.com/christopheraue/ruby-callbacks_attachable
103
78
  licenses:
104
79
  - MIT
@@ -119,8 +94,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
94
  version: '0'
120
95
  requirements: []
121
96
  rubyforge_project:
122
- rubygems_version: 2.4.5.1
97
+ rubygems_version: 2.5.1
123
98
  signing_key:
124
99
  specification_version: 4
125
- summary: Attach callbacks to ruby objects. Then, trigger and detach them.
100
+ summary: Attach callbacks to classes or individual instances.
126
101
  test_files: []
102
+ has_rdoc:
data/Rakefile DELETED
@@ -1,2 +0,0 @@
1
- require "bundler/gem_tasks"
2
-