message_router 0.1.3 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/.travis.yml +10 -0
- data/Gemfile +8 -4
- data/Gemfile.lock +50 -18
- data/Guardfile +29 -5
- data/README.rdoc +40 -37
- data/lib/message_router/router.rb +97 -77
- data/lib/message_router/version.rb +1 -1
- data/message_router.gemspec +2 -2
- data/spec/message_router_spec.rb +178 -169
- metadata +29 -45
- data/.rvmrc +0 -1
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 41cf9f1df6c11508d36a7dda6cce51a70ba19f30
|
4
|
+
data.tar.gz: 8168d00903f7ee8255021d28c251876e56a9787c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f6ea5ea859997e69e646bb65d3505a2d7f65b51a73f22a3613bf91970fbf2890cc9ef99253f482b6ea9c424d6fd85c6ceb3a41ab16d43f3192b5befefb035fc
|
7
|
+
data.tar.gz: 9f06de8f00cce839914fdce6ed191e84c447d03ab0687ba948d2fb791943cb2428859efd7a06260ed0638b962f5d85ea45b1e2e2a5679e0af80d03c277e0078a
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.2
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -1,12 +1,16 @@
|
|
1
|
-
source "
|
1
|
+
source "https://rubygems.org"
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in message_router.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
group :test, :development do
|
6
|
+
group :ci, :test, :development do
|
7
7
|
gem 'rspec'
|
8
|
-
gem '
|
8
|
+
gem 'rake'
|
9
|
+
end
|
10
|
+
|
11
|
+
group :test, :development do
|
12
|
+
gem 'listen'
|
9
13
|
gem 'growl'
|
10
14
|
gem 'guard'
|
11
15
|
gem 'guard-rspec'
|
12
|
-
end
|
16
|
+
end
|
data/Gemfile.lock
CHANGED
@@ -1,27 +1,58 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
message_router (0.
|
4
|
+
message_router (0.2.0)
|
5
5
|
|
6
6
|
GEM
|
7
|
-
remote:
|
7
|
+
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
|
-
|
9
|
+
celluloid (0.16.0)
|
10
|
+
timers (~> 4.0.0)
|
11
|
+
coderay (1.1.0)
|
12
|
+
diff-lcs (1.2.5)
|
13
|
+
ffi (1.9.6)
|
14
|
+
formatador (0.2.5)
|
10
15
|
growl (1.0.3)
|
11
|
-
guard (
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
rspec
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
guard (2.6.1)
|
17
|
+
formatador (>= 0.2.4)
|
18
|
+
listen (~> 2.7)
|
19
|
+
lumberjack (~> 1.0)
|
20
|
+
pry (>= 0.9.12)
|
21
|
+
thor (>= 0.18.1)
|
22
|
+
guard-rspec (4.3.1)
|
23
|
+
guard (~> 2.1)
|
24
|
+
rspec (>= 2.14, < 4.0)
|
25
|
+
hitimes (1.2.2)
|
26
|
+
listen (2.7.11)
|
27
|
+
celluloid (>= 0.15.2)
|
28
|
+
rb-fsevent (>= 0.9.3)
|
29
|
+
rb-inotify (>= 0.9)
|
30
|
+
lumberjack (1.0.9)
|
31
|
+
method_source (0.8.2)
|
32
|
+
pry (0.10.1)
|
33
|
+
coderay (~> 1.1.0)
|
34
|
+
method_source (~> 0.8.1)
|
35
|
+
slop (~> 3.4)
|
36
|
+
rake (10.3.2)
|
37
|
+
rb-fsevent (0.9.4)
|
38
|
+
rb-inotify (0.9.5)
|
39
|
+
ffi (>= 0.5.0)
|
40
|
+
rspec (3.1.0)
|
41
|
+
rspec-core (~> 3.1.0)
|
42
|
+
rspec-expectations (~> 3.1.0)
|
43
|
+
rspec-mocks (~> 3.1.0)
|
44
|
+
rspec-core (3.1.7)
|
45
|
+
rspec-support (~> 3.1.0)
|
46
|
+
rspec-expectations (3.1.2)
|
47
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
48
|
+
rspec-support (~> 3.1.0)
|
49
|
+
rspec-mocks (3.1.3)
|
50
|
+
rspec-support (~> 3.1.0)
|
51
|
+
rspec-support (3.1.2)
|
52
|
+
slop (3.6.0)
|
53
|
+
thor (0.19.1)
|
54
|
+
timers (4.0.1)
|
55
|
+
hitimes
|
25
56
|
|
26
57
|
PLATFORMS
|
27
58
|
ruby
|
@@ -30,6 +61,7 @@ DEPENDENCIES
|
|
30
61
|
growl
|
31
62
|
guard
|
32
63
|
guard-rspec
|
64
|
+
listen
|
33
65
|
message_router!
|
34
|
-
|
66
|
+
rake
|
35
67
|
rspec
|
data/Guardfile
CHANGED
@@ -1,8 +1,32 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
4
|
+
# Note: The cmd option is now required due to the increasing number of ways
|
5
|
+
# rspec may be run, below are examples of the most common uses.
|
6
|
+
# * bundler: 'bundle exec rspec'
|
7
|
+
# * bundler binstubs: 'bin/rspec'
|
8
|
+
# * spring: 'bin/rsspec' (This will use spring if running and you have
|
9
|
+
# installed the spring binstubs per the docs)
|
10
|
+
# * zeus: 'zeus rspec' (requires the server to be started separetly)
|
11
|
+
# * 'just' rspec: 'rspec'
|
12
|
+
guard :rspec, cmd: 'bundle exec rspec' do
|
13
|
+
watch(%r{^spec/.+_spec\.rb$})
|
14
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
15
|
+
watch('spec/spec_helper.rb') { "spec" }
|
16
|
+
|
17
|
+
# Rails example
|
18
|
+
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
19
|
+
watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
|
20
|
+
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
21
|
+
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
22
|
+
watch('config/routes.rb') { "spec/routing" }
|
23
|
+
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
24
|
+
watch('spec/rails_helper.rb') { "spec" }
|
25
|
+
|
26
|
+
# Capybara features specs
|
27
|
+
watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
|
28
|
+
|
29
|
+
# Turnip features and steps
|
30
|
+
watch(%r{^spec/acceptance/(.+)\.feature$})
|
31
|
+
watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
|
32
|
+
end
|
data/README.rdoc
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
= Message Router
|
2
2
|
|
3
|
+
{<img src="https://travis-ci.org/polleverywhere/message_router.svg?branch=master" alt="Build Status" />}[https://travis-ci.org/polleverywhere/message_router]
|
4
|
+
{<img src="https://codeclimate.com/github/polleverywhere/message_router/badges/gpa.svg" />}[https://codeclimate.com/github/polleverywhere/message_router]
|
5
|
+
|
3
6
|
Message router is a DSL for routing and processing simple messages, like SMS messages or Tweets.
|
4
7
|
|
5
8
|
== Installation
|
@@ -12,30 +15,30 @@ See rdoc for MessageRouter::Router.build (lib/message_router/router.rb) for exam
|
|
12
15
|
|
13
16
|
And now some irb action.
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
Hi there. You sent me: {'body'=>"can you say hi to me?"}
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
WTF? I don't know how to do that!
|
35
|
-
|
36
|
-
|
37
|
-
Hi there. You sent me: {'body'=>"can you say hi to me?", 'to'=>"greeter"}
|
38
|
-
|
18
|
+
class HelloRouter < MessageRouter::Router
|
19
|
+
match /hi/ do
|
20
|
+
puts "Hi there. You sent me: #{env.inspect}"
|
21
|
+
true # puts returns nil, and that would fail the matcher
|
22
|
+
end
|
23
|
+
end
|
24
|
+
# => [[/hi/, #<Proc:0x00000000026963b8@(irb):2>]]
|
25
|
+
HelloRouter.call({'body' => 'can you say hi to me?'})
|
26
|
+
# Hi there. You sent me: {'body'=>"can you say hi to me?"}
|
27
|
+
# => true
|
28
|
+
class MainRouter < MessageRouter::Router
|
29
|
+
match({'to' => 'greeter'}, HelloRouter)
|
30
|
+
match(true) do
|
31
|
+
puts "WTF? I don't know how to do that!"
|
32
|
+
true # puts returns nil, and that would fail the matcher
|
33
|
+
end
|
34
|
+
end
|
35
|
+
# => [[{"to"=>"greeter"}, HelloRouter], [true, #<Proc:0x007f98c39e5b70@(irb):13>]]
|
36
|
+
MainRouter.call({'body' => 'can you say hi to me?'})
|
37
|
+
# WTF? I don't know how to do that!
|
38
|
+
# => true
|
39
|
+
MainRouter.call({'body' => 'can you say hi to me?', 'to' => 'greeter'})
|
40
|
+
# Hi there. You sent me: {'body'=>"can you say hi to me?", 'to'=>"greeter"}
|
41
|
+
# => true
|
39
42
|
|
40
43
|
|
41
44
|
== TODO
|
@@ -57,7 +60,7 @@ Add tests to ensure that instance variables can be shared between initializers a
|
|
57
60
|
@sender.puts 'something'
|
58
61
|
end
|
59
62
|
end
|
60
|
-
MyRouter
|
63
|
+
MyRouter(:sender => STDOUT).call({}) # prints out 'something' to standard out.
|
61
64
|
|
62
65
|
Pass Regexp captures on to the proc when there is a match. Examples:
|
63
66
|
match /some (cool|awesome) thing/ do |match|
|
@@ -106,17 +109,17 @@ Make helper methods defined (or included) in parent routers available in sub rou
|
|
106
109
|
Pass around copies of the env Hash instead of modifying the existing Hash in place.
|
107
110
|
* This _might_ help with multi-threading
|
108
111
|
* Perhaps a parent router wants to delegate to 2 sub-routers which are independent of each other. The current implementation has a shared env hash, so I couldn't use multi-threading, (though forking could work). I would have to trust the user to call #dup on at least one of the env hashes. With this new way, it is safe by default.
|
109
|
-
* Convention would be for the '
|
112
|
+
* Convention would be for the 'condition' Procs to return a copy of the env hashes, either modified or not, depending on their needs.
|
110
113
|
* They would still return nil or false if they don't match.
|
111
114
|
* We could also require (by convention only) that sub-routers also return a copy of the env hash (if they succeed) so this (optionally modified) env hash can be used for further routing.
|
112
115
|
* This would give the original router access to both the modified env hash and the original env hash.
|
113
116
|
|
114
|
-
Find a way to allow user-defined '
|
117
|
+
Find a way to allow user-defined 'action' procs/blocks to not have to return a true value to be considered to have matched. We still need a way to know if a sub-router matched or not. This _may_require that the code treat sub-routers and user-defined 'action' procs/blocks differently, which could get awkward.
|
115
118
|
|
116
119
|
Allow routers to accept an optional logger. Depending on the log level, print out info such as:
|
117
120
|
* When a matcher is registered
|
118
121
|
* Each time a matcher is evaluated, including what the return value was.
|
119
|
-
* Each time a '
|
122
|
+
* Each time a 'action' block is evaluated, including what the return value was.
|
120
123
|
Each time we write to the log include the following (depending on the log level):
|
121
124
|
* The value of the env hash
|
122
125
|
* The name of the class (so we can tell which subclass we are in)
|
@@ -132,21 +135,21 @@ Consider having a class called Run nested within the router's namespace. Instead
|
|
132
135
|
end
|
133
136
|
Run#run might look something like:
|
134
137
|
def run
|
135
|
-
router.rules.detect do |
|
136
|
-
|
137
|
-
self.instance_eval &
|
138
|
+
router.rules.detect do |condition, action|
|
139
|
+
condition = if condition.kind_of?(Proc)
|
140
|
+
self.instance_eval &condition
|
138
141
|
else
|
139
|
-
|
142
|
+
condition.call env
|
140
143
|
end
|
141
144
|
|
142
|
-
if
|
143
|
-
|
144
|
-
self.instance_eval &
|
145
|
+
if condition
|
146
|
+
action = if action.kind_of?(Proc)
|
147
|
+
self.instance_eval &action
|
145
148
|
else
|
146
|
-
|
149
|
+
action.call env
|
147
150
|
end
|
148
151
|
|
149
|
-
return
|
152
|
+
return action if action
|
150
153
|
end
|
151
154
|
end
|
152
155
|
end
|
@@ -8,11 +8,11 @@ class MessageRouter
|
|
8
8
|
#
|
9
9
|
# prerequisite :db_connected?
|
10
10
|
#
|
11
|
-
# match SomeOtherRouter
|
11
|
+
# match SomeOtherRouter
|
12
12
|
# # `mount` is an alias of `match`
|
13
|
-
# mount AnotherRouter
|
13
|
+
# mount AnotherRouter
|
14
14
|
#
|
15
|
-
# match(
|
15
|
+
# match(lambda { env['from'].nil? }) do
|
16
16
|
# Logger.error "Can't reply when when don't know who a message is from: #{env.inspect}"
|
17
17
|
# end
|
18
18
|
#
|
@@ -40,13 +40,13 @@ class MessageRouter
|
|
40
40
|
# send_reply "Sorry, you are trying to use a deprecated short code. Please try again.", env
|
41
41
|
# end
|
42
42
|
#
|
43
|
-
# match :user_name => PriorityUsernameRouter
|
44
|
-
# match :user_name, OldStyleUsernameRouter
|
43
|
+
# match :user_name => PriorityUsernameRouter
|
44
|
+
# match :user_name, OldStyleUsernameRouter
|
45
45
|
# match :user_name do
|
46
46
|
# send_reply "I found you! Your name is #{user_name}.", env
|
47
47
|
# end
|
48
48
|
#
|
49
|
-
# match %w(stop end quit), StopRouter
|
49
|
+
# match %w(stop end quit), StopRouter
|
50
50
|
#
|
51
51
|
# # Array elements don't need to be the same type
|
52
52
|
# match [
|
@@ -54,7 +54,7 @@ class MessageRouter
|
|
54
54
|
# {'to' => %w(12345 54321)},
|
55
55
|
# {'RAILS_ENV' => 'test'},
|
56
56
|
# 'test'
|
57
|
-
# ], TestRouter
|
57
|
+
# ], TestRouter
|
58
58
|
#
|
59
59
|
# # Works inside a Hash too
|
60
60
|
# match 'from' => ['12345', '54321', /111\d\d/] do
|
@@ -80,7 +80,7 @@ class MessageRouter
|
|
80
80
|
# end
|
81
81
|
# end
|
82
82
|
#
|
83
|
-
# router = MyApp::Router::Application
|
83
|
+
# router = MyApp::Router::Application
|
84
84
|
# router.call({}) # Logs an error about not knowing who the message is from
|
85
85
|
# router.call({'from' => 'mr-smith', 'body' => 'ping'}) # Sends a 'pong' reply
|
86
86
|
# router.call({'from' => 'mr-smith', 'to' => 12345}) # Sends a deprecation warning reply
|
@@ -149,28 +149,31 @@ class MessageRouter
|
|
149
149
|
when 0
|
150
150
|
raise ArgumentError, "You must provide either a block or an argument which responds to call."
|
151
151
|
when 1
|
152
|
-
if args[0].respond_to?(:
|
153
|
-
|
154
|
-
|
152
|
+
if args[0].respond_to?(:env)
|
153
|
+
condition = true
|
154
|
+
action = args[0]
|
155
|
+
elsif args[0].respond_to?(:call)
|
156
|
+
condition = true
|
157
|
+
action = args[0]
|
155
158
|
elsif args[0].kind_of?(Hash) && args[0].values.size == 1 && args[0].values[0].respond_to?(:call)
|
156
159
|
# Syntactical suger to make:
|
157
|
-
# match :cool? => OnlyForCoolPeopleRouter
|
160
|
+
# match :cool? => OnlyForCoolPeopleRouter
|
158
161
|
# work just like:
|
159
|
-
# match :cool?, OnlyForCoolPeopleRouter
|
160
|
-
|
161
|
-
|
162
|
+
# match :cool?, OnlyForCoolPeopleRouter
|
163
|
+
condition = args[0].keys[0]
|
164
|
+
action = args[0].values[0]
|
162
165
|
else
|
163
166
|
raise ArgumentError, "You must provide either a block or a 2nd argument which responds to call."
|
164
167
|
end
|
165
168
|
when 2
|
166
|
-
|
167
|
-
raise ArgumentError, "The 2nd argument must respond to call." unless
|
169
|
+
condition, action = args
|
170
|
+
raise ArgumentError, "The 2nd argument must respond to call." unless action.respond_to?(:call)
|
168
171
|
else
|
169
172
|
raise ArgumentError, "Too many arguments. Note: you may not provide a block when a 2nd argument has been provided."
|
170
173
|
end
|
171
174
|
|
172
175
|
# Save the arguments for later.
|
173
|
-
rules << [
|
176
|
+
rules << [condition, action]
|
174
177
|
end
|
175
178
|
alias :mount :match
|
176
179
|
|
@@ -193,13 +196,34 @@ class MessageRouter
|
|
193
196
|
def prerequisites
|
194
197
|
@prerequisites ||= []
|
195
198
|
end
|
199
|
+
|
200
|
+
# Kicks off the router. 'env' is a Hash. The keys are up to the user;
|
201
|
+
# however, the default key (used when a matcher is just a String or Regexp)
|
202
|
+
# is 'body'. If you don't specify this key, then String and Regexp matchers
|
203
|
+
# will always be false.
|
204
|
+
# Returns a new instance of this class, that gets run before being returned
|
205
|
+
# A rule "matches" if its condition return true and the action does not
|
206
|
+
# explicitly call not_matched. For example:
|
207
|
+
# match(true) { }
|
208
|
+
# matches. However:
|
209
|
+
# match(true) { not_matched }
|
210
|
+
# does not count as a match. This allows us to mount sub-routers and
|
211
|
+
# continue trying other rules if those subrouters fail to match something.
|
212
|
+
def call(env)
|
213
|
+
new(env).run
|
214
|
+
end
|
196
215
|
end
|
197
216
|
|
198
217
|
|
199
218
|
# This method initializes all the rules stored at the class level. When you
|
200
219
|
# create your subclass, if you want to add your own initializer, it is very
|
201
220
|
# important to call `super` or none of your rules will be matched.
|
202
|
-
def initialize
|
221
|
+
def initialize(env) #:nodoc:
|
222
|
+
@env = env.dup
|
223
|
+
# a parent router may be assuming a successful match
|
224
|
+
# but this subrouter may not, so we explicitly set it to not matched
|
225
|
+
# on creation
|
226
|
+
not_matched
|
203
227
|
@rules = []
|
204
228
|
# Actually create the rules so that the procs we create are in the
|
205
229
|
# context of an instance of this object. This is most important when the
|
@@ -209,100 +233,96 @@ class MessageRouter
|
|
209
233
|
self.class.rules.each {|rule| match *rule }
|
210
234
|
|
211
235
|
@prerequisites = []
|
212
|
-
self.class.prerequisites.each
|
236
|
+
self.class.prerequisites.each do |prerequisite|
|
237
|
+
@prerequisites << normalize_match_params(prerequisite)
|
238
|
+
end
|
213
239
|
end
|
214
240
|
|
215
|
-
|
216
|
-
# however, the default key (used when a matcher is just a String or Regexp)
|
217
|
-
# is 'body'. If you don't specify this key, then String and Regexp matchers
|
218
|
-
# will always be false.
|
219
|
-
# Returns nil if no rules match
|
220
|
-
# Returns true if a rule matches
|
221
|
-
# A rule "matches" if both its procs return true. For example:
|
222
|
-
# match(true) { true }
|
223
|
-
# matches. However:
|
224
|
-
# match(true) { false }
|
225
|
-
# does not count as a match. This allows us to mount sub-routers and
|
226
|
-
# continue trying other rules if those subrouters fail to match something.
|
227
|
-
# However, this does mean you need to be careful when writing the 2nd
|
228
|
-
# argument to #match. If you return nil or false, the router will keep
|
229
|
-
# looking for another match.
|
230
|
-
def call(env)
|
231
|
-
# I'm pretty sure this is NOT thread safe. Having two threads use the
|
232
|
-
# same router at the same time will almost certainly give you VERY weird
|
233
|
-
# and incorrect results. We may want to introduce a RouterRun object to
|
234
|
-
# encapsulate one invocation of this #call method.
|
235
|
-
@env = env
|
236
|
-
|
241
|
+
def run #:nodoc:
|
237
242
|
# All prerequisites must return true in order to continue.
|
238
|
-
return
|
239
|
-
|
240
|
-
self.instance_eval &should_i
|
241
|
-
else
|
242
|
-
should_i.call @env
|
243
|
-
end
|
243
|
+
return self unless @prerequisites.all? do |condition|
|
244
|
+
self.instance_eval &condition
|
244
245
|
end
|
245
246
|
|
246
|
-
@rules.detect do |
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
247
|
+
@rules.detect do |condition, action|
|
248
|
+
if self.instance_eval &condition
|
249
|
+
matched
|
250
|
+
r = self.instance_eval &action
|
251
|
+
@env = r.respond_to?(:env) ? r.env : r
|
252
|
+
return self if matched?
|
251
253
|
end
|
254
|
+
end
|
252
255
|
|
253
|
-
|
254
|
-
|
255
|
-
self.instance_eval &do_this
|
256
|
-
else
|
257
|
-
do_this.call @env
|
258
|
-
end
|
256
|
+
self # always return router instance
|
257
|
+
end
|
259
258
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
259
|
+
def not_matched
|
260
|
+
env['_matched'] = false
|
261
|
+
end
|
262
|
+
def matched
|
263
|
+
env['_matched'] = true
|
264
|
+
end
|
265
|
+
def matched?
|
266
|
+
!!env['_matched']
|
265
267
|
end
|
266
268
|
|
267
269
|
|
268
|
-
private
|
269
270
|
def env; @env; end
|
271
|
+
private
|
270
272
|
|
271
|
-
def match(
|
272
|
-
@rules << [normalize_match_params(
|
273
|
+
def match(condition, action)
|
274
|
+
@rules << [normalize_match_params(condition), normalize_action(action)]
|
275
|
+
end
|
276
|
+
|
277
|
+
def normalize_action(action)
|
278
|
+
if action.kind_of?(Proc) # This is true for blocks and lamdas too.
|
279
|
+
Proc.new do
|
280
|
+
self.instance_eval &action
|
281
|
+
env
|
282
|
+
end
|
283
|
+
else
|
284
|
+
Proc.new do
|
285
|
+
action.call(env)
|
286
|
+
end
|
287
|
+
end
|
273
288
|
end
|
274
289
|
|
275
|
-
def normalize_match_params(
|
276
|
-
|
290
|
+
def normalize_match_params(condition=nil, &block)
|
291
|
+
condition ||= block if block
|
277
292
|
|
278
|
-
case
|
293
|
+
case condition
|
279
294
|
when Regexp, String
|
280
|
-
Proc.new { attr_matches? default_attribute,
|
295
|
+
Proc.new { attr_matches? default_attribute, condition }
|
281
296
|
|
282
297
|
when TrueClass, FalseClass, NilClass
|
283
|
-
Proc.new {
|
298
|
+
Proc.new { condition }
|
284
299
|
|
285
300
|
when Symbol
|
286
301
|
Proc.new do
|
287
|
-
self.send
|
302
|
+
self.send condition
|
288
303
|
end
|
289
304
|
|
290
305
|
when Array
|
291
|
-
|
306
|
+
condition = condition.map {|x| normalize_match_params x}
|
292
307
|
Proc.new do
|
293
|
-
|
308
|
+
condition.any? { |x| x.call env }
|
294
309
|
end
|
295
310
|
|
296
311
|
when Hash
|
297
312
|
Proc.new do
|
298
|
-
|
313
|
+
condition.all? do |key, val|
|
299
314
|
attr_matches? env[key], val
|
300
315
|
end
|
301
316
|
end
|
302
317
|
|
318
|
+
when Proc
|
319
|
+
condition
|
320
|
+
|
303
321
|
else
|
304
322
|
# Assume it already responds to #call.
|
305
|
-
|
323
|
+
Proc.new do
|
324
|
+
condition.call env
|
325
|
+
end
|
306
326
|
end
|
307
327
|
end
|
308
328
|
|
data/message_router.gemspec
CHANGED
@@ -5,8 +5,8 @@ require "message_router/version"
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "message_router"
|
7
7
|
s.version = MessageRouter::VERSION
|
8
|
-
s.authors = ["Brad Gessler", "Paul Cortens"]
|
9
|
-
s.email = ["brad@bradgessler.com", "paul@thoughtless.ca"]
|
8
|
+
s.authors = ["Brad Gessler", "Paul Cortens", "Christopher Bertels"]
|
9
|
+
s.email = ["brad@bradgessler.com", "paul@thoughtless.ca", "bakkdoor@flasht.de"]
|
10
10
|
s.homepage = ""
|
11
11
|
s.summary = %q{Route messages}
|
12
12
|
s.description = %q{a DSL for routing SMS, Twitter, and other short message formats.}
|
data/spec/message_router_spec.rb
CHANGED
@@ -5,11 +5,6 @@ describe MessageRouter::Router do
|
|
5
5
|
|
6
6
|
describe 'defining matchers' do
|
7
7
|
describe '1st argument' do
|
8
|
-
before do
|
9
|
-
# For use in confirming whether or not a proc was called.
|
10
|
-
$thing_to_match = $did_it_run = nil
|
11
|
-
end
|
12
|
-
|
13
8
|
let :env do
|
14
9
|
{
|
15
10
|
'body' => 'hello world',
|
@@ -19,10 +14,10 @@ describe MessageRouter::Router do
|
|
19
14
|
end
|
20
15
|
|
21
16
|
# This needs to be a method (and not memoized by #let) so that
|
22
|
-
#
|
23
|
-
def router
|
17
|
+
# thing_to_match can change within a test.
|
18
|
+
def router(thing_to_match)
|
24
19
|
Class.new MessageRouter::Router do
|
25
|
-
match(
|
20
|
+
match(thing_to_match) { env['did_it_run'] = true }
|
26
21
|
|
27
22
|
# Using these methods also proves that the message is optionally
|
28
23
|
# passed to helper methods.
|
@@ -32,20 +27,16 @@ describe MessageRouter::Router do
|
|
32
27
|
def always_false
|
33
28
|
false
|
34
29
|
end
|
35
|
-
end
|
30
|
+
end
|
36
31
|
end
|
37
32
|
|
38
33
|
let :the_test do
|
39
34
|
Proc.new do |opts|
|
40
|
-
|
41
|
-
|
42
|
-
$did_it_run.should == true
|
43
|
-
$did_it_run = nil # reset for next time
|
35
|
+
r = router(opts[:true]).call(env.dup)
|
36
|
+
expect(r.env['did_it_run']).to eq true
|
44
37
|
|
45
|
-
|
46
|
-
|
47
|
-
$did_it_run.should == nil
|
48
|
-
$did_it_run = nil # reset for next time
|
38
|
+
r = router(opts[:false]).call(env.dup)
|
39
|
+
expect(r.env['did_it_run']).to eq nil
|
49
40
|
end
|
50
41
|
end
|
51
42
|
|
@@ -82,27 +73,27 @@ describe MessageRouter::Router do
|
|
82
73
|
def default_attribute
|
83
74
|
env['tacos']
|
84
75
|
end
|
85
|
-
end
|
76
|
+
end
|
86
77
|
end
|
87
78
|
|
88
79
|
it 'accepts a string to match against the 1st word in the default attribute' do
|
89
|
-
|
90
|
-
|
91
|
-
env['result'].
|
80
|
+
r = router.call({ 'tacos' => 'cheese please' })
|
81
|
+
expect(r.matched?).to be_truthy
|
82
|
+
expect(r.env['result']).to eq 'i found cheese'
|
92
83
|
end
|
93
84
|
it "does not match strings against the 'body' attribute" do
|
94
|
-
|
95
|
-
|
85
|
+
r = router.call({ 'body' => 'cheese please' })
|
86
|
+
expect(r.matched?).to be_falsey
|
96
87
|
end
|
97
88
|
|
98
89
|
it 'accepts a regex to match against the default attribute' do
|
99
|
-
|
100
|
-
|
101
|
-
env['result'].
|
90
|
+
r = router.call({ 'tacos' => 'i like beans a lot' })
|
91
|
+
expect(r.matched?).to be_truthy
|
92
|
+
expect(r.env['result']).to eq 'magical fruit'
|
102
93
|
end
|
103
94
|
it "does not match regex against the 'body' attribute" do
|
104
|
-
|
105
|
-
|
95
|
+
r = router.call({ 'body' => 'i like beans a lot' })
|
96
|
+
expect(r.matched?).to be_falsey
|
106
97
|
end
|
107
98
|
end
|
108
99
|
|
@@ -115,31 +106,18 @@ describe MessageRouter::Router do
|
|
115
106
|
end
|
116
107
|
|
117
108
|
describe 'matching an Array' do
|
118
|
-
it "doesn't run the '
|
119
|
-
|
120
|
-
|
121
|
-
match [true, true] do
|
122
|
-
$run_count += 1
|
123
|
-
nil # Return nil to ensure this matcher failed.
|
124
|
-
end
|
125
|
-
end.new
|
126
|
-
|
127
|
-
router.call({})
|
128
|
-
$run_count.should == 1
|
129
|
-
end
|
130
|
-
|
131
|
-
it "returns nil if the 'do_this' block returns nil" do
|
132
|
-
$run_count = 0
|
109
|
+
it "doesn't run the 'action' block multiple times if there are multiple matches" do
|
110
|
+
run = double
|
111
|
+
expect(run).to receive(:count).once
|
133
112
|
router = Class.new(MessageRouter::Router) do
|
134
113
|
match [true, true] do
|
135
|
-
|
136
|
-
|
114
|
+
run.count
|
115
|
+
not_matched
|
137
116
|
end
|
138
|
-
end
|
139
|
-
|
140
|
-
|
117
|
+
end
|
118
|
+
r = router.call({})
|
119
|
+
expect(r.matched?).to be_falsey
|
141
120
|
end
|
142
|
-
|
143
121
|
end
|
144
122
|
|
145
123
|
describe 'matching a hash' do
|
@@ -181,10 +159,8 @@ describe MessageRouter::Router do
|
|
181
159
|
end
|
182
160
|
|
183
161
|
it 'accepts keys that are missing (but is always false)' do
|
184
|
-
|
185
|
-
|
186
|
-
$did_it_run.should == nil
|
187
|
-
$did_it_run = nil # reset for next time
|
162
|
+
r = router({'i dont exist' => /.*/}).call(env)
|
163
|
+
expect(r.env['did_it_run']).to eq nil
|
188
164
|
end
|
189
165
|
end
|
190
166
|
end
|
@@ -194,34 +170,34 @@ describe MessageRouter::Router do
|
|
194
170
|
env = {}
|
195
171
|
router = Class.new MessageRouter::Router do
|
196
172
|
match(true, Proc.new { env['did_it_run'] = true })
|
197
|
-
end
|
173
|
+
end
|
198
174
|
router.call env
|
199
|
-
env['did_it_run'].
|
175
|
+
expect(env['did_it_run']).to be_truthy
|
200
176
|
end
|
201
177
|
|
202
178
|
it 'accepts a block' do
|
203
179
|
env = {}
|
204
180
|
router = Class.new MessageRouter::Router do
|
205
181
|
match(true) { env['did_it_run'] = true }
|
206
|
-
end
|
182
|
+
end
|
207
183
|
router.call env
|
208
|
-
env['did_it_run'].
|
184
|
+
expect(env['did_it_run']).to be_truthy
|
209
185
|
end
|
210
186
|
|
211
187
|
it 'raises an execption when both a Proc and a block are given' do
|
212
|
-
|
188
|
+
expect {
|
213
189
|
router = Class.new MessageRouter::Router do
|
214
190
|
match(true, Proc.new { env['did_it_run'] = true }) { env['did_it_run'] = true }
|
215
|
-
end
|
216
|
-
}.
|
191
|
+
end
|
192
|
+
}.to raise_error(ArgumentError)
|
217
193
|
end
|
218
194
|
|
219
195
|
it 'raises an execption when neither a Proc nor a block are given' do
|
220
|
-
|
196
|
+
expect {
|
221
197
|
router = Class.new MessageRouter::Router do
|
222
198
|
match true
|
223
|
-
end
|
224
|
-
}.
|
199
|
+
end
|
200
|
+
}.to raise_error(ArgumentError)
|
225
201
|
end
|
226
202
|
end
|
227
203
|
|
@@ -229,18 +205,18 @@ describe MessageRouter::Router do
|
|
229
205
|
env = {}
|
230
206
|
router = Class.new MessageRouter::Router do
|
231
207
|
match { env['did_it_run'] = true }
|
232
|
-
end
|
208
|
+
end
|
233
209
|
router.call env
|
234
|
-
env['did_it_run'].
|
210
|
+
expect(env['did_it_run']).to be_truthy
|
235
211
|
end
|
236
212
|
|
237
213
|
it 'defaults the 1st argument to true if only a Proc is given' do
|
238
214
|
env = {}
|
239
215
|
router = Class.new MessageRouter::Router do
|
240
216
|
match(Proc.new { env['did_it_run'] = true })
|
241
|
-
end
|
217
|
+
end
|
242
218
|
router.call env
|
243
|
-
env['did_it_run'].
|
219
|
+
expect(env['did_it_run']).to be_truthy
|
244
220
|
end
|
245
221
|
|
246
222
|
it 'accepts a Hash with a symbol as its only key and a Proc as its only value' do
|
@@ -248,41 +224,41 @@ describe MessageRouter::Router do
|
|
248
224
|
router = Class.new MessageRouter::Router do
|
249
225
|
match :true_method => (Proc.new { env['did_it_run'] = true })
|
250
226
|
def true_method; true; end
|
251
|
-
end
|
227
|
+
end
|
252
228
|
router.call env
|
253
|
-
env['did_it_run'].
|
229
|
+
expect(env['did_it_run']).to be_truthy
|
254
230
|
end
|
255
231
|
|
256
232
|
it 'raises an execption when no arguments and no block is given' do
|
257
|
-
|
233
|
+
expect {
|
258
234
|
router = Class.new MessageRouter::Router do
|
259
235
|
match
|
260
|
-
end
|
261
|
-
}.
|
236
|
+
end
|
237
|
+
}.to raise_error(ArgumentError)
|
262
238
|
end
|
263
239
|
end
|
264
240
|
|
265
241
|
|
266
242
|
describe "#call" do
|
267
|
-
it "
|
268
|
-
|
269
|
-
|
243
|
+
it "does not match with no rules" do
|
244
|
+
router = MessageRouter::Router.call({})
|
245
|
+
expect(router.matched?).to be_falsey
|
270
246
|
end
|
271
247
|
|
272
248
|
context 'a rule matches' do
|
273
249
|
subject do
|
274
250
|
Class.new MessageRouter::Router do
|
275
251
|
match(true) { env[:did_it_run] = true }
|
276
|
-
end
|
252
|
+
end
|
277
253
|
end
|
278
254
|
|
279
255
|
it "returns true" do
|
280
|
-
subject.call({}).
|
256
|
+
expect(subject.call({})).to be_truthy
|
281
257
|
end
|
282
258
|
|
283
259
|
it "calls the matcher's code" do
|
284
|
-
subject.call(env = {})
|
285
|
-
env[:did_it_run].
|
260
|
+
r = subject.call(env = {})
|
261
|
+
expect(r.env[:did_it_run]).to be_truthy
|
286
262
|
end
|
287
263
|
end
|
288
264
|
|
@@ -292,16 +268,16 @@ describe MessageRouter::Router do
|
|
292
268
|
prerequisite :true_method
|
293
269
|
match(true) { env[:did_it_run] = true }
|
294
270
|
def true_method; true; end
|
295
|
-
end
|
271
|
+
end
|
296
272
|
end
|
297
273
|
|
298
|
-
it "
|
299
|
-
subject.call({}).
|
274
|
+
it "matches" do
|
275
|
+
expect(subject.call({}).matched?).to be_truthy
|
300
276
|
end
|
301
277
|
|
302
278
|
it "calls the matcher's code" do
|
303
|
-
subject.call(env = {})
|
304
|
-
env[:did_it_run].
|
279
|
+
r = subject.call(env = {})
|
280
|
+
expect(r.env[:did_it_run]).to be_truthy
|
305
281
|
end
|
306
282
|
end
|
307
283
|
|
@@ -311,112 +287,126 @@ describe MessageRouter::Router do
|
|
311
287
|
prerequisite :false_method
|
312
288
|
match(true) { env[:did_it_run] = true }
|
313
289
|
def false_method; false; end
|
314
|
-
end
|
290
|
+
end
|
315
291
|
end
|
316
292
|
|
317
|
-
it "
|
318
|
-
subject.call({}).
|
293
|
+
it "doesn't match" do
|
294
|
+
expect(subject.call({}).matched?).to be_falsey
|
319
295
|
end
|
320
296
|
|
321
297
|
it "doesn't calls the matcher's code" do
|
322
298
|
subject.call(env = {})
|
323
|
-
env[:did_it_run].
|
299
|
+
expect(env[:did_it_run]).to_not be_truthy
|
324
300
|
end
|
325
301
|
end
|
326
302
|
|
327
|
-
describe '
|
328
|
-
|
303
|
+
describe 'mount routers' do
|
304
|
+
it "can delegate to other routers" do
|
305
|
+
sub_router = Class.new(MessageRouter::Router) do
|
306
|
+
match do
|
307
|
+
env['result'] = true
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
main_router = Class.new(MessageRouter::Router) do
|
312
|
+
mount sub_router
|
313
|
+
end
|
314
|
+
|
315
|
+
r = main_router.call({})
|
316
|
+
expect(r.env['result']).to eq true
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
describe "explicitly not matching" do
|
321
|
+
let(:router) do
|
329
322
|
Class.new(MessageRouter::Router) do
|
330
|
-
|
331
|
-
|
332
|
-
end
|
323
|
+
match do
|
324
|
+
not_matched
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|
333
328
|
|
334
|
-
|
335
|
-
|
336
|
-
|
329
|
+
it "sets matched to false in env" do
|
330
|
+
r = router.call({})
|
331
|
+
expect(r.matched?).to be_falsey
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
describe "explicitly matching" do
|
336
|
+
let(:router) do
|
337
|
+
Class.new(MessageRouter::Router) do
|
338
|
+
match do
|
339
|
+
not_matched
|
337
340
|
end
|
338
|
-
|
341
|
+
match do
|
342
|
+
matched
|
343
|
+
end
|
344
|
+
end
|
339
345
|
end
|
340
346
|
|
341
|
-
|
342
|
-
|
347
|
+
it "sets matched to true in env" do
|
348
|
+
r = router.call({})
|
349
|
+
expect(r.matched?).to be_truthy
|
343
350
|
end
|
351
|
+
end
|
344
352
|
|
345
|
-
|
346
|
-
|
353
|
+
describe 'nested routers' do
|
354
|
+
def main_router(matcher_opts = {})
|
355
|
+
Class.new(MessageRouter::Router) do
|
356
|
+
sub_router = Class.new(MessageRouter::Router) do
|
357
|
+
match { not_matched; env['did_outer_run'] = true }
|
358
|
+
match(matcher_opts[:inner]) { env['did_inner_run'] = true }
|
359
|
+
end
|
347
360
|
|
348
|
-
|
349
|
-
|
350
|
-
$did_inner_run.should be_true
|
361
|
+
match matcher_opts[:outer] => sub_router
|
362
|
+
end
|
351
363
|
end
|
352
364
|
|
353
|
-
it
|
354
|
-
|
355
|
-
|
365
|
+
it 'runs both when both match' do
|
366
|
+
r = main_router(:outer => true, :inner => true).call({})
|
367
|
+
expect(r.env['did_outer_run']).to be_truthy
|
368
|
+
expect(r.env['did_inner_run']).to be_truthy
|
369
|
+
end
|
356
370
|
|
357
|
-
|
358
|
-
|
359
|
-
|
371
|
+
it "runs outer only when outer matches and inner doesn't" do
|
372
|
+
r = main_router(:outer => true, :inner => false).call({})
|
373
|
+
expect(r.env['did_outer_run']).to be_truthy
|
374
|
+
expect(r.env['did_inner_run']).to be_nil
|
360
375
|
end
|
361
376
|
|
362
377
|
it "runs neither when inner matches and outer doesn't" do
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
main_router.call({}).should be_nil
|
367
|
-
$did_outer_run.should be_nil
|
368
|
-
$did_inner_run.should be_nil
|
378
|
+
r = main_router(:outer => false, :inner => true).call({})
|
379
|
+
expect(r.env['did_outer_run']).to be_nil
|
380
|
+
expect(r.env['did_inner_run']).to be_nil
|
369
381
|
end
|
370
382
|
|
371
383
|
context 'multiple inner matchers' do
|
372
|
-
|
373
|
-
$outer_matcher_1 = $outer_matcher_2 = $inner_matcher_1 = $inner_matcher_2 = $did_outer_run_1 = $did_outer_run_2 = $did_inner_run_1 = $did_inner_run_2 = nil
|
374
|
-
end
|
375
|
-
|
376
|
-
def main_router
|
384
|
+
def main_router(inner_matcher_1)
|
377
385
|
Class.new MessageRouter::Router do
|
378
386
|
# Define them
|
379
387
|
sub_router_1 = Class.new MessageRouter::Router do
|
380
|
-
match(
|
381
|
-
end
|
388
|
+
match(inner_matcher_1) { env['did_inner_run_1'] = true }
|
389
|
+
end
|
382
390
|
sub_router_2 = Class.new MessageRouter::Router do
|
383
|
-
match(
|
384
|
-
end.new
|
385
|
-
|
386
|
-
# 'mount' them
|
387
|
-
match $outer_matcher_1 do
|
388
|
-
$did_outer_run_1 = true
|
389
|
-
sub_router_1.call(env)
|
391
|
+
match(true) { env['did_inner_run_2'] = true }
|
390
392
|
end
|
391
393
|
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
end
|
396
|
-
end.new
|
394
|
+
mount sub_router_1
|
395
|
+
mount sub_router_2
|
396
|
+
end
|
397
397
|
end
|
398
398
|
|
399
399
|
it "runs only 1st outer and 1st inner when all match" do
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
$did_outer_run_1.should be_true
|
404
|
-
$did_outer_run_2.should be_nil
|
405
|
-
$did_inner_run_1.should be_true
|
406
|
-
$did_inner_run_2.should be_nil
|
400
|
+
r = main_router(true).call({})
|
401
|
+
expect(r.env['did_inner_run_1']).to eq true
|
402
|
+
expect(r.env['did_inner_run_2']).to eq nil
|
407
403
|
end
|
408
404
|
|
409
405
|
it "runs both outers, and 2nd inner when all but 1st inner match" do
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
main_router.call({}).should be_true
|
414
|
-
$did_outer_run_1.should be_true
|
415
|
-
$did_outer_run_2.should be_true
|
416
|
-
$did_inner_run_1.should be_nil
|
417
|
-
$did_inner_run_2.should be_true
|
406
|
+
r = main_router(false).call({})
|
407
|
+
expect(r.env['did_inner_run_1']).to be_nil
|
408
|
+
expect(r.env['did_inner_run_2']).to be_truthy
|
418
409
|
end
|
419
|
-
|
420
410
|
end
|
421
411
|
end
|
422
412
|
|
@@ -437,7 +427,7 @@ describe MessageRouter::Router do
|
|
437
427
|
Class.new MessageRouter::Router do
|
438
428
|
include MyTestHelper
|
439
429
|
match :lookup_human_name do
|
440
|
-
|
430
|
+
env['is_john'] = env['human_name'] == 'John'
|
441
431
|
end
|
442
432
|
|
443
433
|
match 'run_a' => 'block' do
|
@@ -448,7 +438,7 @@ describe MessageRouter::Router do
|
|
448
438
|
env['id'] = 2
|
449
439
|
env['the_name'] = lookup_human_name
|
450
440
|
end)
|
451
|
-
match({'run_a' => 'lambda'}, lambda do
|
441
|
+
match({'run_a' => 'lambda'}, lambda do |args|
|
452
442
|
env['id'] = 2
|
453
443
|
env['the_name'] = lookup_human_name
|
454
444
|
end)
|
@@ -459,34 +449,53 @@ describe MessageRouter::Router do
|
|
459
449
|
lookup_human_name
|
460
450
|
end
|
461
451
|
) { true }
|
462
|
-
end
|
452
|
+
end
|
463
453
|
end
|
464
454
|
|
465
455
|
it 'can access/modify the env via #env' do
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
env['human_name'].
|
470
|
-
end
|
471
|
-
|
472
|
-
it '#env is reset after #call has finished' do
|
473
|
-
router.call({'id' => 1}).should be_true
|
474
|
-
router.send(:env).should be_nil
|
456
|
+
r = router.call({'id' => 1})
|
457
|
+
expect(r.matched?).to be_truthy
|
458
|
+
expect(r.env['is_john']).to be_truthy # Prove the inner matcher can see the new value
|
459
|
+
expect(r.env['human_name']).to eq 'John' # Prove we can get at the value after the router has finished.
|
475
460
|
end
|
476
461
|
|
477
462
|
%w(block proc lambda).each do |type|
|
478
463
|
it "can be accessed from a #{type} that is the 2nd argument" do
|
479
|
-
|
480
|
-
|
481
|
-
env['the_name'].
|
464
|
+
r = router.call({'run_a' => type})
|
465
|
+
expect(r.matched?).to be_truthy
|
466
|
+
expect(r.env['the_name']).to eq 'Jim'
|
482
467
|
end
|
483
468
|
end
|
484
469
|
|
485
470
|
%w(proc lambda).each do |type|
|
486
471
|
it "can be accessed from a #{type} that is the 1st argument" do
|
487
|
-
|
488
|
-
|
489
|
-
env['human_name'].
|
472
|
+
r = router.call({'match_with' => type})
|
473
|
+
expect(r.matched?).to be_truthy
|
474
|
+
expect(r.env['human_name']).to eq 'Jules'
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
describe "instance variables" do
|
479
|
+
let :router do
|
480
|
+
Class.new MessageRouter::Router do
|
481
|
+
prerequisite :helper_method
|
482
|
+
|
483
|
+
match do
|
484
|
+
env['result'] = @helper_method
|
485
|
+
end
|
486
|
+
|
487
|
+
private
|
488
|
+
def helper_method
|
489
|
+
@helper_method ||= 0
|
490
|
+
@helper_method += 1
|
491
|
+
end
|
492
|
+
end
|
493
|
+
end
|
494
|
+
|
495
|
+
it "doesn't leak state to a 2nd run" do
|
496
|
+
router.call({})
|
497
|
+
r = router.call({})
|
498
|
+
expect(r.env['result']).to eq 1
|
490
499
|
end
|
491
500
|
end
|
492
501
|
end
|
metadata
CHANGED
@@ -1,37 +1,29 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: message_router
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 1
|
9
|
-
- 3
|
10
|
-
version: 0.1.3
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.0
|
11
5
|
platform: ruby
|
12
|
-
authors:
|
6
|
+
authors:
|
13
7
|
- Brad Gessler
|
14
8
|
- Paul Cortens
|
9
|
+
- Christopher Bertels
|
15
10
|
autorequire:
|
16
11
|
bindir: bin
|
17
12
|
cert_chain: []
|
18
|
-
|
19
|
-
date: 2012-09-10 00:00:00 Z
|
13
|
+
date: 2014-10-21 00:00:00.000000000 Z
|
20
14
|
dependencies: []
|
21
|
-
|
22
15
|
description: a DSL for routing SMS, Twitter, and other short message formats.
|
23
|
-
email:
|
16
|
+
email:
|
24
17
|
- brad@bradgessler.com
|
25
18
|
- paul@thoughtless.ca
|
19
|
+
- bakkdoor@flasht.de
|
26
20
|
executables: []
|
27
|
-
|
28
21
|
extensions: []
|
29
|
-
|
30
22
|
extra_rdoc_files: []
|
31
|
-
|
32
|
-
|
33
|
-
- .
|
34
|
-
- .
|
23
|
+
files:
|
24
|
+
- ".gitignore"
|
25
|
+
- ".ruby-version"
|
26
|
+
- ".travis.yml"
|
35
27
|
- Gemfile
|
36
28
|
- Gemfile.lock
|
37
29
|
- Guardfile
|
@@ -45,38 +37,30 @@ files:
|
|
45
37
|
- spec/message_router_spec.rb
|
46
38
|
- spec/spec.opts
|
47
39
|
- spec/spec_helper.rb
|
48
|
-
homepage:
|
40
|
+
homepage: ''
|
49
41
|
licenses: []
|
50
|
-
|
42
|
+
metadata: {}
|
51
43
|
post_install_message:
|
52
44
|
rdoc_options: []
|
53
|
-
|
54
|
-
require_paths:
|
45
|
+
require_paths:
|
55
46
|
- lib
|
56
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
-
|
58
|
-
requirements:
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
59
49
|
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
version: "0"
|
65
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
|
-
requirements:
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
68
54
|
- - ">="
|
69
|
-
- !ruby/object:Gem::Version
|
70
|
-
|
71
|
-
segments:
|
72
|
-
- 0
|
73
|
-
version: "0"
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
74
57
|
requirements: []
|
75
|
-
|
76
58
|
rubyforge_project: message_router
|
77
|
-
rubygems_version:
|
59
|
+
rubygems_version: 2.2.2
|
78
60
|
signing_key:
|
79
|
-
specification_version:
|
61
|
+
specification_version: 4
|
80
62
|
summary: Route messages
|
81
|
-
test_files:
|
82
|
-
|
63
|
+
test_files:
|
64
|
+
- spec/message_router_spec.rb
|
65
|
+
- spec/spec.opts
|
66
|
+
- spec/spec_helper.rb
|
data/.rvmrc
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rvm use --install ree
|