提交 2b7256a4 编写于 作者: D David Heinemeier Hansson

Extract Mapping class from monster match method

上级 74b2e00c
...@@ -19,9 +19,9 @@ def call(env) ...@@ -19,9 +19,9 @@ def call(env)
@constraints.each { |constraint| @constraints.each { |constraint|
if constraint.respond_to?(:matches?) && !constraint.matches?(req) if constraint.respond_to?(:matches?) && !constraint.matches?(req)
return [417, {}, []] return [ 417, {}, [] ]
elsif constraint.respond_to?(:call) && !constraint.call(req) elsif constraint.respond_to?(:call) && !constraint.call(req)
return [417, {}, []] return [ 417, {}, [] ]
end end
} }
...@@ -29,94 +29,138 @@ def call(env) ...@@ -29,94 +29,138 @@ def call(env)
end end
end end
module Base class Mapping
def initialize(set) def initialize(set, scope, args)
@set = set @set, @scope = set, scope
@path, @options = extract_path_and_options(args)
end end
def root(options = {}) def to_route
match '/', options.merge(:as => :root) [ app, conditions, requirements, defaults, @options[:as] ]
end end
def match(*args) private
if args.one? && args.first.is_a?(Hash) def extract_path_and_options(args)
path = args.first.keys.first
options = { :to => args.first.values.first }
else
path = args.first
options = args.extract_options! options = args.extract_options!
end
conditions, defaults = {}, {}
path = nil if path == ""
path = "#{@scope[:path]}#{path}" if @scope[:path]
path = Rack::Mount::Utils.normalize_path(path) if path
raise ArgumentError, "path is required" unless path
constraints = options[:constraints] || {} if args.empty?
unless constraints.is_a?(Hash) path, to = options.find { |name, value| name.is_a?(String) }
block, constraints = constraints, {} options.merge!(:to => to).delete(path) if path
else
path = args.first
end
[ normalize_path(path), options ]
end end
blocks = ((@scope[:blocks] || []) + [block]).compact
constraints = (@scope[:constraints] || {}).merge(constraints)
options.each { |k, v| constraints[k] = v if v.is_a?(Regexp) }
conditions[:path_info] = path def normalize_path(path)
requirements = constraints.dup path = nil if path == ""
path = "#{@scope[:path]}#{path}" if @scope[:path]
path = Rack::Mount::Utils.normalize_path(path) if path
path_regexp = Rack::Mount::Strexp.compile(path, constraints, SEPARATORS) raise ArgumentError, "path is required" unless path
segment_keys = Rack::Mount::RegexpWithNamedGroups.new(path_regexp).names
constraints.reject! { |k, v| segment_keys.include?(k.to_s) } path
conditions.merge!(constraints) end
requirements[:controller] ||= @set.controller_constraints
if via = options[:via] def app
via = Array(via).map { |m| m.to_s.upcase } Constraints.new(
conditions[:request_method] = Regexp.union(*via) to.respond_to?(:call) ? to : Routing::RouteSet::Dispatcher.new(:defaults => defaults),
blocks
)
end end
defaults[:controller] ||= @scope[:controller].to_s if @scope[:controller] def conditions
{ :path_info => @path }.merge(constraints).merge(request_method_condition)
app = initialize_app_endpoint(options, defaults) end
validate_defaults!(app, defaults, segment_keys)
app = Constraints.new(app, blocks) def requirements
@requirements ||= returning(@options[:constraints] || {}) do |requirements|
requirements.reverse_merge!(@scope[:constraints]) if @scope[:constraints]
@options.each { |k, v| requirements[k] = v if v.is_a?(Regexp) }
requirements[:controller] ||= @set.controller_constraints
end
end
@set.add_route(app, conditions, requirements, defaults, options[:as]) def defaults
@defaults ||= if to.respond_to?(:call)
{ }
else
defaults = case to
when String
controller, action = to.split('#')
{ :controller => controller, :action => action }
when Symbol
{ :controller => default_controller, :action => to.to_s }
else
{ :controller => default_controller }
end
if defaults[:controller].blank? && segment_keys.exclude?("controller")
raise ArgumentError, "missing :controller"
end
if defaults[:action].blank? && segment_keys.exclude?("action")
raise ArgumentError, "missing :action"
end
defaults
end
end
self
end def blocks
if @options[:constraints].present? && !@options[:constraints].is_a?(Hash)
block = @options[:constraints]
else
block = nil
end
((@scope[:blocks] || []) + [ block ]).compact
end
def constraints
@constraints ||= requirements.reject { |k, v| segment_keys.include?(k.to_s) || k == :controller }
end
private def request_method_condition
def initialize_app_endpoint(options, defaults) if via = @options[:via]
app = nil via = Array(via).map { |m| m.to_s.upcase }
{ :request_method => Regexp.union(*via) }
if options[:to].respond_to?(:call) else
app = options[:to] { }
defaults.delete(:controller)
defaults.delete(:action)
elsif options[:to].is_a?(String)
defaults[:controller], defaults[:action] = options[:to].split('#')
elsif options[:to].is_a?(Symbol)
defaults[:action] = options[:to].to_s
end end
end
def segment_keys
@segment_keys ||= Rack::Mount::RegexpWithNamedGroups.new(
Rack::Mount::Strexp.compile(@path, requirements, SEPARATORS)
).names
end
app || Routing::RouteSet::Dispatcher.new(:defaults => defaults) def to
@options[:to]
end
def default_controller
@scope[:controller].to_s if @scope[:controller]
end end
end
def validate_defaults!(app, defaults, segment_keys) module Base
return unless app.is_a?(Routing::RouteSet::Dispatcher) def initialize(set)
@set = set
end
unless defaults.include?(:controller) || segment_keys.include?("controller") def root(options = {})
raise ArgumentError, "missing :controller" match '/', options.reverse_merge(:as => :root)
end end
unless defaults.include?(:action) || segment_keys.include?("action") def match(*args)
raise ArgumentError, "missing :action" @set.add_route(*Mapping.new(@set, @scope, args).to_route)
end self
end end
end end
module HttpHelpers module HttpHelpers
...@@ -139,15 +183,16 @@ def delete(*args, &block) ...@@ -139,15 +183,16 @@ def delete(*args, &block)
def redirect(*args, &block) def redirect(*args, &block)
options = args.last.is_a?(Hash) ? args.pop : {} options = args.last.is_a?(Hash) ? args.pop : {}
path = args.shift || block path = args.shift || block
path_proc = path.is_a?(Proc) ? path : proc {|params| path % params } path_proc = path.is_a?(Proc) ? path : proc { |params| path % params }
status = options[:status] || 301 status = options[:status] || 301
lambda do |env| lambda do |env|
req = Rack::Request.new(env) req = Rack::Request.new(env)
params = path_proc.call(env["action_dispatch.request.path_parameters"]) params = path_proc.call(env["action_dispatch.request.path_parameters"])
url = req.scheme + '://' + req.host + params url = req.scheme + '://' + req.host + params
[status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently']]
[ status, {'Location' => url, 'Content-Type' => 'text/html'}, ['Moved Permanently'] ]
end end
end end
...@@ -211,11 +256,11 @@ def scope(*args) ...@@ -211,11 +256,11 @@ def scope(*args)
self self
ensure ensure
@scope[:path] = path if path_set @scope[:path] = path if path_set
@scope[:name_prefix] = name_prefix if name_prefix_set @scope[:name_prefix] = name_prefix if name_prefix_set
@scope[:controller] = controller if controller_set @scope[:controller] = controller if controller_set
@scope[:options] = options @scope[:options] = options
@scope[:blocks] = blocks @scope[:blocks] = blocks
@scope[:constraints] = constraints @scope[:constraints] = constraints
end end
...@@ -311,12 +356,12 @@ def resource(*resources, &block) ...@@ -311,12 +356,12 @@ def resource(*resources, &block)
with_scope_level(:resource, resource) do with_scope_level(:resource, resource) do
yield if block_given? yield if block_given?
get "(.:format)", :to => :show, :as => resource.member_name get "(.:format)", :to => :show, :as => resource.member_name
post "(.:format)", :to => :create post "(.:format)", :to => :create
put "(.:format)", :to => :update put "(.:format)", :to => :update
delete "(.:format)", :to => :destroy delete "(.:format)", :to => :destroy
get "/new(.:format)", :to => :new, :as => "new_#{resource.singular}" get "/new(.:format)", :to => :new, :as => "new_#{resource.singular}"
get "/edit(.:format)", :to => :edit, :as => "edit_#{resource.singular}" get "/edit(.:format)", :to => :edit, :as => "edit_#{resource.singular}"
end end
end end
...@@ -346,8 +391,9 @@ def resources(*resources, &block) ...@@ -346,8 +391,9 @@ def resources(*resources, &block)
yield if block_given? yield if block_given?
with_scope_level(:collection) do with_scope_level(:collection) do
get "(.:format)", :to => :index, :as => resource.collection_name get "(.:format)", :to => :index, :as => resource.collection_name
post "(.:format)", :to => :create post "(.:format)", :to => :create
with_exclusive_name_prefix :new do with_exclusive_name_prefix :new do
get "/new(.:format)", :to => :new, :as => resource.singular get "/new(.:format)", :to => :new, :as => resource.singular
end end
...@@ -355,9 +401,10 @@ def resources(*resources, &block) ...@@ -355,9 +401,10 @@ def resources(*resources, &block)
with_scope_level(:member) do with_scope_level(:member) do
scope("/:id") do scope("/:id") do
get "(.:format)", :to => :show, :as => resource.member_name get "(.:format)", :to => :show, :as => resource.member_name
put "(.:format)", :to => :update put "(.:format)", :to => :update
delete "(.:format)", :to => :destroy delete "(.:format)", :to => :destroy
with_exclusive_name_prefix :edit do with_exclusive_name_prefix :edit do
get "/edit(.:format)", :to => :edit, :as => resource.singular get "/edit(.:format)", :to => :edit, :as => resource.singular
end end
...@@ -473,4 +520,4 @@ def with_scope_level(kind, resource = parent_resource) ...@@ -473,4 +520,4 @@ def with_scope_level(kind, resource = parent_resource)
include Resources include Resources
end end
end end
end end
\ No newline at end of file
...@@ -22,7 +22,7 @@ def self.matches?(request) ...@@ -22,7 +22,7 @@ def self.matches?(request)
delete 'logout', :to => :destroy, :as => :logout delete 'logout', :to => :destroy, :as => :logout
end end
match 'account/logout' => redirect("/logout") match 'account/logout' => redirect("/logout"), :as => :logout_redirect
match 'account/login', :to => redirect("/login") match 'account/login', :to => redirect("/login")
match 'account/modulo/:name', :to => redirect("/%{name}s") match 'account/modulo/:name', :to => redirect("/%{name}s")
...@@ -110,6 +110,7 @@ def self.matches?(request) ...@@ -110,6 +110,7 @@ def self.matches?(request)
resources :rooms resources :rooms
end end
match '/info' => 'projects#info', :as => 'info'
root :to => 'projects#index' root :to => 'projects#index'
end end
end end
...@@ -153,6 +154,7 @@ def test_login_redirect ...@@ -153,6 +154,7 @@ def test_login_redirect
def test_logout_redirect_without_to def test_logout_redirect_without_to
with_test_routes do with_test_routes do
assert_equal '/account/logout', logout_redirect_path
get '/account/logout' get '/account/logout'
assert_equal 301, @response.status assert_equal 301, @response.status
assert_equal 'http://www.example.com/logout', @response.headers['Location'] assert_equal 'http://www.example.com/logout', @response.headers['Location']
...@@ -462,10 +464,19 @@ def test_access_token_rooms ...@@ -462,10 +464,19 @@ def test_access_token_rooms
def test_root def test_root
with_test_routes do with_test_routes do
assert_equal '/', root_path
get '/' get '/'
assert_equal 'projects#index', @response.body assert_equal 'projects#index', @response.body
end end
end end
def test_index
with_test_routes do
assert_equal '/info', info_path
get '/info'
assert_equal 'projects#info', @response.body
end
end
private private
def with_test_routes def with_test_routes
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册