bhauman-twroute 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,13 +1,432 @@
1
1
  = Twroute - Route Twitter status updates over http to your web app
2
2
 
3
+ Twroute uses the {Twitter Stream API}[http://apiwiki.twitter.com/Streaming-API-Documentation]
4
+ to watch status updates and convert them to HTTP post requests.
5
+
6
+ Twoute uses {Delayed Job}[http://github.com/tobi/delayed_job/tree/master]
7
+ as a message queue ensuring that http requests are retried if the
8
+ targeted web app is out of service for a bit.
9
+
3
10
  As a Rails developer the motivation to write this gem is because
4
11
  I wanted a super simple way to write a twitter app where my app
5
12
  can recieve messages from twitter over http and respond to the sender
6
- over http.
13
+ by simply responding to the http request. [Not implemented yet]
14
+
15
+ In other words an ordinary Rails/Merb/Sinatra controller can recieve
16
+ a tweet and then reply to the sender by simply rendering a response.
17
+
18
+ == Install
19
+
20
+ sudo gem install bhauman-twroute
21
+
22
+ == Making your first Twroute app
23
+
24
+ Let's say we are going to create an app that rewards you for
25
+ shooting someone in the ass and reprimands you for shooting someone in
26
+ the arm, face, etc. It gives you a point for the bum shot and takes
27
+ one away for the the others.
28
+
29
+ twroute bad_shot
30
+
31
+ This will create the following directory structure:
32
+
33
+ bad_shot
34
+ |- config
35
+ config.yml # the configuration file
36
+ twroutes.rb # the routing file with sample routes
37
+ |- db # holds the sqlite3 database
38
+ |- log # holds the database log files
39
+ |- test
40
+ test_helper.rb # defines the should_route_to macro
41
+ twroutes_test.rb # sample tests for the sample routes
42
+
43
+ === App Configuration
44
+
45
+ The config.yml file has 3 sections:
46
+
47
+ ==== "Submit to" section
48
+
49
+ This is where you define the host, port and HTTP Auth inforomation for
50
+ the web app that twroute will be routing requests to.
51
+
52
+ submit_to:
53
+ host: localhost
54
+ port: 3000
55
+ # http_auth_user: ''
56
+ # http_auth_password: ''
57
+
58
+ The +port+ field is not required. Be sure to set the +host+ to the
59
+ target web app. For instance if you have a web application that lives
60
+ at +tweetrecorder+.+com+, the config would look like:
61
+
62
+ submit_to:
63
+ host: tweetrecorder.com
64
+
65
+ ==== Twitter section
66
+
67
+ This is where you specify the username and password for the twitter
68
+ account that is requesting the Twitter Stream and making the replies
69
+ to the senders.
70
+
71
+ This section also specifies which Twitter stream api to use. Most
72
+ likely +spritzer+, +follow+ or +track+ unless you are privileged.
73
+ See the {Twitter Stream API docs}[http://apiwiki.twitter.com/Streaming-API-Documentation]
74
+ for more information.
75
+
76
+ This section also describes the post query parameters that you want to
77
+ send to the twitter-api call.
78
+
79
+ The following is an example configuration if you want to see all the
80
+ tweets that have the word +shoot+ in them.
81
+
82
+ twitter:
83
+ user: example_account_name
84
+ password: example_password
85
+ stream_api: track
86
+ stream_api_args:
87
+ track: shoot
88
+
89
+ ==== Database section
90
+
91
+ This section should be ready to go as is. If you want to use MySQL
92
+ this configuration goes straight to ActiveRecord so set it up the way
93
+ you would for a Rails project. I haven't used it for MySQL so no
94
+ guarantees that it will work.
95
+
96
+ == Routing
97
+
98
+ === Testing First
99
+
100
+ We are going to use test driven development here. The system
101
+ currently uses regex's. And even the best programmers have trouble
102
+ getting regex's to work correctly.
103
+
104
+ For our example app *bad_shot* we have set of twitter updates that
105
+ we would like to map to calls to our web app.
106
+
107
+ shoot @johnboy in the ass yeah buddy => /goodshot/create
108
+ shoot @johnboy in the arm => /badshot/create
109
+ shoot @johnboy in the head => /badshot/create
110
+ shoot @johnboy in the foot => /badshot/create
111
+
112
+ Let's make these into tests first.
113
+
114
+ Open +test+/+twroutes_test+.+rb+ it will have some sample tests in
115
+ it. Delete them and replace them with these routing tests.
116
+
117
+ class TwroutesTest < Test::Unit::TestCase
118
+ should_route_to "shoot @john_Boy3 in the ass yeah buddy", "/goodshot/create"
119
+ should_route_to "shoot @john_Boy3 in the arm", "/badshot/create"
120
+ should_route_to "shoot @john_Boy3 in the head", "/badshot/create"
121
+ should_route_to "shoot @john_Boy3 in the foot", "/badshot/create"
122
+ end
123
+
124
+ Now you can run +rake+ +test+ and see all of your tests fail. But that
125
+ is a way better start than not having any tests at all.
126
+
127
+ === Writing your routes
128
+
129
+ Let's try to make some of our tests pass.
130
+
131
+ First comment out all the tests except for the first one.
132
+
133
+ class TwroutesTest < Test::Unit::TestCase
134
+ should_route_to "shoot @john_Boy3 in the ass yeah buddy", "/goodshot/create"
135
+ # should_route_to "shoot @john_Boy3 in the arm", "/badshot/create"
136
+ # should_route_to "shoot @john_Boy3 in the head", "/badshot/create"
137
+ # should_route_to "shoot @john_Boy3 in the foot", "/badshot/create"
138
+ end
139
+
140
+ We are going to only work on this one and then repeat the process for
141
+ the other routes.
142
+
143
+ Open the +config+/+twroutes.rb+ file in your editor of choice remove
144
+ or comment the exiting routes. So it should read something like this:
145
+
146
+ Twroute::Routes.draw do |map|
147
+
148
+ end
149
+
150
+ Then add this first route:
151
+
152
+ Twroute::Routes.draw do |map|
153
+ map.regex( {:whole_tweet => /shoot @john_Boy3 in the ass/},
154
+ '/goodshot/create' )
155
+ end
156
+
157
+ Then execute +rake+ +test+
158
+
159
+ You will notice that the test passed. (if not fix it). This is a good
160
+ base to start from. Now lets refine the route one step at a time.
161
+
162
+ We want to match any username so add another test in +twroutes_test.rb+:
163
+
164
+ should_route_to "shoot @john_Boy3 in the ass yeah buddy", "/goodshot/create"
165
+ should_route_to "shoot @jannie_fly5 in the ass oh yeah", "/goodshot/create"
166
+
167
+ # the rest of the tests are commented out
168
+
169
+ Now the tests should fail. Change the Regex in the route like below:
170
+
171
+ map.regex( {:whole_tweet => /shoot @[\w\d_]+ in the ass/},
172
+ '/goodshot/create' )
173
+
174
+ After each step check to see that the test passes. This should be
175
+ passing now. We decided that white space shouldn't matter so we add a
176
+ new test.
177
+
178
+ should_route_to "shoot @john_Boy3 in the ass yeah buddy", "/goodshot/create"
179
+ should_route_to "shoot @jannie_fly5 in the ass oh yeah", "/goodshot/create"
180
+ should_route_to "shoot @jannie_fly5 in the ass oh yeah", "/goodshot/create"
181
+
182
+ # the rest of the tests are commented out
183
+
184
+ Tests fail, adjust the route:
185
+
186
+ map.regex( {:whole_tweet => /shoot\s+@[\w\d_]+\s+in\s+the\s+ass/},
187
+ '/goodshot/create' )
188
+
189
+ So this is a passable route but it will match all kinds of things you
190
+ wouldn't expect like "skeetshoot @marko in the ass" so more work could
191
+ be done. Add a test:
192
+
193
+ should_route_to "shoot @john_Boy3 in the ass yeah buddy", "/goodshot/create"
194
+ should_route_to "shoot @jannie_fly5 in the ass oh yeah", "/goodshot/create"
195
+ should_route_to "shoot @jannie_fly5 in the ass oh yeah", "/goodshot/create"
196
+ should_not_route_to "skeetshoot @marko in the ass oh yeah", "/goodshot/create"
197
+
198
+ Tests fail, adjust the routes:
199
+
200
+ map.regex( {:whole_tweet => /^shoot\s+@[\w\d_]+\s+in\s+the\s+ass/},
201
+ '/goodshot/create' )
202
+
203
+ Alright you get the picture. This is the best way to go to ensure you
204
+ are picking up the right tweets. As anomalies happen add tests and
205
+ adjust the regex.
206
+
207
+ ===== How the regex matcher works.
208
+
209
+ I am going to show you an advanced route.
210
+
211
+ map.regex( { :whole_tweet => /^shoot\s+@[\w\d_]+\s+in\s+the\s+(\w+).*/,
212
+ :who_got_shot => [/^shoot\s+@([\w\d_]+)\s+/, 1]
213
+ :shot_where => [/\s+in\s+the\s+(\w+).*/, 1]
214
+ }, '/badshot/create' )
215
+
216
+ A few things are going on here. ALL the regexes defined have to be
217
+ matched. The result of the match is a hash of values. :+whole_tweet+
218
+ will be assigned the value of the whole tweet. The second match
219
+ :+who_got_shot+ has a back reference so it will only be assigned the
220
+ name of the user who was shot. The third match :+shot_where+ gets
221
+ assigned the place where the person was shot.
222
+
223
+ Now what happens to the hash of matches? Two things
224
+
225
+ 1 It gets posted along with the request as a hash named +parsed+[].
226
+ So for example in a Rails app you can refer to these parsed out goodies as
227
+
228
+ @name = params[:parsed][:who_got_shot]
229
+ @shot_where = params[:parsed][:shot_where]
230
+
231
+ 2 The keys are available as substitutions in the target URL. So in
232
+ the above example if we wanted to include some of the parsed items
233
+ in the resulting url we could do this:
234
+
235
+ map.regex( { :whole_tweet => /^shoot\s+@[\w\d_]+\s+in\s+the\s+(\w+).*/,
236
+ :who_got_shot => [/^shoot\s+@([\w\d_]+)\s+/, 1],
237
+ :shot_where => [/\s+in\s+the\s+(\w+).*/, 1]
238
+ }, '/badshot/create/name/:who_got_shot/where/:shot_where' )
239
+
240
+ ==== Regex matcher and procs
241
+
242
+ We could rewrite the above example to use a proc as well.
243
+
244
+ map.regex( { :whole_tweet => /^shoot\s+@[\w\d_]+\s+in\s+the\s+(\w+).*/,
245
+ :who_got_shot => [/^shoot\s+@([\w\d_]+)\s+/, 1],
246
+ :shot_where => lambda { |tweet_text|
247
+ match_data = tweet_text.match(/\s+in\s+the\s+(\w+).*/)
248
+ match_data ? match_data[1] : nil
249
+ }
250
+ },
251
+ '/badshot/create/name/:who_got_shot/where/:shot_where')
252
+
253
+ If the proc returns +nil+ it will not be considered a match and the next
254
+ route will be tried.
255
+
256
+ === Routing order
257
+
258
+ The routes are executed in a similar manner as Routes in Rails. They
259
+ are tried in top down order. As soon as a match is found the rest of
260
+ the routes are ignored.
261
+
262
+ == What gets posted?
263
+
264
+ When a route is finally selected and a path is chosen three hashes get
265
+ posted to the selected url:
266
+
267
+ ==== The Parsed Hash
268
+
269
+ In our example this will be:
270
+
271
+ parsed[whole_tweet]: shoot @johnny in the wild
272
+ parsed[who_got_shot]: johnny
273
+ parsed[shot_where]: wild
274
+
275
+ ==== The Twitter Tweet Hash
276
+
277
+ For example:
278
+
279
+ tweet[in_reply_to_screen_name]:
280
+ tweet[id]: 3317086732
281
+ tweet[created_at]: Fri Aug 14 22:31:44 +0000 2009
282
+ tweet[in_reply_to_user_id]:
283
+ tweet[favorited]: false
284
+ tweet[truncated]: false
285
+ tweet[source]: <a href="http://www.tweetdeck.com/" rel="nofollow">TweetDeck</a>
286
+ tweet[in_reply_to_status_id]:
287
+ tweet[text]: shoot @johnny in the wild
288
+
289
+ ==== The Twitter User Hash
290
+
291
+ We pull this out of the tweet[:user] and post it as the sender[] hash:
292
+
293
+ sender[following]:
294
+ sender[friends_count]: 86
295
+ sender[followers_count]: 113
296
+ sender[profile_link_color]: "990000"
297
+ sender[protected]: false
298
+ sender[profile_sidebar_border_color]: DFDFDF
299
+ sender[notifications]:
300
+ sender[screen_name]: Sarahndipitea
301
+ sender[name]: Sarah
302
+ sender[profile_sidebar_fill_color]: F3F3F3
303
+ sender[created_at]: Tue Oct 21 03:06:15 +0000 2008
304
+ sender[id]: 16880192
305
+ sender[location]: Stumptown
306
+ sender[profile_image_url]: http://s3.amazonaws.com/twitter_production/profile_images/332336440/EllieUp_normal.jpg
307
+ sender[description]: You found me! Were you even *looking* for me?
308
+ sender[favourites_count]: 12
309
+ sender[profile_background_image_url]: http://static.twitter.com/images/themes/theme7/bg.gif
310
+ sender[statuses_count]: 9601
311
+ sender[profile_background_tile]: false
312
+ sender[verified]: false
313
+ sender[profile_background_color]: EBEBEB
314
+ sender[profile_text_color]: "333333"
315
+ sender[time_zone]: Pacific Time (US & Canada)
316
+ sender[utc_offset]: -28800
317
+ sender[url]: http://Sarahndipitea.wordpress.com
318
+
319
+ (_This tweet was completely chosen randomly. I didn't want to take time
320
+ to come up with fake data. If you have some funny data. Send me
321
+ a pull request._)
322
+
323
+ == Gentlemen start your servers.
324
+
325
+ So now we setup the config file and we have have tests and routes.
326
+
327
+ === First initialize the Sqlite3 DB
328
+
329
+ Execute the following rake command:
330
+
331
+ rake twroute:init
332
+
333
+ === Create a sample app to receive the post requests
334
+
335
+ You might want to set up a sample Rails app and tail the development
336
+ log at this point.
337
+
338
+ rails sample_twroute_app
339
+ cd sample_twroute_app
340
+ ./script/server
341
+
342
+ No need to create controllers that do anything. This just so you can
343
+ see that the requsts are being made.
344
+
345
+ === Start the twroute_runner daemon
346
+
347
+ This is the daemon that pulls down the tweets from the twitter stream
348
+ api, routes them and stores them as a delayed job.
349
+
350
+ Change to the bad_shot directory and execute:
351
+
352
+ twroute_runner start
353
+
354
+ At this point IF there are tweets that match your stream api query AND
355
+ these tweets also match your routes defined in +twroutes+.+rb+ then you
356
+ should see some delayed_jobs being created in +log+/+database.log+
357
+
358
+ You can stop this daemon by executing:
359
+
360
+ twroute_runner stop
361
+
362
+ === Start the twroute_worker daemon
363
+
364
+ Seeing as we are creating Delayed Jobs we have to have a daemon that
365
+ executes the jobs. You can start it in a similar fashion.
366
+
367
+ Change to the bad_shot directory and execute:
368
+
369
+ twroute_worker start
370
+
371
+ At this point IF there are jobs stored in the Sqlite3 database then
372
+ you should see activity in the +log+/+delayed.log+
373
+
374
+ You can stop this daemon by executing:
375
+
376
+ twroute_worker stop
377
+
378
+ === Start/Stop Short Cut
379
+
380
+ You can start and stop both the daemons using the +rake+ +twroute+:+start+ and
381
+ +rake+ +twroute+:+stop+ commands.
382
+
383
+ == Troubleshooting
384
+
385
+ === No output
386
+
387
+ You can check that your Twitter stream request is functioning by
388
+ temporarily making a catchall route at the end of you routes like so:
389
+
390
+ map.regex( { :match_all_tweets => /.*/ }, '/badshot/create' )
391
+
392
+ This will force all tweets from the stream to be sent to your app.
393
+ This is very useful to verify that tweets are coming down and going
394
+ through the system.
395
+
396
+ == Monit and God
397
+
398
+ Don't forget to setup either Monit, God or some other server process
399
+ monitor because Twitter reserves the right to close the connection
400
+ whenever they want. I would say that it's fairly safe to simply
401
+ restart the daemons periodically as well.
402
+
403
+
404
+
405
+ == License
406
+
407
+ (The MIT License)
408
+
409
+ Copyright (c) 2009 Bruce Hauman <bhauman@gmail.com>
410
+
411
+ Permission is hereby granted, free of charge, to any person obtaining
412
+ a copy of this software and associated documentation files (the
413
+ 'Software'), to deal in the Software without restriction, including
414
+ without limitation the rights to use, copy, modify, merge, publish,
415
+ distribute, sublicense, and/or sell copies of the Software, and to
416
+ permit persons to whom the Software is furnished to do so, subject to
417
+ the following conditions:
418
+
419
+ The above copyright notice and this permission notice shall be
420
+ included in all copies or substantial portions of the Software.
421
+
422
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
423
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
424
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
425
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
426
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
427
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
428
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7
429
 
8
- In other words a controller can recieve a tweet and then reply to the
9
- sender by simply rendering a view.
10
430
 
11
- Cool huh? Well I like it.
431
+ Copyright (c) 2009 Bruce Hauman, released under the MIT license
12
432
 
13
- == more docs soon?
data/Rakefile CHANGED
@@ -12,10 +12,16 @@ begin
12
12
  gem.email = "bhauman@gmail.com"
13
13
  gem.homepage = "http://github.com/bhauman/twroute"
14
14
  gem.authors = ["bhauman"]
15
+ gem.executables = ['twroute', 'twroute_runner', 'twroute_worker']
15
16
  gem.add_dependency('activerecord', '>= 2.1.0')
16
17
  gem.add_dependency('tobi-delayed_job', '>= 1.7.0')
17
18
  gem.add_dependency('brianmario-yajl-ruby', '>= 0.5.12')
18
- gem.add_dependency('daemons', '>= 1.0.10')
19
+ gem.add_dependency('daemons', '>= 1.0.10')
20
+ gem.add_dependency('rubigen', '>= 1.5.2')
21
+ gem.add_dependency('thoughtbot-shoulda', '>= 2.10.1')
22
+ gem.add_dependency('mhennemeyer-matchy', '>= 0.3.3')
23
+ gem.add_dependency('jeremymcanally-stump', '>= 0.0.2')
24
+ gem.add_dependency('sqlite-ruby', '>= 2.2.3')
19
25
  end
20
26
 
21
27
  rescue LoadError
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.1.3
@@ -1,12 +1,12 @@
1
1
  submit_to:
2
- host: 'localhost'
2
+ host: localhost
3
3
  port: 3000
4
4
  # http_auth_user: ''
5
5
  # http_auth_password: ''
6
6
  twitter:
7
7
  user: ''
8
8
  password: ''
9
- stream_api: 'track'
9
+ stream_api: track
10
10
  stream_api_args:
11
11
  track: twitter
12
12
  database:
data/twroute.gemspec CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{twroute}
5
- s.version = "0.1.1"
5
+ s.version = "0.1.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["bhauman"]
9
- s.date = %q{2009-08-14}
9
+ s.date = %q{2009-08-15}
10
10
  s.description = %q{Twroute listens for Twitter updates and redirects them to HTTP post requests}
11
11
  s.email = %q{bhauman@gmail.com}
12
- s.executables = ["twroute", "twroute_gen", "twroute_runner", "twroute_worker"]
12
+ s.executables = ["twroute", "twroute_runner", "twroute_worker"]
13
13
  s.extra_rdoc_files = [
14
14
  "README.rdoc"
15
15
  ]
@@ -97,16 +97,31 @@ Gem::Specification.new do |s|
97
97
  s.add_runtime_dependency(%q<tobi-delayed_job>, [">= 1.7.0"])
98
98
  s.add_runtime_dependency(%q<brianmario-yajl-ruby>, [">= 0.5.12"])
99
99
  s.add_runtime_dependency(%q<daemons>, [">= 1.0.10"])
100
+ s.add_runtime_dependency(%q<rubigen>, [">= 1.5.2"])
101
+ s.add_runtime_dependency(%q<thoughtbot-shoulda>, [">= 2.10.1"])
102
+ s.add_runtime_dependency(%q<mhennemeyer-matchy>, [">= 0.3.3"])
103
+ s.add_runtime_dependency(%q<jeremymcanally-stump>, [">= 0.0.2"])
104
+ s.add_runtime_dependency(%q<sqlite-ruby>, [">= 2.2.3"])
100
105
  else
101
106
  s.add_dependency(%q<activerecord>, [">= 2.1.0"])
102
107
  s.add_dependency(%q<tobi-delayed_job>, [">= 1.7.0"])
103
108
  s.add_dependency(%q<brianmario-yajl-ruby>, [">= 0.5.12"])
104
109
  s.add_dependency(%q<daemons>, [">= 1.0.10"])
110
+ s.add_dependency(%q<rubigen>, [">= 1.5.2"])
111
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 2.10.1"])
112
+ s.add_dependency(%q<mhennemeyer-matchy>, [">= 0.3.3"])
113
+ s.add_dependency(%q<jeremymcanally-stump>, [">= 0.0.2"])
114
+ s.add_dependency(%q<sqlite-ruby>, [">= 2.2.3"])
105
115
  end
106
116
  else
107
117
  s.add_dependency(%q<activerecord>, [">= 2.1.0"])
108
118
  s.add_dependency(%q<tobi-delayed_job>, [">= 1.7.0"])
109
119
  s.add_dependency(%q<brianmario-yajl-ruby>, [">= 0.5.12"])
110
120
  s.add_dependency(%q<daemons>, [">= 1.0.10"])
121
+ s.add_dependency(%q<rubigen>, [">= 1.5.2"])
122
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 2.10.1"])
123
+ s.add_dependency(%q<mhennemeyer-matchy>, [">= 0.3.3"])
124
+ s.add_dependency(%q<jeremymcanally-stump>, [">= 0.0.2"])
125
+ s.add_dependency(%q<sqlite-ruby>, [">= 2.2.3"])
111
126
  end
112
127
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bhauman-twroute
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - bhauman
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-08-14 00:00:00 -07:00
12
+ date: 2009-08-15 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -52,11 +52,60 @@ dependencies:
52
52
  - !ruby/object:Gem::Version
53
53
  version: 1.0.10
54
54
  version:
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubigen
57
+ type: :runtime
58
+ version_requirement:
59
+ version_requirements: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 1.5.2
64
+ version:
65
+ - !ruby/object:Gem::Dependency
66
+ name: thoughtbot-shoulda
67
+ type: :runtime
68
+ version_requirement:
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: 2.10.1
74
+ version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: mhennemeyer-matchy
77
+ type: :runtime
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 0.3.3
84
+ version:
85
+ - !ruby/object:Gem::Dependency
86
+ name: jeremymcanally-stump
87
+ type: :runtime
88
+ version_requirement:
89
+ version_requirements: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: 0.0.2
94
+ version:
95
+ - !ruby/object:Gem::Dependency
96
+ name: sqlite-ruby
97
+ type: :runtime
98
+ version_requirement:
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 2.2.3
104
+ version:
55
105
  description: Twroute listens for Twitter updates and redirects them to HTTP post requests
56
106
  email: bhauman@gmail.com
57
107
  executables:
58
108
  - twroute
59
- - twroute_gen
60
109
  - twroute_runner
61
110
  - twroute_worker
62
111
  extensions: []