add back in rack helpers. make examples verifiable
This commit is contained in:
parent
9fd85e83c3
commit
30b6c1709f
40
Rakefile
40
Rakefile
|
@ -20,3 +20,43 @@ end
|
|||
|
||||
Bundler::GemHelper.install_tasks
|
||||
CodeStats::Tasks.new(:reporting_depth => 3)
|
||||
|
||||
task :test_examples do
|
||||
$: << 'lib'
|
||||
require 'http_router'
|
||||
require 'thin'
|
||||
Dir['./examples/**/*.ru'].each do |example|
|
||||
print "running example #{example}..."
|
||||
comments = File.read(example).split(/\n/).select{|l| l[0] == ?#}
|
||||
pid = nil
|
||||
Thin::Logging.silent = true
|
||||
begin
|
||||
pid = fork {
|
||||
code = "Proc.new { \n#{File.read(example)}\n }"
|
||||
r = eval(code, binding, example, 2)
|
||||
Thin::Server.start(:signals => false, &r)
|
||||
}
|
||||
sleep 0.5
|
||||
out = nil
|
||||
assertion_count = 0
|
||||
comments.each do |c|
|
||||
c.gsub!(/^# ?/, '')
|
||||
case c
|
||||
when /^\$/
|
||||
out = `#{c[1, c.size]} 2>/dev/null`.split(/\n/)
|
||||
raise "#{c} produced #{out}" unless $?.success?
|
||||
when /^=> ?(.*)/
|
||||
c = $1
|
||||
raise "out was nil" if out.nil?
|
||||
test = out.shift
|
||||
raise "excepted #{c.inspect}, recieved #{test.inspect}" unless c.strip == test.strip
|
||||
assertion_count += 1
|
||||
end
|
||||
end
|
||||
raise "no assertions were raised in #{example}" if assertion_count.zero?
|
||||
puts "✔"
|
||||
ensure
|
||||
Process.kill('HUP', pid) if pid
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,8 +4,8 @@ run HttpRouter.new {
|
|||
get('/*glob').to { |env| [200, {'Content-type' => 'text/plain'}, ["My glob is\n#{env['router.params'][:glob].map{|v| " * #{v}\n"}.join}"]]}
|
||||
}
|
||||
|
||||
# crapbook-pro:~ joshua$ curl http://127.0.0.1:3000/123/345/123
|
||||
# My glob is
|
||||
# * 123
|
||||
# * 345
|
||||
# * 123
|
||||
# $ curl http://127.0.0.1:3000/123/345/123
|
||||
# => My glob is
|
||||
# => * 123
|
||||
# => * 345
|
||||
# => * 123
|
|
@ -1,46 +0,0 @@
|
|||
require 'http_router'
|
||||
|
||||
use(HttpRouter, :middleware => true) {
|
||||
add('/test').name(:test)
|
||||
add('/:variable').name(:var)
|
||||
add('/more/*glob').name(:glob)
|
||||
add('/get/:id').matching(:id => /\d+/).name(:get)
|
||||
}
|
||||
|
||||
run proc {|env|
|
||||
[
|
||||
200,
|
||||
{'Content-type' => 'text/plain'},
|
||||
[<<-HEREDOC
|
||||
We matched? #{env['router.response'] && env['router.response'].matched? ? 'yes!' : 'no'}
|
||||
Params are #{env['router.response'] && env['router.response'].matched? ? env['router.response'].params_as_hash.inspect : 'we had no params'}
|
||||
That was fun
|
||||
HEREDOC
|
||||
]
|
||||
]
|
||||
}
|
||||
|
||||
# crapbook-pro:polleverywhere joshua$ curl http://127.0.0.1:3000/hi
|
||||
# We matched? yes!
|
||||
# Params are {:variable=>"hi"}
|
||||
# That was fun
|
||||
# crapbook-pro:polleverywhere joshua$ curl http://127.0.0.1:3000/test
|
||||
# We matched? yes!
|
||||
# Params are {}
|
||||
# That was fun
|
||||
# crapbook-pro:polleverywhere joshua$ curl http://127.0.0.1:3000/hey
|
||||
# We matched? yes!
|
||||
# Params are {:variable=>"hey"}
|
||||
# That was fun
|
||||
# crapbook-pro:polleverywhere joshua$ curl http://127.0.0.1:3000/more/fun/in/the/sun
|
||||
# We matched? yes!
|
||||
# Params are {:glob=>["fun", "in", "the", "sun"]}
|
||||
# That was fun
|
||||
# crapbook-pro:polleverywhere joshua$ curl http://127.0.0.1:3000/get/what
|
||||
# We matched? no
|
||||
# Params are we had no params
|
||||
# That was fun
|
||||
# crapbook-pro:polleverywhere joshua$ curl http://127.0.0.1:3000/get/123
|
||||
# We matched? yes!
|
||||
# Params are {:id=>"123"}
|
||||
# That was fun
|
|
@ -1,5 +1,5 @@
|
|||
require 'http_router'
|
||||
HttpRouter.override_rack_mapper!
|
||||
HttpRouter::Rack.override_rack_builder!
|
||||
|
||||
map('/get/:id') { |env|
|
||||
[200, {'Content-type' => 'text/plain'}, ["My id is #{env['router.params'][:id]}\n"]]
|
||||
|
@ -14,9 +14,9 @@ map('/get/:id', :matching => {:id => /\d+/}) { |env|
|
|||
[200, {'Content-type' => 'text/plain'}, ["My id is #{env['router.params'][:id]}, which is a number\n"]]
|
||||
}
|
||||
|
||||
# crapbook-pro:~ joshua$ curl http://127.0.0.1:3000/get/foo
|
||||
# My id is foo
|
||||
# crapbook-pro:~ joshua$ curl -X POST http://127.0.0.1:3000/get/foo
|
||||
# My id is foo and you posted!
|
||||
# crapbook-pro:~ joshua$ curl -X POST http://127.0.0.1:3000/get/123
|
||||
# My id is 123, which is a number
|
||||
# $ curl http://127.0.0.1:3000/get/foo
|
||||
# => My id is foo
|
||||
# $ curl -X POST http://127.0.0.1:3000/get/foo
|
||||
# => My id is foo and you posted!
|
||||
# $ curl -X POST http://127.0.0.1:3000/get/123
|
||||
# => My id is 123, which is a number
|
||||
|
|
|
@ -4,5 +4,5 @@ run HttpRouter.new {
|
|||
get('/hi').to { |env| [200, {'Content-type' => 'text/plain'}, ["hi!\n"]]}
|
||||
}
|
||||
|
||||
# crapbook-pro:~ joshua$ curl http://127.0.0.1:3000/hi
|
||||
# hi!
|
||||
# $ curl http://127.0.0.1:3000/hi
|
||||
# => hi!
|
||||
|
|
|
@ -5,22 +5,22 @@ require 'http_router'
|
|||
base = File.expand_path(File.dirname(__FILE__))
|
||||
|
||||
run HttpRouter.new {
|
||||
get('/favicon.ico').static("#{base}/favicon.ico") # from a single file
|
||||
get('/images').static("#{base}/images") # or from a directory
|
||||
add('/favicon.ico').static("#{base}/favicon.ico") # from a single file
|
||||
add('/images').static("#{base}/images") # or from a directory
|
||||
}
|
||||
|
||||
# crapbook-pro:~ joshua$ curl -I http://localhost:3000/favicon.ico
|
||||
# HTTP/1.1 200 OK
|
||||
# Last-Modified: Fri, 11 Jun 2010 21:02:22 GMT
|
||||
# Content-Type: image/vnd.microsoft.icon
|
||||
# Content-Length: 1150
|
||||
# Connection: keep-alive
|
||||
# Server: thin 1.2.7 codename No Hup
|
||||
# $ curl -I http://localhost:3000/favicon.ico
|
||||
# => HTTP/1.1 200 OK
|
||||
# => Last-Modified: Sat, 26 Mar 2011 18:04:26 GMT
|
||||
# => Content-Type: image/vnd.microsoft.icon
|
||||
# => Content-Length: 1150
|
||||
# => Connection: keep-alive
|
||||
# => Server: thin 1.2.7 codename No Hup
|
||||
#
|
||||
# crapbook-pro:~ joshua$ curl -I http://localhost:3000/images/cat1.jpg
|
||||
# HTTP/1.1 200 OK
|
||||
# Last-Modified: Fri, 11 Jun 2010 21:54:16 GMT
|
||||
# Content-Type: image/jpeg
|
||||
# Content-Length: 29817
|
||||
# Connection: keep-alive
|
||||
# Server: thin 1.2.7 codename No Hup
|
||||
# $ curl -I http://localhost:3000/images/cat1.jpg
|
||||
# => HTTP/1.1 200 OK
|
||||
# => Last-Modified: Sat, 26 Mar 2011 18:04:26 GMT
|
||||
# => Content-Type: image/jpeg
|
||||
# => Content-Length: 29817
|
||||
# => Connection: keep-alive
|
||||
# => Server: thin 1.2.7 codename No Hup
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
require 'http_router'
|
||||
|
||||
run HttpRouter.new {
|
||||
get('/:').to { |env| [200, {'Content-type' => 'text/plain'}, ["my variables are\n#{env['router.params'].inspect}\n"]]}
|
||||
}
|
||||
|
||||
# crapbook-pro:~ joshua$ curl http://127.0.0.1:3000/heyguys
|
||||
# my variables are
|
||||
# {:$1=>"heyguys"}
|
|
@ -4,6 +4,6 @@ run HttpRouter.new {
|
|||
get('/:variable').to { |env| [200, {'Content-type' => 'text/plain'}, ["my variables are\n#{env['router.params'].inspect}\n"]]}
|
||||
}
|
||||
|
||||
# crapbook-pro:~ joshua$ curl http://127.0.0.1:3000/heyguys
|
||||
# my variables are
|
||||
# {:variable=>"heyguys"}
|
||||
# $ curl http://127.0.0.1:3000/heyguys
|
||||
# => my variables are
|
||||
# => {:variable=>"heyguys"}
|
||||
|
|
|
@ -4,7 +4,7 @@ run HttpRouter.new {
|
|||
get('/get/:id').matching(:id => /\d+/).to { |env| [200, {'Content-type' => 'text/plain'}, ["id is #{Integer(env['router.params'][:id]) * 2} * 2\n"]]}
|
||||
}
|
||||
|
||||
# crapbook-pro:~ joshua$ curl http://127.0.0.1:3000/get/123
|
||||
# id is 246 * 2
|
||||
# crapbook-pro:~ joshua$ curl http://127.0.0.1:3000/get/asd
|
||||
# Not Found
|
||||
# $ curl http://127.0.0.1:3000/get/123
|
||||
# => id is 246 * 2
|
||||
# $ curl http://127.0.0.1:3000/get/asd
|
||||
# => Your request couldn't be found
|
||||
|
|
|
@ -5,6 +5,7 @@ require 'http_router/request'
|
|||
require 'http_router/response'
|
||||
require 'http_router/route'
|
||||
require 'http_router/path'
|
||||
require 'http_router/rack'
|
||||
require 'http_router/regex_route'
|
||||
require 'http_router/optional_compiler'
|
||||
|
||||
|
@ -110,7 +111,7 @@ class HttpRouter
|
|||
# the default application will be called. The router will be available in the env under the key <tt>router</tt>. And parameters matched will
|
||||
# be available under the key <tt>router.params</tt>.
|
||||
def call(env, perform_call = true)
|
||||
rack_request = Rack::Request.new(env)
|
||||
rack_request = ::Rack::Request.new(env)
|
||||
if redirect_trailing_slash? && (rack_request.head? || rack_request.get?) && rack_request.path_info[-1] == ?/
|
||||
response = ::Rack::Response.new
|
||||
response.redirect(request.path_info[0, request.path_info.size - 1], 302)
|
||||
|
@ -120,7 +121,7 @@ class HttpRouter
|
|||
response = catch(:success) { @root[request] }
|
||||
if !response
|
||||
supported_methods = (@known_methods - [env['REQUEST_METHOD']]).select do |m|
|
||||
test_env = Rack::Request.new(rack_request.env.clone)
|
||||
test_env = ::Rack::Request.new(rack_request.env.clone)
|
||||
test_env.env['REQUEST_METHOD'] = m
|
||||
test_env.env['_HTTP_ROUTER_405_TESTING_ACCEPTANCE'] = true
|
||||
test_request = Request.new(test_env.path_info, test_env, 405)
|
||||
|
@ -138,7 +139,7 @@ class HttpRouter
|
|||
# Resets the router to a clean state.
|
||||
def reset!
|
||||
@root = Node.new(self)
|
||||
@default_app = Proc.new{ |env| Rack::Response.new("Your request couldn't be found", 404).finish }
|
||||
@default_app = Proc.new{ |env| ::Rack::Response.new("Your request couldn't be found", 404).finish }
|
||||
@routes = []
|
||||
@named_routes = {}
|
||||
end
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
class HttpRouter
|
||||
module Rack
|
||||
autoload :URLMap, 'http_router/rack/url_map'
|
||||
autoload :Builder, 'http_router/rack/builder'
|
||||
autoload :BuilderMixin, 'http_router/rack/builder'
|
||||
|
||||
# Monkey-patches Rack::Builder to use HttpRouter.
|
||||
# See examples/rack_mapper.rb
|
||||
def self.override_rack_builder!
|
||||
::Rack::Builder.class_eval("remove_method :map; include HttpRouter::Rack::BuilderMixin")
|
||||
end
|
||||
|
||||
# Monkey-patches Rack::URLMap to use HttpRouter.
|
||||
# See examples/rack_mapper.rb
|
||||
def self.override_rack_urlmap!
|
||||
::Rack.class_eval("OriginalURLMap = URLMap; HttpRouterURLMap = HttpRouter::Rack::URLMap; remove_const :URLMap; URLMap = HttpRouterURLMap")
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,69 @@
|
|||
require 'http_router'
|
||||
|
||||
# Replacement for {Rack::Builder} which using HttpRouter to map requests instead of a simple Hash.
|
||||
# As well, add convenience methods for the request methods.
|
||||
module HttpRouter::Rack::BuilderMixin
|
||||
def router
|
||||
@router ||= HttpRouter.new
|
||||
end
|
||||
|
||||
# Maps a path to a block.
|
||||
# @param path [String] Path to map to.
|
||||
# @param options [Hash] Options for added path.
|
||||
# @see HttpRouter#add
|
||||
def map(path, options = {}, method = nil, &block)
|
||||
route = router.add(path, options)
|
||||
route.send(method) if method
|
||||
route.to(&block)
|
||||
@ins << router unless @ins.last == router
|
||||
route
|
||||
end
|
||||
|
||||
# Maps a path with request methods `HEAD` and `GET` to a block.
|
||||
# @param path [String] Path to map to.
|
||||
# @param options [Hash] Options for added path.
|
||||
# @see HttpRouter#add
|
||||
def get(path, options = {}, &block)
|
||||
map(path, options, :get, &block)
|
||||
end
|
||||
|
||||
# Maps a path with request methods `POST` to a block.
|
||||
# @param path [String] Path to map to.
|
||||
# @param options [Hash] Options for added path.
|
||||
# @see HttpRouter#add
|
||||
def post(path, options = {}, &block)
|
||||
map(path, options, :post, &block)
|
||||
end
|
||||
|
||||
# Maps a path with request methods `PUT` to a block.
|
||||
# @param path [String] Path to map to.
|
||||
# @param options [Hash] Options for added path.
|
||||
# @see HttpRouter#add
|
||||
def put(path, options = {}, &block)
|
||||
map(path, options, :put, &block)
|
||||
end
|
||||
|
||||
# Maps a path with request methods `DELETE` to a block.
|
||||
# @param path [String] Path to map to.
|
||||
# @param options [Hash] Options for added path.
|
||||
# @see HttpRouter#add
|
||||
def delete(path, options = {}, &block)
|
||||
map(path, options, :delete, &block)
|
||||
end
|
||||
|
||||
# Maps a path with request methods `HEAD` to a block.
|
||||
# @param path [String] Path to map to.
|
||||
# @param options [Hash] Options for added path.
|
||||
# @see HttpRouter#add
|
||||
def head(path, options = {}, &block)
|
||||
map(path, options, :head, &block)
|
||||
end
|
||||
|
||||
def options(path, options = {}, &block)
|
||||
map(path, options, :options, &block)
|
||||
end
|
||||
end
|
||||
|
||||
class HttpRouter::Rack::Builder < ::Rack::Builder
|
||||
include HttpRouter::Rack::BuilderMixin
|
||||
end
|
|
@ -0,0 +1,16 @@
|
|||
require 'http_router'
|
||||
|
||||
class HttpRouter
|
||||
module Rack
|
||||
class URLMap < ::Rack::URLMap
|
||||
def initialize(map = {})
|
||||
@router = HttpRouter.new
|
||||
map.each { |path, app| (path =~ /^(https?):\/\/(.*?)(\/.*)/ ? @router.add($3).host($2).scheme($1) : @router.add(path)).partial.to(app) }
|
||||
end
|
||||
|
||||
def call(env)
|
||||
@router.call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -12,6 +12,7 @@ class HttpRouter
|
|||
@arbitrary = opts[:arbitrary] || opts[:__arbitrary__]
|
||||
@conditions = opts[:conditions] || opts[:__conditions__] || {}
|
||||
name(opts.delete(:name)) if opts.key?(:name)
|
||||
@opts.merge!(opts[:matching]) if opts[:matching]
|
||||
@matches_with = {}
|
||||
@default_values = opts[:default_values] || {}
|
||||
if @original_path[-1] == ?*
|
||||
|
|
|
@ -107,12 +107,15 @@ class TestVariable < MiniTest::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_regex_and_greedy
|
||||
with_regex, without_regex = router {
|
||||
with_regex, without_regex, with_post = router {
|
||||
add("/:common_variable/:matched").matching(:matched => /\d+/)
|
||||
add("/:common_variable/:unmatched")
|
||||
post("/:common_variable/:unmatched")
|
||||
}
|
||||
assert_route with_regex, '/common/123', {:common_variable => 'common', :matched => '123'}
|
||||
assert_route without_regex, '/common/other', {:common_variable => 'common', :unmatched => 'other'}
|
||||
assert_route with_regex, Rack::MockRequest.env_for('/common/123', :method => 'POST'), {:common_variable => 'common', :matched => '123'}
|
||||
assert_route with_post, Rack::MockRequest.env_for('/common/other', :method => 'POST'), {:common_variable => 'common', :unmatched => 'other'}
|
||||
end
|
||||
|
||||
if //.respond_to?(:names)
|
||||
|
|
Loading…
Reference in New Issue