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 +5 -0
- data/README.md +137 -12
- data/lib/has_guarded_handlers/version.rb +1 -1
- data/lib/has_guarded_handlers.rb +15 -11
- data/spec/has_guarded_handlers_spec.rb +15 -2
- metadata +65 -20
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
|
-
|
26
|
-
|
27
|
-
|
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
|
-
|
30
|
-
|
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).
|
data/lib/has_guarded_handlers.rb
CHANGED
@@ -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
|
-
|
23
|
-
|
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.
|
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
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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:
|
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.
|
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:
|