first pass
This commit is contained in:
parent
cd68d13696
commit
6c7285f9ca
|
@ -1,7 +1,7 @@
|
|||
require 'http_router'
|
||||
HttpRouter::Rack.override_rack_builder!
|
||||
|
||||
map('/get/:id', :matching => {:id => /\d+/}) { |env|
|
||||
map('/get/:id', :match_with => {:id => /\d+/}) { |env|
|
||||
[200, {'Content-type' => 'text/plain'}, ["My id is #{env['router.params'][:id]}, which is a number\n"]]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require 'http_router'
|
||||
|
||||
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"]]}
|
||||
get('/get/:id', :id => /\d+/).to { |env| [200, {'Content-type' => 'text/plain'}, ["id is #{Integer(env['router.params'][:id]) * 2} * 2\n"]]}
|
||||
}
|
||||
|
||||
# $ curl http://127.0.0.1:3000/get/123
|
||||
|
|
|
@ -20,12 +20,12 @@ class HttpRouter
|
|||
InvalidRouteException = Class.new(RuntimeError)
|
||||
# Raised when a Route is not able to be generated due to a missing parameter.
|
||||
MissingParameterException = Class.new(RuntimeError)
|
||||
# Raised when a Route is compiled twice
|
||||
DoubleCompileError = Class.new(RuntimeError)
|
||||
# Raised an invalid request value is used
|
||||
InvalidRequestValueError = Class.new(RuntimeError)
|
||||
# Raised when there are extra parameters passed in to #url
|
||||
TooManyParametersException = Class.new(RuntimeError)
|
||||
# Raised when there are left over options
|
||||
LeftOverOptions = Class.new(RuntimeError)
|
||||
|
||||
# Creates a new HttpRouter.
|
||||
# Can be called with either <tt>HttpRouter.new(proc{|env| ... }, { .. options .. })</tt> or with the first argument omitted.
|
||||
|
@ -62,6 +62,7 @@ class HttpRouter
|
|||
#
|
||||
# Returns the route object.
|
||||
def add(*args, &app)
|
||||
uncompile
|
||||
opts = args.last.is_a?(Hash) ? args.pop : {}
|
||||
path = args.first
|
||||
route = add_route((Regexp === path ? RegexRoute : Route).new(self, path, opts))
|
||||
|
@ -114,15 +115,10 @@ 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)
|
||||
request = Request.new(rack_request.path_info, rack_request, perform_call)
|
||||
response = catch(:success) { @root[request] }
|
||||
if perform_call
|
||||
response or no_response(env)
|
||||
else
|
||||
request.matches.empty? ? nil : request.matches
|
||||
end
|
||||
compile
|
||||
call(env, perform_call)
|
||||
end
|
||||
alias_method :compiling_call, :call
|
||||
|
||||
# Resets the router to a clean state.
|
||||
def reset!
|
||||
|
@ -140,7 +136,7 @@ class HttpRouter
|
|||
#
|
||||
# Example:
|
||||
# router = HttpRouter.new
|
||||
# router.add('/:foo.:format').name(:test).to{|env| [200, {}, []]}
|
||||
# router.add('/:foo.:format', :name => :test).to{|env| [200, {}, []]}
|
||||
# router.url(:test, 123, 'html')
|
||||
# # ==> "/123.html"
|
||||
# router.url(:test, 123, :format => 'html')
|
||||
|
@ -150,12 +146,10 @@ class HttpRouter
|
|||
# router.url(:test, :foo => 123, :format => 'html', :fun => 'inthesun')
|
||||
# # ==> "/123.html?fun=inthesun"
|
||||
def url(route, *args)
|
||||
case route
|
||||
when Symbol then @named_routes.key?(route) && @named_routes[route].each{|r| url = r.url(*args); return url if url}
|
||||
when Route then return route.url(*args)
|
||||
end
|
||||
raise(InvalidRouteException)
|
||||
compile
|
||||
raw_url(route, *args)
|
||||
end
|
||||
alias_method :compiling_url, :url
|
||||
|
||||
# This method is invoked when a Path object gets called with an env. Override it to implement custom path processing.
|
||||
def process_destination_path(path, env)
|
||||
|
@ -184,7 +178,6 @@ class HttpRouter
|
|||
@routes.each do |route|
|
||||
new_route = route.clone(cloned_router)
|
||||
cloned_router.add_route(new_route)
|
||||
new_route.name(route.named) if route.named
|
||||
begin
|
||||
new_route.to route.dest.clone
|
||||
rescue
|
||||
|
@ -218,6 +211,7 @@ class HttpRouter
|
|||
end
|
||||
|
||||
def to_s
|
||||
compile
|
||||
"#<HttpRouter:0x#{object_id.to_s(16)} number of routes (#{routes.size}) ignore_trailing_slash? (#{ignore_trailing_slash?}) redirect_trailing_slash? (#{redirect_trailing_slash?}) known_methods (#{known_methods.to_a.join(', ')})>"
|
||||
end
|
||||
|
||||
|
@ -226,9 +220,44 @@ class HttpRouter
|
|||
"#{to_s}\n#{'=' * head.size}\n#{@root.inspect}"
|
||||
end
|
||||
|
||||
def compile
|
||||
return if @compiled
|
||||
@routes.each {|r| r.send(:compile)}
|
||||
instance_eval "undef :url; alias :url :raw_url", __FILE__, __LINE__
|
||||
instance_eval "undef :call; alias :call :raw_call", __FILE__, __LINE__
|
||||
@compiled = true
|
||||
end
|
||||
|
||||
def uncompile
|
||||
return unless @compiled
|
||||
instance_eval "undef :url; alias :url :compiling_url", __FILE__, __LINE__
|
||||
instance_eval "undef :call; alias :call :compiling_call", __FILE__, __LINE__
|
||||
@compiled = false
|
||||
end
|
||||
|
||||
def raw_url(route, *args)
|
||||
case route
|
||||
when Symbol then @named_routes.key?(route) && @named_routes[route].each{|r| url = r.url(*args); return url if url}
|
||||
when Route then return route.url(*args)
|
||||
end
|
||||
raise(InvalidRouteException)
|
||||
end
|
||||
|
||||
def raw_call(env, perform_call = true)
|
||||
rack_request = ::Rack::Request.new(env)
|
||||
request = Request.new(rack_request.path_info, rack_request, perform_call)
|
||||
response = catch(:success) { @root[request] }
|
||||
if perform_call
|
||||
response or no_response(env)
|
||||
else
|
||||
request.matches.empty? ? nil : request.matches
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def add_with_request_method(path, method, opts = {}, &app)
|
||||
route = add(path, opts).send(method.to_sym)
|
||||
opts[:request_method] = method
|
||||
route = add(path, opts)
|
||||
route.to(app) if app
|
||||
route
|
||||
end
|
||||
|
|
|
@ -54,7 +54,7 @@ class HttpRouter
|
|||
end
|
||||
|
||||
def inspect_label
|
||||
"Path: #{original_path.inspect} for route #{route.named || 'unnamed route'} to #{route.dest.inspect}"
|
||||
"Path: #{original_path.inspect} for route #{route.name || 'unnamed route'} to #{route.dest.inspect}"
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -38,6 +38,7 @@ class HttpRouter
|
|||
|
||||
private
|
||||
def compile
|
||||
router.send(:compile)
|
||||
root.extend(root.methods_module)
|
||||
instance_eval "def [](request)\n#{to_code}\nnil\nend", __FILE__, __LINE__
|
||||
@compiled = true
|
||||
|
|
|
@ -12,8 +12,7 @@ module HttpRouter::Rack::BuilderMixin
|
|||
# @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 = router.send(method || :add, path, options)
|
||||
route.to(&block)
|
||||
@ins << router unless @ins.last == router
|
||||
route
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
class HttpRouter
|
||||
class RegexRoute < Route
|
||||
def initialize(router, path, opts = {})
|
||||
def initialize(router, path, opts = nil)
|
||||
@router, @original_path, @opts = router, path, opts
|
||||
@param_names = @original_path.respond_to?(:names) ? @original_path.names.map(&:to_sym) : []
|
||||
@path_validation_regex = original_path
|
||||
Util.add_path_generation(self, self, opts.delete(:path_for_generation), @original_path) if opts.key?(:path_for_generation)
|
||||
process_opts
|
||||
process_opts if opts
|
||||
end
|
||||
|
||||
def add_path_to_tree
|
||||
def compile
|
||||
@paths = [@original_path]
|
||||
add_non_path_to_tree(@router.root.add_free_match(@original_path), path, @param_names)
|
||||
add_non_path_to_tree(@router.root.add_free_match(@original_path), @original_path, @param_names)
|
||||
end
|
||||
|
||||
def significant_variable_names
|
||||
|
|
|
@ -1,92 +1,24 @@
|
|||
class HttpRouter
|
||||
class Route
|
||||
attr_reader :default_values, :router, :path, :conditions, :original_path, :match_partially, :dest, :regex, :named, :matches_with
|
||||
attr_reader :default_values, :router, :conditions, :original_path, :match_partially, :dest, :regex, :name, :matches_with, :app
|
||||
alias_method :dest, :app
|
||||
alias_method :match_partially?, :match_partially
|
||||
alias_method :regex?, :regex
|
||||
|
||||
def initialize(router, path, opts = {})
|
||||
@router, @original_path, @opts = router, path, opts
|
||||
if @original_path
|
||||
@match_partially = true and path.slice!(-1) if @original_path[/[^\\]\*$/]
|
||||
@original_path[0, 0] = '/' if @original_path[0] != ?/
|
||||
else
|
||||
@match_partially = true
|
||||
end
|
||||
process_opts
|
||||
def initialize(router, original_path, opts = nil)
|
||||
@router, @original_path, @opts = router, original_path, opts
|
||||
process_path
|
||||
process_opts if opts
|
||||
process_match_with
|
||||
post_process
|
||||
end
|
||||
|
||||
def process_opts
|
||||
@default_values = @opts[:__default_values__] || @opts[:default_values] || {}
|
||||
@arbitrary = @opts[:__arbitrary__] || @opts[:arbitrary]
|
||||
@matches_with = significant_variable_names.include?(:matching) ? @opts : @opts[:__matching__] || @opts[:matching] || {}
|
||||
significant_variable_names.each do |name|
|
||||
@matches_with[name] = @opts[name] if @opts.key?(name) && !@matches_with.key?(name)
|
||||
end
|
||||
@conditions = @opts[:__conditions__] || @opts[:conditions] || {}
|
||||
@match_partially = @opts[:__partial__] if @match_partially.nil? && !@opts[:__partial__].nil?
|
||||
@match_partially = @opts[:partial] if @match_partially.nil? && !@opts[:partial].nil?
|
||||
name(@opts[:__name__] || @opts[:name]) if @opts.key?(:__name__) || @opts.key?(:name)
|
||||
@needed_keys = significant_variable_names - @default_values.keys
|
||||
def name=(name)
|
||||
@name = name
|
||||
@router.named_routes[name] << self
|
||||
@router.named_routes[name].sort!{|r1, r2| r2.significant_variable_names.size <=> r1.significant_variable_names.size }
|
||||
end
|
||||
|
||||
def as_options
|
||||
{:__matching__ => @matches_with, :__conditions__ => @conditions, :__default_values__ => @default_values, :__name__ => @named, :__partial__ => @partially_match, :__arbitrary__ => @arbitrary}
|
||||
end
|
||||
|
||||
def compiled?
|
||||
!@paths.nil?
|
||||
end
|
||||
|
||||
def partial(match_partially = true)
|
||||
@match_partially = match_partially
|
||||
self
|
||||
end
|
||||
|
||||
def to(dest = nil, &dest2)
|
||||
@dest = dest || dest2
|
||||
add_path_to_tree
|
||||
self
|
||||
end
|
||||
|
||||
def name(n)
|
||||
@named = n
|
||||
@router.named_routes[n] << self
|
||||
@router.named_routes[n].sort!{|r1, r2| r2.significant_variable_names.size <=> r1.significant_variable_names.size }
|
||||
self
|
||||
end
|
||||
|
||||
def request_method(*method)
|
||||
add_to_contitions(:request_method, method)
|
||||
end
|
||||
|
||||
def host(*host)
|
||||
add_to_contitions(:host, host)
|
||||
end
|
||||
|
||||
def scheme(*scheme)
|
||||
add_to_contitions(:scheme, scheme)
|
||||
end
|
||||
|
||||
def user_agent(*user_agent)
|
||||
add_to_contitions(:user_agent, user_agent)
|
||||
end
|
||||
|
||||
def add_to_contitions(name, *vals)
|
||||
((@conditions ||= {})[name] ||= []).concat(vals.flatten)
|
||||
self
|
||||
end
|
||||
|
||||
def matching(matchers)
|
||||
@matches_with.merge!(matchers.is_a?(Array) ? Hash[*matchers] : matchers)
|
||||
self
|
||||
end
|
||||
|
||||
def default(defaults)
|
||||
(@default_values ||= {}).merge!(defaults)
|
||||
self
|
||||
end
|
||||
|
||||
# Sets the destination of this route to redirect to an arbitrary URL.
|
||||
def redirect(path, status = 302)
|
||||
raise ArgumentError, "Status has to be an integer between 300 and 399" unless (300..399).include?(status)
|
||||
to { |env|
|
||||
|
@ -95,38 +27,31 @@ class HttpRouter
|
|||
response.redirect(eval(%|"#{path}"|), status)
|
||||
response.finish
|
||||
}
|
||||
self
|
||||
end
|
||||
|
||||
# Sets the destination of this route to serve static files from either a directory or a single file.
|
||||
def static(root)
|
||||
if File.directory?(root)
|
||||
partial.to ::Rack::File.new(root)
|
||||
else
|
||||
to {|env| env['PATH_INFO'] = File.basename(root); ::Rack::File.new(File.dirname(root)).call(env) }
|
||||
@match_partially = true if File.directory?(root)
|
||||
to File.directory?(root) ?
|
||||
::Rack::File.new(root) :
|
||||
proc {|env|
|
||||
env['PATH_INFO'] = File.basename(root)
|
||||
::Rack::File.new(File.dirname(root)).call(env)
|
||||
}
|
||||
end
|
||||
|
||||
def to(app = nil, &app2)
|
||||
@app = app || app2 || raise("you didn't specify a destination")
|
||||
if @app.respond_to?(:url_mount=)
|
||||
urlmount = UrlMount.new(original_path, @default_values || {})
|
||||
urlmount.url_mount = router.url_mount if router.url_mount
|
||||
dest.url_mount = urlmount
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def post; request_method('POST'); end
|
||||
def get; request_method('GET'); end
|
||||
def put; request_method('PUT'); end
|
||||
def delete; request_method('DELETE'); end
|
||||
def head; request_method('HEAD'); end
|
||||
def options; request_method('OPTIONS'); end
|
||||
def patch; request_method('PATCH'); end
|
||||
def trace; request_method('TRACE'); end
|
||||
def conenct; request_method('CONNECT'); end
|
||||
|
||||
def arbitrary(blk = nil, &blk2)
|
||||
arbitrary_with_continue { |req, params|
|
||||
req.continue[(blk || blk2)[req, params]]
|
||||
}
|
||||
end
|
||||
|
||||
def arbitrary_with_continue(blk = nil, &blk2)
|
||||
(@arbitrary ||= []) << (blk || blk2)
|
||||
self
|
||||
def as_options
|
||||
{:__match_with__ => @matches_with, :__conditions__ => @conditions, :__default_values__ => @default_values, :__name__ => @name, :__partial__ => @partially_match}
|
||||
end
|
||||
|
||||
def url(*args)
|
||||
|
@ -135,7 +60,7 @@ class HttpRouter
|
|||
end
|
||||
|
||||
def clone(new_router)
|
||||
Route.new(new_router, @original_path.dup, as_options)
|
||||
Route.new(new_router, @original_path.dup, as_options).to(@app)
|
||||
end
|
||||
|
||||
def url_with_params(*a)
|
||||
|
@ -151,7 +76,7 @@ class HttpRouter
|
|||
options = options.nil? ? default_values.dup : default_values.merge(options) if default_values
|
||||
options.delete_if{ |k,v| v.nil? } if options
|
||||
result, params = yield args, options
|
||||
mount_point = router.url_mount && router.url_mount.url(options)
|
||||
mount_point = router.url_mount && (options ? router.url_mount.url(options) : router.url_mount.url)
|
||||
mount_point ? [File.join(mount_point, result), params] : [result, params]
|
||||
end
|
||||
|
||||
|
@ -162,24 +87,68 @@ class HttpRouter
|
|||
def matching_path(params, other_hash = nil)
|
||||
return @paths.first if @paths.size == 1
|
||||
case params
|
||||
when Array
|
||||
when Array, nil
|
||||
significant_keys = other_hash && significant_variable_names & other_hash.keys
|
||||
@paths.find { |path| path.param_names.size == (significant_keys ? params.size + significant_keys.size : params.size) }
|
||||
@paths.find { |path|
|
||||
params_size = params ? params.size : 0
|
||||
path.param_names.size == (significant_keys ? (params_size) + significant_keys.size : params_size) }
|
||||
when Hash
|
||||
@paths.find { |path| (params && !params.empty? && (path.param_names & params.keys).size == path.param_names.size) || path.param_names.empty? }
|
||||
end
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#<HttpRouter:Route #{object_id} @original_path=#{@original_path.inspect} @conditions=#{@conditions.inspect} @arbitrary=#{@arbitrary.inspect}>"
|
||||
"#<HttpRouter:Route #{object_id} @original_path=#{@original_path.inspect} @conditions=#{@conditions.inspect}>"
|
||||
end
|
||||
|
||||
private
|
||||
def add_to_contitions(name, *vals)
|
||||
((@conditions ||= {})[name] ||= []).concat(vals.flatten)
|
||||
self
|
||||
end
|
||||
|
||||
def process_path
|
||||
@path_for_processing = @original_path && @original_path.dup
|
||||
if @path_for_processing
|
||||
@match_partially = true and @path_for_processing.slice!(-1) if @path_for_processing[/[^\\]\*$/]
|
||||
@path_for_processing[0, 0] = '/' if @path_for_processing[0] != ?/
|
||||
else
|
||||
@match_partially = true
|
||||
end
|
||||
end
|
||||
|
||||
def post_process
|
||||
raise LeftOverOptions.new("There are still options left, #{@opts.inspect}") unless @opts.empty?
|
||||
end
|
||||
|
||||
def process_opts
|
||||
@default_values = @opts.delete(:__default_values__) || @opts.delete(:default_values)
|
||||
@matches_with = significant_variable_names.include?(:match_with) ?
|
||||
@opts :
|
||||
@opts.delete(:__match_with__) || @opts.delete(:match_with)
|
||||
@conditions = @opts.delete(:__conditions__) || @opts.delete(:conditions)
|
||||
if @match_partially.nil?
|
||||
@match_partially = @opts.delete(:__partial__) if @opts.key?(:__partial__)
|
||||
@match_partially = @opts.delete(:partial) if @opts.key?(:partial) && match_partially.nil?
|
||||
end
|
||||
self.name = @opts.delete(:__name__) || @opts.delete(:name)
|
||||
add_to_contitions :request_method, @opts.delete(:request_method) if @opts.key?(:request_method)
|
||||
add_to_contitions :host, @opts.delete(:host) if @opts.key?(:host)
|
||||
add_to_contitions :scheme, @opts.delete(:scheme) if @opts.key?(:scheme)
|
||||
add_to_contitions :user_agent, @opts.delete(:user_agent) if @opts.key?(:user_agent)
|
||||
end
|
||||
|
||||
def process_match_with
|
||||
significant_variable_names.each do |name|
|
||||
(@matches_with ||= {})[name] = @opts.delete(name) if @opts.key?(name) && (@matches_with.nil? || !@matches_with.key?(name))
|
||||
end
|
||||
end
|
||||
|
||||
def raw_paths
|
||||
return [] if @original_path.nil?
|
||||
@raw_paths ||= begin
|
||||
start_index, end_index = 0, 1
|
||||
@raw_paths, chars = [""], @original_path.split('')
|
||||
@raw_paths, chars = [""], @path_for_processing.split('')
|
||||
until chars.empty?
|
||||
case fc = chars.first[0]
|
||||
when ?(
|
||||
|
@ -206,10 +175,10 @@ class HttpRouter
|
|||
node.add_lookup(part[1].chr)
|
||||
when ?:
|
||||
param_names << name.to_sym
|
||||
@matches_with[name.to_sym] ? node.add_spanning_match(@matches_with[name.to_sym]) : node.add_variable
|
||||
@matches_with && @matches_with[name.to_sym] ? node.add_spanning_match(@matches_with[name.to_sym]) : node.add_variable
|
||||
when ?*
|
||||
param_names << name.to_sym
|
||||
@matches_with[name.to_sym] ? node.add_glob_regexp(@matches_with[name.to_sym]) : node.add_glob
|
||||
@matches_with && @matches_with[name.to_sym] ? node.add_glob_regexp(@matches_with[name.to_sym]) : node.add_glob
|
||||
else
|
||||
node.add_lookup(part)
|
||||
end
|
||||
|
@ -227,9 +196,9 @@ class HttpRouter
|
|||
name = part[1, part.size].to_sym
|
||||
param_names << name
|
||||
if spans
|
||||
@matches_with[name] ? "((?:#{@matches_with[name]}\\/?)+)" : '(.*?)'
|
||||
@matches_with && @matches_with[name] ? "((?:#{@matches_with[name]}\\/?)+)" : '(.*?)'
|
||||
else
|
||||
"(#{(@matches_with[name] || '[^/]*?')})"
|
||||
"(#{(@matches_with && @matches_with[name] || '[^/]*?')})"
|
||||
end
|
||||
else
|
||||
Regexp.quote(part)
|
||||
|
@ -239,35 +208,26 @@ class HttpRouter
|
|||
node.add_match(Regexp.new("#{regex}$"), capturing_indicies, splitting_indicies)
|
||||
end
|
||||
|
||||
def add_path_to_tree
|
||||
raise DoubleCompileError if compiled?
|
||||
@paths ||= begin
|
||||
if raw_paths.empty?
|
||||
add_non_path_to_tree(@router.root, nil, [])
|
||||
else
|
||||
raw_paths.map do |path|
|
||||
param_names = []
|
||||
node = @router.root
|
||||
path.split(/\//).each do |part|
|
||||
next if part == ''
|
||||
parts = part.scan(/\\.|[:*][a-z0-9_]+|[^:*\\]+/)
|
||||
node = parts.size == 1 ? add_normal_part(node, part, param_names) : add_complex_part(node, parts, param_names)
|
||||
end
|
||||
add_non_path_to_tree(node, path, param_names)
|
||||
def compile
|
||||
@paths = if raw_paths.empty?
|
||||
add_non_path_to_tree(@router.root, nil, [])
|
||||
else
|
||||
raw_paths.map do |path|
|
||||
param_names = []
|
||||
node = @router.root
|
||||
path.split(/\//).each do |part|
|
||||
next if part == ''
|
||||
parts = part.scan(/\\.|[:*][a-z0-9_]+|[^:*\\]+/)
|
||||
node = parts.size == 1 ? add_normal_part(node, part, param_names) : add_complex_part(node, parts, param_names)
|
||||
end
|
||||
add_non_path_to_tree(node, path, param_names)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def add_non_path_to_tree(node, path, names)
|
||||
node = node.add_request(@conditions) unless @conditions.empty?
|
||||
@arbitrary.each{|a| node = node.add_arbitrary(a, match_partially?, names)} if @arbitrary
|
||||
node = node.add_request(@conditions) if @conditions && !@conditions.empty?
|
||||
path_obj = node.add_destination(self, path, names)
|
||||
if dest.respond_to?(:url_mount=)
|
||||
urlmount = UrlMount.new(@original_path, @default_values)
|
||||
urlmount.url_mount = router.url_mount if router.url_mount
|
||||
dest.url_mount = urlmount
|
||||
end
|
||||
path_obj
|
||||
end
|
||||
|
||||
|
@ -275,7 +235,7 @@ class HttpRouter
|
|||
case value
|
||||
when Array then value.each{ |v| append_querystring_value(uri, "#{key}[]", v) }
|
||||
when Hash then value.each{ |k, v| append_querystring_value(uri, "#{key}[#{k}]", v) }
|
||||
else uri << '&' << CGI.escape(key.to_s) << '=' << CGI.escape(value.to_s)
|
||||
else uri << "&#{CGI.escape(key.to_s)}=#{CGI.escape(value.to_s)}"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ class HttpRouter
|
|||
code << part
|
||||
dynamic = true
|
||||
else
|
||||
regex << (route.matches_with[part[1, part.size].to_sym] || '.*?').to_s unless path_validation_regex
|
||||
regex << (route.matches_with && route.matches_with[part[1, part.size].to_sym] || '.*?').to_s unless path_validation_regex
|
||||
code << "\#{args.shift || (options && options.delete(:#{part[1, part.size]})) || return}"
|
||||
dynamic = true
|
||||
end
|
||||
|
|
|
@ -83,11 +83,11 @@ class AbstractTest
|
|||
@routes.case.each do |route_definition|
|
||||
error("Too many keys! #{route_definition.keys.inspect}") unless route_definition.keys.size == 1
|
||||
route_name, route_properties = route_definition.keys.first, route_definition.values.first
|
||||
opts = {:name => route_name.to_sym}
|
||||
route = case route_properties
|
||||
when String
|
||||
@router.add(route_properties)
|
||||
@router.add(route_properties, opts)
|
||||
when Hash
|
||||
opts = {}
|
||||
route_path = interpret_val(route_properties.delete("path"))
|
||||
if route_properties.key?("conditions")
|
||||
opts[:conditions] = Hash[route_properties.delete("conditions").map{|k, v| [k.to_sym, interpret_val(v)]}]
|
||||
|
@ -102,7 +102,6 @@ class AbstractTest
|
|||
else
|
||||
error("Route isn't a String or hash")
|
||||
end
|
||||
route.name(route_name.to_sym)
|
||||
route.to{|env| [200, {"env-to-test" => env.dup}, [route_name]]}
|
||||
end
|
||||
run_tests
|
||||
|
|
|
@ -26,11 +26,6 @@ class TestRouteExtensions < MiniTest::Unit::TestCase
|
|||
assert_equal __FILE__, body.path
|
||||
end
|
||||
|
||||
def test_chainable
|
||||
router.get("/index.html").redirect("/").name(:root)
|
||||
assert_equal "/index.html", router.url(:root)
|
||||
end
|
||||
|
||||
def test_custom_status
|
||||
router.get("/index.html").redirect("/", 303)
|
||||
response = router.call(Rack::MockRequest.env_for("/index.html"))
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
class TestMisc < MiniTest::Unit::TestCase
|
||||
def test_cloning
|
||||
r1 = HttpRouter.new { add('/test').name(:test_route).to(:test) }
|
||||
r1 = HttpRouter.new { add('/test', :name => :test_route).to(:test) }
|
||||
r2 = r1.clone
|
||||
|
||||
r2.add('/test2').name(:test).to(:test2)
|
||||
r2.add('/test2', :name => :test).to(:test2)
|
||||
assert_equal 2, r2.routes.size
|
||||
|
||||
assert_equal nil, r1.recognize(Rack::Request.new(Rack::MockRequest.env_for('/test2')))
|
||||
|
@ -11,7 +11,7 @@ class TestMisc < MiniTest::Unit::TestCase
|
|||
assert_equal r1.routes.first, r1.named_routes[:test_route].first
|
||||
assert_equal r2.routes.first, r2.named_routes[:test_route].first
|
||||
|
||||
r1.add('/another').name(:test).to(:test2)
|
||||
r1.add('/another', :name => :test).to(:test2)
|
||||
|
||||
assert_equal r1.routes.size, r2.routes.size
|
||||
assert_equal '/another', r1.url(:test)
|
||||
|
@ -50,9 +50,9 @@ class TestMisc < MiniTest::Unit::TestCase
|
|||
|
||||
def test_multi_name_gen
|
||||
r = HttpRouter.new
|
||||
r.add('/').name(:index).default_destination
|
||||
r.add('/:name').name(:index).default_destination
|
||||
r.add('/:name/:category').name(:index).default_destination
|
||||
r.add('/', :name => :index).default_destination
|
||||
r.add('/:name', :name => :index).default_destination
|
||||
r.add('/:name/:category', :name => :index).default_destination
|
||||
assert_equal '/', r.url(:index)
|
||||
assert_equal '/name', r.url(:index, 'name')
|
||||
assert_equal '/name/category', r.url(:index, 'name', 'category')
|
||||
|
@ -60,13 +60,13 @@ class TestMisc < MiniTest::Unit::TestCase
|
|||
|
||||
def test_regex_generation
|
||||
r = HttpRouter.new
|
||||
r.add(%r|/test/.*|, :path_for_generation => '/test/:variable').name(:route).default_destination
|
||||
r.add(%r|/test/.*|, :path_for_generation => '/test/:variable', :name => :route).default_destination
|
||||
assert_equal '/test/var', r.url(:route, "var")
|
||||
end
|
||||
|
||||
def test_too_many_params
|
||||
r = HttpRouter.new
|
||||
r.add(%r|/test/.*|, :path_for_generation => '/test/:variable').name(:route).default_destination
|
||||
r.add(%r|/test/.*|, :path_for_generation => '/test/:variable', :name => :route).default_destination
|
||||
assert_equal '/test/var', r.url(:route, "var")
|
||||
assert_equal '/test/var', r.url(:route, :variable => "var")
|
||||
assert_raises(HttpRouter::InvalidRouteException) { r.url(:route) }
|
||||
|
@ -74,7 +74,7 @@ class TestMisc < MiniTest::Unit::TestCase
|
|||
|
||||
def test_too_many_args
|
||||
r = HttpRouter.new
|
||||
r.add('/').name(:route).default_destination
|
||||
r.add('/', :name => :route).default_destination
|
||||
assert_raises(HttpRouter::TooManyParametersException) { r.url(:route, "hi") }
|
||||
end
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ class TestMounting < MiniTest::Unit::TestCase
|
|||
def setup
|
||||
@r1 = HttpRouter.new
|
||||
@r2 = HttpRouter.new
|
||||
@r2.add("/bar").name(:test).to{|env| [200, {}, []]}
|
||||
@r2.add("/bar", :name => :test).to{|env| [200, {}, []]}
|
||||
end
|
||||
|
||||
def test_url_mount_for_child_route
|
||||
|
@ -12,25 +12,25 @@ class TestMounting < MiniTest::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_default_values
|
||||
route = @r1.add("/foo/:bar").default(:bar => "baz").to(@r2)
|
||||
route = @r1.add("/foo/:bar", :default_values => {:bar => "baz"}).to(@r2)
|
||||
assert_equal "/foo/baz/bar", @r2.url(:test)
|
||||
assert_equal "/foo/haha/bar", @r2.url(:test, :bar => "haha")
|
||||
end
|
||||
|
||||
def test_multiple_values
|
||||
@r1.add("/foo/:bar/:baz").default(:bar => "bar").to(@r2)
|
||||
@r1.add("/foo/:bar/:baz", :default_values => {:bar => "bar"}).to(@r2)
|
||||
assert_equal "/foo/bar/baz/bar", @r2.url(:test, :baz => "baz")
|
||||
end
|
||||
|
||||
def test_bubble_params
|
||||
route = @r1.add("/foo/:bar").default(:bar => "baz").to(@r2)
|
||||
route = @r1.add("/foo/:bar", :default_values => {:bar => 'baz'}).to(@r2)
|
||||
assert_equal "/foo/baz/bar?bang=ers", @r2.url(:test, :bang => "ers")
|
||||
assert_equal "/foo/haha/bar?bang=ers", @r2.url(:test, :bar => "haha", :bang => "ers")
|
||||
end
|
||||
|
||||
def test_path_with_optional
|
||||
@r1.add("/foo(/:bar)").to(@r2)
|
||||
@r2.add("/hey(/:there)").name(:test2).to{|env| [200, {}, []]}
|
||||
@r2.add("/hey(/:there)", :name => :test2).to{|env| [200, {}, []]}
|
||||
assert_equal "/foo/hey", @r2.url(:test2)
|
||||
assert_equal "/foo/bar/hey", @r2.url(:test2, :bar => "bar")
|
||||
assert_equal "/foo/bar/hey/there", @r2.url(:test2, :bar => "bar", :there => "there")
|
||||
|
@ -38,10 +38,10 @@ class TestMounting < MiniTest::Unit::TestCase
|
|||
|
||||
def test_nest3
|
||||
@r3 = HttpRouter.new
|
||||
@r1.add("/foo(/:bar)").default(:bar => "barry").to(@r2)
|
||||
@r2.add("/hi").name(:hi).to{|env| [200, {}, []]}
|
||||
@r1.add("/foo(/:bar)", :default_values => {:bar => 'barry'}).to(@r2)
|
||||
@r2.add("/hi", :name => :hi).to{|env| [200, {}, []]}
|
||||
@r2.add("/mounted").to(@r3)
|
||||
@r3.add("/endpoint").name(:endpoint).to{|env| [200, {}, []]}
|
||||
@r3.add("/endpoint", :name => :endpoint).to{|env| [200, {}, []]}
|
||||
|
||||
assert_equal "/foo/barry/hi", @r2.url(:hi)
|
||||
assert_equal "/foo/barry/mounted/endpoint", @r3.url(:endpoint)
|
||||
|
@ -49,7 +49,7 @@ class TestMounting < MiniTest::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_with_default_host
|
||||
@r1.add("/mounted").default(:host => "example.com").to(@r2)
|
||||
@r1.add("/mounted", :default_values => {:host => "example.com"}).to(@r2)
|
||||
assert_equal "http://example.com/mounted/bar", @r2.url(:test)
|
||||
end
|
||||
|
||||
|
|
|
@ -8,63 +8,6 @@ class TestRecognition < MiniTest::Unit::TestCase
|
|||
EOT
|
||||
end
|
||||
|
||||
def test_match
|
||||
hello, love80, love8080 = router {
|
||||
add('test').arbitrary(Proc.new{|req, params| req.rack.host == 'hellodooly' })
|
||||
add("test").arbitrary(Proc.new{|req, params| req.rack.host == 'lovelove' }).arbitrary{|req, params| req.rack.port == 80}
|
||||
add("test").arbitrary(Proc.new{|req, params| req.rack.host == 'lovelove' }).arbitrary{|req, params| req.rack.port == 8080}
|
||||
}
|
||||
assert_route love8080, 'http://lovelove:8080/test'
|
||||
end
|
||||
|
||||
def test_less_specific_node
|
||||
hello, love80, love8080, general = router {
|
||||
add("/test").arbitrary(Proc.new{|req, params| req.rack.host == 'hellodooly' })
|
||||
add("/test").arbitrary(Proc.new{|req, params| req.rack.host == 'lovelove' }).arbitrary{|req, params| req.rack.port == 80}
|
||||
add("/test").arbitrary(Proc.new{|req, params| req.rack.host == 'lovelove' }).arbitrary{|req, params| req.rack.port == 8080}
|
||||
add("/test")
|
||||
}
|
||||
assert_route general, 'http://lovelove:8081/test'
|
||||
assert_route hello, 'http://hellodooly:8081/test'
|
||||
assert_route love80, 'http://lovelove:80/test'
|
||||
assert_route love8080, 'http://lovelove:8080/test'
|
||||
end
|
||||
|
||||
def test_match_request
|
||||
love80, love8080 = router {
|
||||
add("/test").get.arbitrary(Proc.new{|req, params| req.rack.host == 'lovelove' }).arbitrary{|req, params| req.rack.port == 80}
|
||||
add("/test").get.arbitrary(Proc.new{|req, params| req.rack.host == 'lovelove' }).arbitrary{|req, params| req.rack.port == 8080}
|
||||
}
|
||||
assert_route love80, 'http://lovelove:80/test'
|
||||
assert_route love8080, 'http://lovelove:8080/test'
|
||||
end
|
||||
|
||||
def test_less_specific_with_request
|
||||
love80, love8080, general = router {
|
||||
add("test").post.arbitrary(Proc.new{|req, params| req.rack.host == 'lovelove' }).arbitrary{|req, params| req.rack.port == 80}
|
||||
add("test").post.arbitrary(Proc.new{|req, params| req.rack.host == 'lovelove' }).arbitrary{|req, params| req.rack.port == 8080}
|
||||
add("test").post
|
||||
}
|
||||
assert_route love8080, Rack::MockRequest.env_for('http://lovelove:8080/test', :method => :post)
|
||||
assert_route love80, Rack::MockRequest.env_for('http://lovelove:80/test', :method => :post)
|
||||
assert_route general, Rack::MockRequest.env_for('/test', :method => :post)
|
||||
end
|
||||
|
||||
def test_pass_params
|
||||
r = router {
|
||||
add(":test").get.arbitrary(Proc.new{|req, params, dest| params[:test] == 'test' })
|
||||
}
|
||||
assert_route r, '/test', {:test => 'test'}
|
||||
end
|
||||
|
||||
def test_continue
|
||||
no, yes = router {
|
||||
add('test').arbitrary_with_continue{|req, p| req.continue[false]}
|
||||
add('test').arbitrary_with_continue{|req, p| req.continue[true]}
|
||||
}
|
||||
assert_route yes, '/test'
|
||||
end
|
||||
|
||||
def test_passing
|
||||
passed, working = router {
|
||||
add('/').to { |env| throw :pass; [200, {}, ['pass']] }
|
||||
|
@ -90,16 +33,6 @@ class TestRecognition < MiniTest::Unit::TestCase
|
|||
assert_body 'working', router.call(Rack::MockRequest.env_for('/'))
|
||||
end
|
||||
|
||||
def test_request_mutation
|
||||
got_this_far = false
|
||||
non_matching, matching = router {
|
||||
add("/test/:var/:var2/*glob").matching(:var2 => /123/, :glob => /[a-z]+/).get.arbitrary{|env, params| got_this_far = true; false}
|
||||
add("/test/:var/:var2/*glob").matching(:var2 => /123/, :glob => /[a-z]+/).get
|
||||
}
|
||||
assert_route matching, '/test/123/123/asd/aasd/zxcqwe/asdzxc', {:var => '123', :var2 => '123', :glob => %w{asd aasd zxcqwe asdzxc}}
|
||||
assert got_this_far, "matching should have gotten this far"
|
||||
end
|
||||
|
||||
def test_compiling_uncompiling
|
||||
@router = HttpRouter.new
|
||||
root = @router.add('/').default_destination
|
||||
|
|
Loading…
Reference in New Issue