has-guarded-handlers 1.2.0 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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: