has-guarded-handlers 1.2.0 → 1.3.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.
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # [develop](https://github.com/adhearsion/has-guarded-handlers)
2
2
 
3
+ # [1.3.0](https://github.com/adhearsion/has-guarded-handlers/compare/v1.2.0...v1.3.0) - [2012-07-03](https://rubygems.org/gems/has-guarded-handlers/versions/1.3.0)
4
+ * Feature: It is now possible to register a handler to process all events
5
+ * Bugfix: Temporary handlers were being removed after the first event even if their guards didn't match
6
+ * Bugfix: Fix for a syntax error on Ruby 1.8
7
+
3
8
  # [1.2.0](https://github.com/adhearsion/has-guarded-handlers/compare/v1.1.0...v1.2.0) - [2012-03-28](https://rubygems.org/gems/has-guarded-handlers/versions/1.2.0)
4
9
  * Feature: Allow registering temporary (single execution) handlers which are removed after they are triggered
5
10
  * Feature: Registering a handler returns an ID by which it may be unregistered
data/README.md CHANGED
@@ -11,23 +11,148 @@ require 'has_guarded_handlers'
11
11
 
12
12
  class A
13
13
  include HasGuardedHandlers
14
-
15
- def receive_event(event)
16
- trigger_handler :event, event
17
- end
18
14
  end
19
15
 
20
16
  a = A.new
21
- a.register_handler :event, :type => :foo do
22
- puts "Handled the event"
17
+ a.register_handler :event, :type => :foo do |event|
18
+ puts "Handled the event of type #{event.type} with value #{event.value}"
23
19
  end
24
20
 
25
- class Event
26
- attr_accessor :type
27
- end
21
+ Event = Class.new Struct.new(:type, :value)
22
+
23
+ a.trigger_handler :event, Event.new(:foo, 'bar')
24
+ ```
25
+
26
+ Register a handler for a particular named channel:
27
+
28
+ ```ruby
29
+ a.register_handler(:event) { ... }
30
+ # or
31
+ a.register_handler(:event, :type => :foo) { ... }
32
+
33
+ a.trigger_handler :event, :foo
34
+ ```
35
+
36
+ Register a global handler for all channels:
37
+
38
+ ```ruby
39
+ a.register_handler { ... }
40
+ # or
41
+ a.register_handler(nil, :type => :foo) { ... }
42
+
43
+ a.trigger_handler :event, :foo
44
+ ```
45
+
46
+ Register a temporary handler, which is deleted once triggered:
47
+
48
+ ```ruby
49
+ a.register_tmp_handler(:event) { ... } # This will only fire once
50
+ a.trigger_handler :event, :foo
51
+ ```
52
+
53
+ Handlers are triggered in order of priority, followed by order of declaration. By default, all handlers are registered with priority 0, and are thus executed in the order declared:
54
+
55
+ ```ruby
56
+ a.register_handler { ... } # This is triggered first
57
+ a.register_handler { ... } # This is triggered second
58
+ ...
59
+
60
+ a.trigger_handler :event, :foo
61
+ ```
62
+
63
+ You may specify a handler priority in order to change this order. Higher priority is executed first:
64
+
65
+ ```ruby
66
+ a.register_handler(:event) { ... } # This is triggered second
67
+ a.register_handler_with_priority(:event, 10) { ... } # This is triggered first
68
+ ...
69
+
70
+ a.trigger_handler :event, :foo
71
+ ```
72
+
73
+ You may specify a priority for a temporary handler:
74
+
75
+ ```ruby
76
+ a.register_handler_with_options(:event, {:tmp => true, :priority => 10}, :foo => :bar) { ... }
77
+ ```
78
+
79
+ ### Handler chaining
80
+
81
+ When multiple handlers match the event, the return value of each handler will determine if the handler chain continues. A truthy return value will cause the handler to swallow the event and halt the handler chain. A falsy return value will continue the chain.
82
+
83
+ It is possible to explicitly pass to the next handler by throwing `:pass` in your handler:
84
+
85
+ ```ruby
86
+ a.register_handler(:event) { throw :pass }
87
+ a.register_handler(:event) { ... } # This will be executed
88
+
89
+ a.trigger_handler :event, :foo
90
+ ```
91
+
92
+ or indeed explicitly halt the handler chain by throwing `:halt` in the handler:
93
+
94
+ ```ruby
95
+ a.register_handler(:event) { throw :halt }
96
+ a.register_handler(:event) { ... } # This will not be executed
97
+
98
+ a.trigger_handler :event, :foo
99
+ ```
100
+
101
+ ### What are guards?
102
+
103
+ Guards are a concept borrowed from Erlang. They help to better compartmentalise handlers.
104
+
105
+ There are a number of guard types and one bit of special syntax. Guards act like AND statements. Each condition must be met if the handler is to be used.
106
+
107
+ ```ruby
108
+ # Equivalent to saying (stanza.chat? && stanza.body)
109
+ message :chat?, :body
110
+ ```
111
+
112
+ The different types of guards are:
113
+
114
+ ```ruby
115
+ # Class / Module
116
+ # Checks that the event is of the type specified
117
+ # Equivalent to event.is_a? Foo
118
+ register_handler Foo
119
+
120
+ # Symbol
121
+ # Checks for a non-false reply to calling the symbol on the event
122
+ # Equivalent to event.chat?
123
+ register_handler :chat?
124
+
125
+ # Hash with any value (:body => 'exit')
126
+ # Calls the key on the event and checks for equality
127
+ # Equivalent to event.body == 'exit'
128
+ register_handler :body => 'exit'
129
+
130
+ # Hash with regular expression (:body => /exit/)
131
+ # Calls the key on the event and checks for a match
132
+ # Equivalent to event.body.match /exit/
133
+ register_handler :body => /exit/
134
+
135
+ # Hash with array value (:name => [:gone, :forbidden])
136
+ # Calls the key on the event and check for inclusion in the array
137
+ # Equivalent to [:gone, :forbidden].include?(event.name)
138
+ register_handler :name => [:gone, :fobidden]
139
+
140
+ # Hash with array key ([:[], :name] => :gone)
141
+ # Calls the first element of the key on the event, passing the other elements as arguments
142
+ # and checks the value matches
143
+ # Equivalent to event[:name] == :gone
144
+ register_handler [:[], :name] => :gone
145
+
146
+ # Proc
147
+ # Calls the proc passing in the event
148
+ # Checks that the ID is modulo 3
149
+ register_handler proc { |m| m.id % 3 == 0 }
28
150
 
29
- event = Event.new.tap { |e| e.type = :foo }
30
- a.receive_event event
151
+ # Array
152
+ # Use arrays with the previous types effectively turns the guard into
153
+ # an OR statement.
154
+ # Equivalent to event.body == 'foo' || event.body == 'baz'
155
+ register_handler [{:body => 'foo'}, {:body => 'baz'}]
31
156
  ```
32
157
 
33
158
  ## Links:
@@ -46,4 +171,4 @@ a.receive_event event
46
171
 
47
172
  ## Copyright
48
173
 
49
- Copyright (c) 2011 Ben Langfeld, Jeff Smick. MIT licence (see LICENSE for details).
174
+ Copyright (c) 2011 Ben Langfeld, Jeff Smick. MIT licence (see LICENSE.md for details).
@@ -1,3 +1,3 @@
1
1
  module HasGuardedHandlers
2
- VERSION = "1.2.0"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -4,44 +4,44 @@ require 'uuid'
4
4
  module HasGuardedHandlers
5
5
  # Register a handler
6
6
  #
7
- # @param [Symbol, nil] type a classification to separate handlers/events into channels
7
+ # @param [Symbol, nil] type a classification to separate handlers/events into channels. Omitting the classification will create a handler for all events.
8
8
  # @param [guards] guards take a look at the guards documentation
9
9
  #
10
10
  # @yield [Object] trigger_object the incoming event
11
11
  #
12
12
  # @return [String] handler ID for later manipulation
13
- def register_handler(type, *guards, &handler)
13
+ def register_handler(type = nil, *guards, &handler)
14
14
  register_handler_with_options type, {}, *guards, &handler
15
15
  end
16
16
 
17
17
  # Register a temporary handler. Once triggered, the handler will be de-registered
18
18
  #
19
- # @param [Symbol, nil] type a classification to separate handlers/events into channels
19
+ # @param [Symbol, nil] type a classification to separate handlers/events into channels Omitting the classification will create a handler for all events.
20
20
  # @param [guards] guards take a look at the guards documentation
21
21
  #
22
22
  # @yield [Object] trigger_object the incoming event
23
23
  #
24
24
  # @return [String] handler ID for later manipulation
25
- def register_tmp_handler(type, *guards, &handler)
25
+ def register_tmp_handler(type = nil, *guards, &handler)
26
26
  register_handler_with_options type, {:tmp => true}, *guards, &handler
27
27
  end
28
28
 
29
29
  # Register a handler with a specified priority
30
30
  #
31
- # @param [Symbol, nil] type a classification to separate handlers/events into channels
31
+ # @param [Symbol, nil] type a classification to separate handlers/events into channels Omitting the classification will create a handler for all events.
32
32
  # @param [Integer] priority the priority of the handler. Higher priority executes first
33
33
  # @param [guards] guards take a look at the guards documentation
34
34
  #
35
35
  # @yield [Object] trigger_object the incoming event
36
36
  #
37
37
  # @return [String] handler ID for later manipulation
38
- def register_handler_with_priority(type, priority, *guards, &handler)
38
+ def register_handler_with_priority(type = nil, priority = 0, *guards, &handler)
39
39
  register_handler_with_options type, {:priority => priority}, *guards, &handler
40
40
  end
41
41
 
42
42
  # Register a handler with a specified set of options
43
43
  #
44
- # @param [Symbol, nil] type a classification to separate handlers/events into channels
44
+ # @param [Symbol, nil] type a classification to separate handlers/events into channels Omitting the classification will create a handler for all events.
45
45
  # @param [Hash] options the options for the handler
46
46
  # @option options [Integer] :priority (0) the priority of the handler. Higher priority executes first
47
47
  # @option options [true, false] :tmp (false) Wether or not the handler should be considered temporary (single execution)
@@ -50,7 +50,7 @@ module HasGuardedHandlers
50
50
  # @yield [Object] trigger_object the incoming event
51
51
  #
52
52
  # @return [String] handler ID for later manipulation
53
- def register_handler_with_options(type, options, *guards, &handler)
53
+ def register_handler_with_options(type = nil, options = {}, *guards, &handler)
54
54
  check_guards guards
55
55
  options[:priority] ||= 0
56
56
  new_handler_id.tap do |handler_id|
@@ -70,7 +70,7 @@ module HasGuardedHandlers
70
70
  #
71
71
  # @param [Symbol, nil] type remove filters for a specific handler
72
72
  # @param [guards] guards take a look at the guards documentation
73
- def clear_handlers(type, *guards)
73
+ def clear_handlers(type = nil, *guards)
74
74
  delete_handler_if(type) { |g, _| g == guards }
75
75
  end
76
76
 
@@ -82,8 +82,8 @@ module HasGuardedHandlers
82
82
  return unless handler = handlers_of_type(type)
83
83
  catch :halt do
84
84
  handler.find do |guards, handler, tmp|
85
- catch(:pass) { call_handler handler, guards, event }
86
- delete_handler_if(type) { |_, h, _| h.equal? handler } if tmp
85
+ val = catch(:pass) { call_handler handler, guards, event }
86
+ delete_handler_if(type) { |_, h, _| h.equal? handler } if tmp && val
87
87
  end
88
88
  end
89
89
  end
@@ -102,6 +102,10 @@ module HasGuardedHandlers
102
102
  hash.keys.sort.reverse.each do |key|
103
103
  values += hash[key]
104
104
  end
105
+ global_handlers = guarded_handlers[nil]
106
+ global_handlers.keys.sort.reverse.each do |key|
107
+ values += global_handlers[key]
108
+ end
105
109
  values
106
110
  end
107
111
 
@@ -17,10 +17,23 @@ describe HasGuardedHandlers do
17
17
  subject.trigger_handler :event, event
18
18
  end
19
19
 
20
+ it 'can register a handler for all events, regardless of category' do
21
+ response.expects(:call).twice.with(event)
22
+ subject.register_handler { |e| response.call e }
23
+ subject.trigger_handler :event, event
24
+ subject.trigger_handler :bah, event
25
+ end
26
+
20
27
  it 'can register a one-shot (tmp) handler' do
21
28
  response.expects(:call).once.with(event)
22
- subject.register_tmp_handler(:event) { |e| response.call e }
23
- subject.trigger_handler :event, event
29
+ event.expects(:foo).once.returns :bar
30
+
31
+ nomatch_event = mock 'Event(nomatch)'
32
+ nomatch_event.expects(:foo).once.returns :baz
33
+
34
+ subject.register_tmp_handler(:event, :foo => :bar) { |e| response.call e }
35
+
36
+ subject.trigger_handler :event, nomatch_event
24
37
  subject.trigger_handler :event, event
25
38
  end
26
39
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: has-guarded-handlers
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,11 +10,11 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2012-03-28 00:00:00.000000000 Z
13
+ date: 2012-07-03 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: uuid
17
- requirement: &2152452540 !ruby/object:Gem::Requirement
17
+ requirement: !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ! '>='
@@ -22,10 +22,15 @@ dependencies:
22
22
  version: '0'
23
23
  type: :runtime
24
24
  prerelease: false
25
- version_requirements: *2152452540
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
26
31
  - !ruby/object:Gem::Dependency
27
32
  name: bundler
28
- requirement: &2152452020 !ruby/object:Gem::Requirement
33
+ requirement: !ruby/object:Gem::Requirement
29
34
  none: false
30
35
  requirements:
31
36
  - - ~>
@@ -33,10 +38,15 @@ dependencies:
33
38
  version: '1.0'
34
39
  type: :development
35
40
  prerelease: false
36
- version_requirements: *2152452020
41
+ version_requirements: !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ version: '1.0'
37
47
  - !ruby/object:Gem::Dependency
38
48
  name: rspec
39
- requirement: &2152451500 !ruby/object:Gem::Requirement
49
+ requirement: !ruby/object:Gem::Requirement
40
50
  none: false
41
51
  requirements:
42
52
  - - ! '>='
@@ -44,10 +54,15 @@ dependencies:
44
54
  version: 2.5.0
45
55
  type: :development
46
56
  prerelease: false
47
- version_requirements: *2152451500
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ! '>='
61
+ - !ruby/object:Gem::Version
62
+ version: 2.5.0
48
63
  - !ruby/object:Gem::Dependency
49
64
  name: mocha
50
- requirement: &2152451020 !ruby/object:Gem::Requirement
65
+ requirement: !ruby/object:Gem::Requirement
51
66
  none: false
52
67
  requirements:
53
68
  - - ! '>='
@@ -55,10 +70,15 @@ dependencies:
55
70
  version: '0'
56
71
  type: :development
57
72
  prerelease: false
58
- version_requirements: *2152451020
73
+ version_requirements: !ruby/object:Gem::Requirement
74
+ none: false
75
+ requirements:
76
+ - - ! '>='
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
59
79
  - !ruby/object:Gem::Dependency
60
80
  name: ci_reporter
61
- requirement: &2164285360 !ruby/object:Gem::Requirement
81
+ requirement: !ruby/object:Gem::Requirement
62
82
  none: false
63
83
  requirements:
64
84
  - - ! '>='
@@ -66,10 +86,15 @@ dependencies:
66
86
  version: 1.6.3
67
87
  type: :development
68
88
  prerelease: false
69
- version_requirements: *2164285360
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ! '>='
93
+ - !ruby/object:Gem::Version
94
+ version: 1.6.3
70
95
  - !ruby/object:Gem::Dependency
71
96
  name: yard
72
- requirement: &2164284000 !ruby/object:Gem::Requirement
97
+ requirement: !ruby/object:Gem::Requirement
73
98
  none: false
74
99
  requirements:
75
100
  - - ! '>='
@@ -77,10 +102,15 @@ dependencies:
77
102
  version: 0.7.0
78
103
  type: :development
79
104
  prerelease: false
80
- version_requirements: *2164284000
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: 0.7.0
81
111
  - !ruby/object:Gem::Dependency
82
112
  name: rake
83
- requirement: &2164282100 !ruby/object:Gem::Requirement
113
+ requirement: !ruby/object:Gem::Requirement
84
114
  none: false
85
115
  requirements:
86
116
  - - ! '>='
@@ -88,10 +118,15 @@ dependencies:
88
118
  version: '0'
89
119
  type: :development
90
120
  prerelease: false
91
- version_requirements: *2164282100
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ none: false
123
+ requirements:
124
+ - - ! '>='
125
+ - !ruby/object:Gem::Version
126
+ version: '0'
92
127
  - !ruby/object:Gem::Dependency
93
128
  name: guard-rspec
94
- requirement: &2164281140 !ruby/object:Gem::Requirement
129
+ requirement: !ruby/object:Gem::Requirement
95
130
  none: false
96
131
  requirements:
97
132
  - - ! '>='
@@ -99,7 +134,12 @@ dependencies:
99
134
  version: '0'
100
135
  type: :development
101
136
  prerelease: false
102
- version_requirements: *2164281140
137
+ version_requirements: !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ! '>='
141
+ - !ruby/object:Gem::Version
142
+ version: '0'
103
143
  description: Allow an object's API to provide flexible handler registration, storage
104
144
  and matching to arbitrary events.
105
145
  email:
@@ -134,15 +174,21 @@ required_ruby_version: !ruby/object:Gem::Requirement
134
174
  - - ! '>='
135
175
  - !ruby/object:Gem::Version
136
176
  version: '0'
177
+ segments:
178
+ - 0
179
+ hash: -3018957415088485817
137
180
  required_rubygems_version: !ruby/object:Gem::Requirement
138
181
  none: false
139
182
  requirements:
140
183
  - - ! '>='
141
184
  - !ruby/object:Gem::Version
142
185
  version: '0'
186
+ segments:
187
+ - 0
188
+ hash: -3018957415088485817
143
189
  requirements: []
144
190
  rubyforge_project: has-guarded-handlers
145
- rubygems_version: 1.8.10
191
+ rubygems_version: 1.8.24
146
192
  signing_key:
147
193
  specification_version: 3
148
194
  summary: A library for associating a set of event handlers, complete with guards,
@@ -150,4 +196,3 @@ summary: A library for associating a set of event handlers, complete with guards
150
196
  test_files:
151
197
  - spec/has_guarded_handlers_spec.rb
152
198
  - spec/spec_helper.rb
153
- has_rdoc: