http_router_sinatra 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ pkg/*
2
+ *.gem
3
+ .bundle
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in http_router_sinatra.gemspec
4
+ gemspec
@@ -0,0 +1,45 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ http_router_sinatra (0.0.1)
5
+ http_router (~> 0.6.1)
6
+ sinatra (~> 1.2.0)
7
+
8
+ GEM
9
+ remote: http://rubygems.org/
10
+ specs:
11
+ callsite (0.0.4)
12
+ code_stats (0.0.1)
13
+ dirge (>= 0.0.3)
14
+ rainbow
15
+ dirge (0.0.5)
16
+ callsite (>= 0.0.2)
17
+ http_router (0.6.1)
18
+ rack (>= 1.0.0)
19
+ url_mount (~> 0.2.1)
20
+ minitest (2.0.2)
21
+ phocus (1.1)
22
+ rack (1.2.2)
23
+ rainbow (1.1)
24
+ rake (0.8.7)
25
+ rbench (0.2.3)
26
+ sinatra (1.2.1)
27
+ rack (~> 1.1)
28
+ tilt (>= 1.2.2, < 2.0)
29
+ tilt (1.2.2)
30
+ url_mount (0.2.1)
31
+ rack
32
+
33
+ PLATFORMS
34
+ ruby
35
+
36
+ DEPENDENCIES
37
+ bundler (~> 1.0.0)
38
+ code_stats
39
+ http_router (~> 0.6.1)
40
+ http_router_sinatra!
41
+ minitest (~> 2.0.0)
42
+ phocus
43
+ rake
44
+ rbench
45
+ sinatra (~> 1.2.0)
@@ -0,0 +1,10 @@
1
+ # HttpRouter for Sinatra
2
+
3
+ ## Usage
4
+
5
+ In your Sinatra app, register your extension
6
+
7
+ register HttpRouter::Sinatra::Extension
8
+
9
+ Then, add your routes normally. If you use the :name option when defining your route, you can later generate your route
10
+ with the `generate` method.
@@ -0,0 +1,21 @@
1
+ require 'bundler'
2
+ require 'code_stats'
3
+
4
+ desc "Run tests"
5
+ task :test do
6
+ $: << 'lib'
7
+ require 'http_router_sinatra'
8
+ require 'test/helper'
9
+ Dir['test/**/test_*.rb'].each { |test| require test }
10
+ end
11
+
12
+ require 'rake/rdoctask'
13
+ desc "Generate documentation"
14
+ Rake::RDocTask.new do |rd|
15
+ rd.main = "README.rdoc"
16
+ rd.rdoc_files.include("README.rdoc", "lib/**/*.rb")
17
+ rd.rdoc_dir = 'rdoc'
18
+ end
19
+
20
+ Bundler::GemHelper.install_tasks
21
+ CodeStats::Tasks.new(:reporting_depth => 3)
@@ -0,0 +1,30 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "http_router_sinatra/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "http_router_sinatra"
7
+ s.version = HttpRouter::Sinatra::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Joshua Hull"]
10
+ s.email = ["joshbuddy@gmail.com"]
11
+ s.homepage = "https://github.com/joshbuddy/http_router_sinatra"
12
+ s.summary = %q{Kick ass router for Sinatra based on http_router}
13
+ s.description = %q{Kick ass router for Sinatra based on http_router.}
14
+
15
+ s.rubyforge_project = "http_router_sinatra"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency "http_router", "~> 0.6.2"
23
+ s.add_dependency "sinatra", "~> 1.2.0"
24
+ s.add_development_dependency 'minitest', '~> 2.0.0'
25
+ s.add_development_dependency 'code_stats'
26
+ s.add_development_dependency 'rake'
27
+ s.add_development_dependency 'rbench'
28
+ s.add_development_dependency 'phocus'
29
+ s.add_development_dependency 'bundler', '~> 1.0.0'
30
+ end
@@ -0,0 +1,189 @@
1
+ require 'http_router'
2
+ require 'sinatra'
3
+
4
+ class HttpRouter
5
+ class Sinatra
6
+
7
+ def initialize
8
+ ::Sinatra.send(:include, Extension)
9
+ end
10
+
11
+ module Extension
12
+
13
+ def self.registered(app)
14
+ app.send(:include, Extension)
15
+ end
16
+
17
+ def self.included(base)
18
+ base.extend ClassMethods
19
+ end
20
+
21
+ def generate(name, *params)
22
+ self.class.generate(name, *params)
23
+ end
24
+
25
+ private
26
+ def route!(base=self.class, pass_block=nil)
27
+ request.env['sinatra.instance'] = self
28
+ if base.router and match = base.router.recognize(request.env)
29
+ if match.respond_to?(:path)
30
+ throw :halt, @_response_buffer
31
+ elsif match.is_a?(Array)
32
+ route_eval {
33
+ match[1].each{|k,v| response[k] = v}
34
+ status match[0]
35
+ }
36
+ end
37
+ end
38
+
39
+ # Run routes defined in superclass.
40
+ if base.superclass.respond_to?(:router)
41
+ route! base.superclass, pass_block
42
+ return
43
+ end
44
+
45
+ route_eval(&pass_block) if pass_block
46
+
47
+ route_missing
48
+ ensure
49
+ @_response_buffer = nil
50
+ end
51
+
52
+ module ClassMethods
53
+
54
+ def new(*args, &bk)
55
+ configure! unless @_configured
56
+ super(*args, &bk)
57
+ end
58
+
59
+ def get(path, *args, &block)
60
+ conditions = @conditions.dup
61
+ route('GET', path, *args, &block)
62
+
63
+ @conditions = conditions
64
+ route('HEAD', path, *args, &block)
65
+ end
66
+
67
+ def put(path, *args, &bk); route 'PUT', path, *args, &bk end
68
+ def post(path, *args, &bk); route 'POST', path, *args, &bk end
69
+ def delete(path, *args, &bk); route 'DELETE', path, *args, &bk end
70
+ def head(path, *args, &bk); route 'HEAD', path, *args, &bk end
71
+
72
+ def route(verb, path, options={}, &block)
73
+ name = options.delete(:name)
74
+
75
+ path = transform_path(path)
76
+
77
+ define_method "#{verb} #{path}", &block
78
+ unbound_method = instance_method("#{verb} #{path}")
79
+ block = block.arity.zero? ?
80
+ proc { unbound_method.bind(self).call } :
81
+ proc { unbound_method.bind(self).call(*@block_params) }
82
+
83
+ invoke_hook(:route_added, verb, path, block)
84
+
85
+ route = router.add(path)
86
+
87
+ route.matching(options[:matching]) if options.key?(:matching)
88
+
89
+ route.send(verb.downcase.to_sym)
90
+ route.host(options[:host]) if options.key?(:host)
91
+
92
+ route.name(name) if name
93
+
94
+ route.arbitrary_with_continue do |req, params|
95
+ if req.testing_405?
96
+ req.continue[true]
97
+ else
98
+ req.rack_request.env['sinatra.instance'].instance_eval do
99
+ handled = false
100
+ @block_params = req.params
101
+ (@params ||= {}).merge!(params)
102
+ pass_block = catch(:pass) do
103
+ route_eval(&block)
104
+ handled = true
105
+ end
106
+ req.continue[handled]
107
+ end
108
+ end
109
+ end
110
+
111
+ route.to(block)
112
+ route
113
+ end
114
+
115
+ def router
116
+ @router ||= HttpRouter.new
117
+ yield(@router) if block_given?
118
+ @router
119
+ end
120
+
121
+ def generate(name, *params)
122
+ router.url(name, *params)
123
+ end
124
+
125
+ def reset!
126
+ router.reset!
127
+ super
128
+ end
129
+
130
+ def configure!
131
+ configure :development do
132
+ error 404 do
133
+ content_type 'text/html'
134
+
135
+ (<<-HTML).gsub(/^ {17}/, '')
136
+ <!DOCTYPE html>
137
+ <html>
138
+ <head>
139
+ <style type="text/css">
140
+ body { text-align:center;font-family:helvetica,arial;font-size:22px;
141
+ color:#888;margin:20px}
142
+ #c {margin:0 auto;width:500px;text-align:left}
143
+ </style>
144
+ </head>
145
+ <body>
146
+ <h2>Sinatra doesn't know this ditty.</h2>
147
+ <div id="c">
148
+ Try this:
149
+ <pre>#{request.request_method.downcase} '#{request.path_info}' do\n "Hello World"\nend</pre>
150
+ </div>
151
+ </body>
152
+ </html>
153
+ HTML
154
+ end
155
+ error 405 do
156
+ content_type 'text/html'
157
+
158
+ (<<-HTML).gsub(/^ {17}/, '')
159
+ <!DOCTYPE html>
160
+ <html>
161
+ <head>
162
+ <style type="text/css">
163
+ body { text-align:center;font-family:helvetica,arial;font-size:22px;
164
+ color:#888;margin:20px}
165
+ #c {margin:0 auto;width:500px;text-align:left}
166
+ </style>
167
+ </head>
168
+ <body>
169
+ <h2>Sinatra sorta knows this ditty, but the request method is not allowed.</h2>
170
+ </body>
171
+ </html>
172
+ HTML
173
+ end
174
+ end
175
+
176
+ @_configured = true
177
+ end
178
+
179
+ private
180
+ def transform_path(path)
181
+ if path.is_a?(String)
182
+ path.gsub!(/\/\?$/, '(/)')
183
+ end
184
+ path
185
+ end
186
+ end # ClassMethods
187
+ end # Extension
188
+ end # Sinatra
189
+ end # HttpRouter
@@ -0,0 +1,5 @@
1
+ class HttpRouter
2
+ class Sinatra
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,74 @@
1
+ require 'minitest/autorun'
2
+ require 'phocus'
3
+
4
+ class HttpRouter::Route
5
+ def default_destination
6
+ to{|env| Rack::Response.new("Routing to #{to_s}").finish}
7
+ end
8
+ end
9
+
10
+ class MiniTest::Unit::TestCase
11
+ def router(*args, &blk)
12
+ @router ||= HttpRouter.new(*args, &blk)
13
+ if blk
14
+ @router.routes.each do |route|
15
+ route.default_destination if route.dest.nil?
16
+ end
17
+ @router.routes.size > 1 ? @router.routes : @router.routes.first
18
+ else
19
+ @router
20
+ end
21
+ end
22
+
23
+ def assert_body(expect, response)
24
+ response = router.call(response) if response.is_a?(Hash)
25
+ body = case expect
26
+ when Array then []
27
+ when String then ""
28
+ else raise
29
+ end
30
+ response.last.each {|p| body << p}
31
+ assert_equal expect, body
32
+ end
33
+
34
+ def assert_header(header, response)
35
+ response = router.call(response) if response.is_a?(Hash)
36
+ header.each{|k, v| assert_equal v, response[1][k]}
37
+ end
38
+
39
+ def assert_status(status, response)
40
+ response = router.call(response) if response.is_a?(Hash)
41
+ assert_equal status, response.first
42
+ end
43
+
44
+ def assert_route(route, request, params = nil, &blk)
45
+ if route.is_a?(String)
46
+ router.reset!
47
+ route = router.add(route)
48
+ end
49
+ route.to{|env| Rack::Response.new("Routing to #{route.to_s}").finish} if route && !route.compiled?
50
+ request = Rack::MockRequest.env_for(request) if request.is_a?(String)
51
+ response = @router.call(request)
52
+ if route
53
+ dest = "Routing to #{route.to_s}"
54
+ assert_equal [dest], response.last.body
55
+ if params
56
+ assert_equal params.size, request['router.params'].size
57
+ params.each { |k, v| assert_equal v, request['router.params'][k] }
58
+ elsif !request['router.params'].nil? and !request['router.params'].empty?
59
+ raise "Wasn't expecting any parameters, got #{request['router.params'].inspect}"
60
+ end
61
+ else
62
+ assert_equal 404, response.first
63
+ end
64
+ end
65
+
66
+ def assert_generate(path, route, *args)
67
+ if route.is_a?(String)
68
+ router.reset!
69
+ route = router.add(route).to(path.to_sym)
70
+ end
71
+ route.to{|env| Rack::Response.new("Routing to #{route.to_s}").finish} if route.respond_to?(:compiled?) && !route.compiled?
72
+ assert_equal path, router.url(route, *args)
73
+ end
74
+ end
@@ -0,0 +1,145 @@
1
+ module CallWithMockRequestMixin
2
+ def call_with_mock_request(url = "/sample", method = "GET")
3
+ Rack::MockRequest.new(self).request(method, url)
4
+ end
5
+ end
6
+
7
+ class TestRecognize < MiniTest::Unit::TestCase
8
+
9
+ def setup
10
+ @app = Sinatra.new { register HttpRouter::Sinatra::Extension }
11
+ @app.extend(CallWithMockRequestMixin)
12
+ @app.reset!
13
+ end
14
+
15
+ def test_basic
16
+ response = @app.call_with_mock_request('/bar')
17
+ assert_equal 404, response.status
18
+ end
19
+
20
+ def test_map_index
21
+ @app.get("/") { "index" }
22
+ response = @app.call_with_mock_request('/')
23
+ assert_equal 200, response.status
24
+ assert_equal "index", response.body
25
+ end
26
+
27
+ def test_trailing_slash
28
+ @app.get("/foo") { "foo" }
29
+ response = @app.call_with_mock_request('/foo')
30
+ assert_equal 200, response.status
31
+ assert_equal "foo", response.body
32
+ response = @app.call_with_mock_request('/foo/')
33
+ assert_equal 200, response.status
34
+ assert_equal "foo", response.body
35
+ end
36
+
37
+ def test_trailing_slash2
38
+ @app.get("/foo") { "foo" }
39
+ @app.get("/foo/bar") { "bar" }
40
+ response = @app.call_with_mock_request('/foo')
41
+ assert_equal 200, response.status
42
+ assert_equal "foo", response.body
43
+ response = @app.call_with_mock_request('/foo/bar')
44
+ assert_equal 200, response.status
45
+ assert_equal "bar", response.body
46
+ response = @app.call_with_mock_request('/foo/')
47
+ assert_equal 200, response.status
48
+ assert_equal "foo", response.body
49
+ response = @app.call_with_mock_request('/foo/bar/')
50
+ assert_equal 200, response.status
51
+ assert_equal "bar", response.body
52
+ end
53
+
54
+ def test_trailing_slash_with_optional_param
55
+ @app.get("/foo/(:bar)") { params[:bar] }
56
+ @app.get("/bar(/:foo)") { params[:foo] }
57
+ response = @app.call_with_mock_request('/foo/bar')
58
+ assert_equal 200, response.status
59
+ assert_equal "bar", response.body
60
+ response = @app.call_with_mock_request('/bar/foo')
61
+ assert_equal 200, response.status
62
+ assert_equal "foo", response.body
63
+ response = @app.call_with_mock_request('/bar')
64
+ assert_equal 200, response.status
65
+ assert_equal "", response.body
66
+ response = @app.call_with_mock_request('/bar/')
67
+ assert_equal 200, response.status
68
+ assert_equal "", response.body
69
+ end
70
+
71
+ def test_trailing_question_mark
72
+ @app.get("/foo/?") { "foo" }
73
+ response = @app.call_with_mock_request('/foo')
74
+ assert_equal 200, response.status
75
+ assert_equal "foo", response.body
76
+ response = @app.call_with_mock_request('/foo/')
77
+ assert_equal 200, response.status
78
+ assert_equal "foo", response.body
79
+ end
80
+
81
+ def test_map_basic
82
+ @app.get('/hi', :name => :hi) { generate(:hi) }
83
+ response = @app.call_with_mock_request('/hi')
84
+ assert_equal 200, response.status
85
+ assert_equal "/hi", response.body
86
+ end
87
+
88
+ def test_map_basic2
89
+ @app.get('/hi', :name => :hi) { generate(:hi) }
90
+ response = @app.call_with_mock_request('/hi/')
91
+ assert_equal 200, response.status
92
+ assert_equal "/hi", response.body
93
+ end
94
+
95
+ def test_map_param
96
+ @app.get('/hi/:id', :name => :hi) { generate(:hi, :id => 18) }
97
+ response = @app.call_with_mock_request('/hi/1')
98
+ assert_equal 200, response.status
99
+ assert_equal "/hi/18", response.body
100
+ end
101
+
102
+ def test_map_param2
103
+ @app.get('/hi-:id', :name => :hi) { generate(:hi, :id => 18) }
104
+ response = @app.call_with_mock_request('/hi-1')
105
+ assert_equal 200, response.status
106
+ assert_equal "/hi-18", response.body
107
+ end
108
+
109
+ def test_map_complex
110
+ @app.get('/hi/:foo/:bar/:baz(.:format)') { "/#{params[:foo]}/#{params[:bar]}/#{params[:baz]}/#{params[:format]}" }
111
+ response = @app.call_with_mock_request('/hi/foo/bar/baz')
112
+ assert_equal 200, response.status
113
+ assert_equal "/foo/bar/baz/", response.body
114
+ response = @app.call_with_mock_request('/hi/foo/bar-bax/baz')
115
+ assert_equal 200, response.status
116
+ assert_equal "/foo/bar-bax/baz/", response.body
117
+ end
118
+
119
+ def test_map_regexp
120
+ @app.get('/numbers/:digits', :matching => { :digits => /\d+/ }) { params[:digits] }
121
+ response = @app.call_with_mock_request('/numbers/2010')
122
+ assert_equal 200, response.status
123
+ assert_equal "2010", response.body
124
+ end
125
+
126
+ def test_not_map_regex
127
+ @app.get('/numbers/:digits', :matching => { :digits => /\d+/ }) { params[:digits] }
128
+ response = @app.call_with_mock_request('/numbers/nan')
129
+ assert_equal 404, response.status
130
+ end
131
+
132
+ def test_404
133
+ response = @app.call_with_mock_request('/bar')
134
+ assert_equal 404, response.status
135
+ assert_match response.body, /Sinatra doesn't know this ditty/
136
+ end
137
+
138
+ def test_405
139
+ @app.post('/bar') { 'foundpost' }
140
+ @app.put('/bar') { 'foundput' }
141
+ response = @app.call_with_mock_request('/bar')
142
+ assert_equal 405, response.status
143
+ assert_equal ['POST', 'PUT'], response.headers['Allow'].split(/\s*,\s*/).sort
144
+ end
145
+ end
metadata ADDED
@@ -0,0 +1,197 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: http_router_sinatra
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Joshua Hull
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-21 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: http_router
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ - 6
33
+ - 2
34
+ version: 0.6.2
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: sinatra
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ hash: 31
46
+ segments:
47
+ - 1
48
+ - 2
49
+ - 0
50
+ version: 1.2.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: minitest
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ hash: 15
62
+ segments:
63
+ - 2
64
+ - 0
65
+ - 0
66
+ version: 2.0.0
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: code_stats
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ type: :development
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ prerelease: false
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ type: :development
96
+ version_requirements: *id005
97
+ - !ruby/object:Gem::Dependency
98
+ name: rbench
99
+ prerelease: false
100
+ requirement: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 3
106
+ segments:
107
+ - 0
108
+ version: "0"
109
+ type: :development
110
+ version_requirements: *id006
111
+ - !ruby/object:Gem::Dependency
112
+ name: phocus
113
+ prerelease: false
114
+ requirement: &id007 !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ type: :development
124
+ version_requirements: *id007
125
+ - !ruby/object:Gem::Dependency
126
+ name: bundler
127
+ prerelease: false
128
+ requirement: &id008 !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ~>
132
+ - !ruby/object:Gem::Version
133
+ hash: 23
134
+ segments:
135
+ - 1
136
+ - 0
137
+ - 0
138
+ version: 1.0.0
139
+ type: :development
140
+ version_requirements: *id008
141
+ description: Kick ass router for Sinatra based on http_router.
142
+ email:
143
+ - joshbuddy@gmail.com
144
+ executables: []
145
+
146
+ extensions: []
147
+
148
+ extra_rdoc_files: []
149
+
150
+ files:
151
+ - .gitignore
152
+ - Gemfile
153
+ - Gemfile.lock
154
+ - README.md
155
+ - Rakefile
156
+ - http_router_sinatra.gemspec
157
+ - lib/http_router_sinatra.rb
158
+ - lib/http_router_sinatra/version.rb
159
+ - test/helper.rb
160
+ - test/test_recognize.rb
161
+ has_rdoc: true
162
+ homepage: https://github.com/joshbuddy/http_router_sinatra
163
+ licenses: []
164
+
165
+ post_install_message:
166
+ rdoc_options: []
167
+
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ none: false
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ hash: 3
176
+ segments:
177
+ - 0
178
+ version: "0"
179
+ required_rubygems_version: !ruby/object:Gem::Requirement
180
+ none: false
181
+ requirements:
182
+ - - ">="
183
+ - !ruby/object:Gem::Version
184
+ hash: 3
185
+ segments:
186
+ - 0
187
+ version: "0"
188
+ requirements: []
189
+
190
+ rubyforge_project: http_router_sinatra
191
+ rubygems_version: 1.3.7
192
+ signing_key:
193
+ specification_version: 3
194
+ summary: Kick ass router for Sinatra based on http_router
195
+ test_files:
196
+ - test/helper.rb
197
+ - test/test_recognize.rb