mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
A hopefully more successful attempt at the Routing branch merge
git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@617 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
This commit is contained in:
parent
88a3343ed5
commit
b1999be5a7
62 changed files with 1815 additions and 492 deletions
|
@ -141,7 +141,7 @@ module Test #:nodoc:
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# ensure our redirection url is an exact match
|
||||
def assert_redirect_url(url=nil, message=nil)
|
||||
assert_redirect(message)
|
||||
|
@ -158,6 +158,36 @@ module Test #:nodoc:
|
|||
assert_block(msg) { response.redirect_url_match?(pattern) }
|
||||
end
|
||||
|
||||
# -- routing assertions --------------------------------------------------
|
||||
|
||||
# Asserts that the routing of the given path is handled correctly and that the parsed options match.
|
||||
# Also verifies that the provided options can be used to generate the provided path.
|
||||
def assert_routing(path, options, defaults={}, extras={}, message=nil)
|
||||
defaults[:controller] ||= options[:controller] # Assume given controller,
|
||||
request = ActionController::TestRequest.new({}, {}, nil)
|
||||
request.path_parameters = defaults.clone
|
||||
|
||||
ActionController::Routing::Routes.reload if ActionController::Routing::Routes.empty? # Load routes.rb if it hasn't been loaded.
|
||||
|
||||
generated_path, found_extras = ActionController::Routing::Routes.generate(options, request)
|
||||
generated_path = generated_path.join('/')
|
||||
msg = build_message(message, "found extras <?>, not <?>", found_extras, extras)
|
||||
assert_block(msg) { found_extras == extras }
|
||||
|
||||
msg = build_message(message, "The generated path <?> did not match <?>", generated_path, path)
|
||||
assert_block(msg) { path == generated_path }
|
||||
|
||||
request = ActionController::TestRequest.new({}, {}, nil)
|
||||
request.path = path
|
||||
ActionController::Routing::Routes.recognize!(request)
|
||||
|
||||
expected_options = options.clone
|
||||
extras.each {|k,v| expected_options.delete k}
|
||||
|
||||
msg = build_message(message, "The recognized options <?> did not match <?>", request.path_parameters, expected_options)
|
||||
assert_block(msg) { request.path_parameters == expected_options }
|
||||
end
|
||||
|
||||
# -- template assertions ------------------------------------------------
|
||||
|
||||
# ensure that a template object with the given name exists
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
require 'action_controller/request'
|
||||
require 'action_controller/response'
|
||||
require 'action_controller/routing'
|
||||
require 'action_controller/url_rewriter'
|
||||
require 'action_controller/support/class_attribute_accessors'
|
||||
require 'action_controller/support/class_inheritable_attributes'
|
||||
|
@ -13,6 +14,15 @@ module ActionController #:nodoc:
|
|||
end
|
||||
class MissingTemplate < ActionControllerError #:nodoc:
|
||||
end
|
||||
class RoutingError < ActionControllerError
|
||||
attr_reader :failures
|
||||
def initialize(message, failures=[])
|
||||
super(message)
|
||||
@failures = failures
|
||||
end
|
||||
end
|
||||
class UnknownController < ActionControllerError #:nodoc:
|
||||
end
|
||||
class UnknownAction < ActionControllerError #:nodoc:
|
||||
end
|
||||
class MissingFile < ActionControllerError #:nodoc:
|
||||
|
@ -205,6 +215,12 @@ module ActionController #:nodoc:
|
|||
# should instead be implemented in the controller to determine when debugging screens should be shown.
|
||||
@@consider_all_requests_local = true
|
||||
cattr_accessor :consider_all_requests_local
|
||||
|
||||
# Enable or disable the collection of failure information for RoutingErrors.
|
||||
# This information can be extremely useful when tweaking custom routes, but is
|
||||
# pointless once routes have been tested and verified.
|
||||
@@debug_routes = true
|
||||
cattr_accessor :debug_routes
|
||||
|
||||
# Template root determines the base from which template references will be made. So a call to render("test/template")
|
||||
# will be converted to "#{template_root}/test/template.rhtml".
|
||||
|
@ -261,6 +277,14 @@ module ActionController #:nodoc:
|
|||
def controller_name
|
||||
Inflector.underscore(controller_class_name.sub(/Controller/, ""))
|
||||
end
|
||||
|
||||
# Convert the class name from something like "OneModule::TwoModule::NeatController" to "one_module/two_module/neat".
|
||||
def controller_path
|
||||
components = self.name.to_s.split('::').collect { |name| name.underscore }
|
||||
components[-1] = $1 if /^(.*)_controller$/ =~ components[-1]
|
||||
components.shift if components.first == 'controllers' # Transitional conditional to accomodate root Controllers module
|
||||
components.join('/')
|
||||
end
|
||||
end
|
||||
|
||||
public
|
||||
|
@ -337,10 +361,6 @@ module ActionController #:nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
def module_name
|
||||
@params["module"]
|
||||
end
|
||||
|
||||
# Converts the class name from something like "OneModule::TwoModule::NeatController" to "NeatController".
|
||||
def controller_class_name
|
||||
self.class.controller_class_name
|
||||
|
@ -594,7 +614,7 @@ module ActionController #:nodoc:
|
|||
end
|
||||
|
||||
def initialize_current_url
|
||||
@url = UrlRewriter.new(@request, controller_name, action_name)
|
||||
@url = UrlRewriter.new(@request, @params.clone())
|
||||
end
|
||||
|
||||
def log_processing
|
||||
|
@ -691,7 +711,7 @@ module ActionController #:nodoc:
|
|||
end
|
||||
|
||||
def default_template_name(default_action_name = action_name)
|
||||
module_name ? "#{module_name}/#{controller_name}/#{default_action_name}" : "#{controller_name}/#{default_action_name}"
|
||||
"#{self.class.controller_path}/#{default_action_name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -46,8 +46,16 @@ module ActionController #:nodoc:
|
|||
super()
|
||||
end
|
||||
|
||||
def query_string
|
||||
return @cgi.query_string unless @cgi.query_string.nil? || @cgi.query_string.empty?
|
||||
parts = env['REQUEST_URI'].split('?')
|
||||
parts.shift
|
||||
return parts.join('?')
|
||||
end
|
||||
|
||||
def query_parameters
|
||||
@cgi.query_string ? CGIMethods.parse_query_parameters(@cgi.query_string) : {}
|
||||
qs = self.query_string
|
||||
qs.empty? ? {} : CGIMethods.parse_query_parameters(query_string)
|
||||
end
|
||||
|
||||
def request_parameters
|
||||
|
|
|
@ -48,25 +48,22 @@ module ActionController #:nodoc:
|
|||
def helper(*args, &block)
|
||||
args.flatten.each do |arg|
|
||||
case arg
|
||||
when Module
|
||||
add_template_helper(arg)
|
||||
when String, Symbol
|
||||
file_name = Inflector.underscore(arg.to_s.downcase) + '_helper'
|
||||
class_name = Inflector.camelize(file_name)
|
||||
begin
|
||||
require_dependency(file_name)
|
||||
rescue LoadError => load_error
|
||||
requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
|
||||
if requiree == file_name
|
||||
raise LoadError, "Missing helper file helpers/#{file_name}.rb"
|
||||
else
|
||||
raise LoadError, "Can't load file: #{requiree}"
|
||||
when Module
|
||||
add_template_helper(arg)
|
||||
when String, Symbol
|
||||
file_name = arg.to_s.underscore + '_helper'
|
||||
class_name = file_name.camelize
|
||||
|
||||
begin
|
||||
require_dependency(file_name)
|
||||
rescue LoadError => load_error
|
||||
requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
|
||||
raise LoadError, requiree == file_name ? "Missing helper file helpers/#{file_name}.rb" : "Can't load file: #{requiree}"
|
||||
end
|
||||
end
|
||||
raise ArgumentError, "Missing #{class_name} module in helpers/#{file_name}.rb" unless Object.const_defined?(class_name)
|
||||
add_template_helper(Object.const_get(class_name))
|
||||
else
|
||||
raise ArgumentError, 'helper expects String, Symbol, or Module argument'
|
||||
|
||||
add_template_helper(class_name.constantize)
|
||||
else
|
||||
raise ArgumentError, 'helper expects String, Symbol, or Module argument'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -95,7 +92,7 @@ module ActionController #:nodoc:
|
|||
def inherited(child)
|
||||
inherited_without_helper(child)
|
||||
begin
|
||||
child.helper(child.controller_name)
|
||||
child.helper(child.controller_path)
|
||||
rescue ArgumentError, LoadError
|
||||
# No default helper available for this controller
|
||||
end
|
||||
|
|
|
@ -3,7 +3,8 @@ module ActionController
|
|||
class AbstractRequest
|
||||
# Returns both GET and POST parameters in a single hash.
|
||||
def parameters
|
||||
@parameters ||= request_parameters.update(query_parameters)
|
||||
# puts "#{request_parameters.inspect} | #{query_parameters.inspect} | #{path_parameters.inspect}"
|
||||
@parameters ||= request_parameters.merge(query_parameters).merge(path_parameters).with_indifferent_access
|
||||
end
|
||||
|
||||
def method
|
||||
|
@ -73,7 +74,7 @@ module ActionController
|
|||
end
|
||||
|
||||
def request_uri
|
||||
env['REQUEST_URI']
|
||||
(%r{^\w+\://[^/]+(/.*|$)$} =~ env['REQUEST_URI']) ? $1 : env['REQUEST_URI'] # Remove domain, which webrick puts into the request_uri.
|
||||
end
|
||||
|
||||
def protocol
|
||||
|
@ -85,7 +86,7 @@ module ActionController
|
|||
end
|
||||
|
||||
def path
|
||||
request_uri ? request_uri.split('?').first : ''
|
||||
path = request_uri ? request_uri.split('?').first : ''
|
||||
end
|
||||
|
||||
def port
|
||||
|
@ -100,7 +101,16 @@ module ActionController
|
|||
def host_with_port
|
||||
env['HTTP_HOST'] || host + port_string
|
||||
end
|
||||
|
||||
def path_parameters=(parameters)
|
||||
@path_parameters = parameters
|
||||
@parameters = nil
|
||||
end
|
||||
|
||||
def path_parameters
|
||||
@path_parameters ||= {}
|
||||
end
|
||||
|
||||
#--
|
||||
# Must be implemented in the concrete request
|
||||
#++
|
||||
|
|
|
@ -48,7 +48,11 @@ module ActionController #:nodoc:
|
|||
|
||||
# Overwrite to implement public exception handling (for requests answering false to <tt>local_request?</tt>).
|
||||
def rescue_action_in_public(exception) #:doc:
|
||||
render_text "<html><body><h1>Application error (Rails)</h1></body></html>"
|
||||
case exception
|
||||
when RoutingError, UnknownAction then
|
||||
render_text(IO.read(File.join(RAILS_ROOT, 'public', '404.html')), "404 Not Found")
|
||||
else render_text "<html><body><h1>Application error (Rails)</h1></body></html>"
|
||||
end
|
||||
end
|
||||
|
||||
# Overwrite to expand the meaning of a local request in order to show local rescues on other occurences than
|
||||
|
@ -66,7 +70,7 @@ module ActionController #:nodoc:
|
|||
@contents = @template.render_file(template_path_for_local_rescue(exception), false)
|
||||
|
||||
@headers["Content-Type"] = "text/html"
|
||||
render_file(rescues_path("layout"), "500 Internal Error")
|
||||
render_file(rescues_path("layout"), response_code_for_rescue(exception))
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -110,13 +114,21 @@ module ActionController #:nodoc:
|
|||
rescues_path(
|
||||
case exception
|
||||
when MissingTemplate then "missing_template"
|
||||
when RoutingError then "routing_error"
|
||||
when UnknownAction then "unknown_action"
|
||||
when ActionView::TemplateError then "template_error"
|
||||
else "diagnostics"
|
||||
else raise ;"diagnostics"
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
def response_code_for_rescue(exception)
|
||||
case exception
|
||||
when UnknownAction, RoutingError then "404 Page Not Found"
|
||||
else "500 Internal Error"
|
||||
end
|
||||
end
|
||||
|
||||
def clean_backtrace(exception)
|
||||
exception.backtrace.collect { |line| Object.const_defined?(:RAILS_ROOT) ? line.gsub(RAILS_ROOT, "") : line }
|
||||
end
|
||||
|
|
260
actionpack/lib/action_controller/routing.rb
Normal file
260
actionpack/lib/action_controller/routing.rb
Normal file
|
@ -0,0 +1,260 @@
|
|||
module ActionController
|
||||
module Routing
|
||||
ROUTE_FILE = defined?(RAILS_ROOT) ? File.expand_path(File.join(RAILS_ROOT, 'config', 'routes')) : nil
|
||||
|
||||
class Route
|
||||
attr_reader :defaults # The defaults hash
|
||||
|
||||
def initialize(path, hash={})
|
||||
raise ArgumentError, "Second argument must be a hash!" unless hash.kind_of?(Hash)
|
||||
@defaults = {}
|
||||
@requirements = {}
|
||||
self.items = path
|
||||
hash.each do |k, v|
|
||||
raise TypeError, "Hash may only contain symbols!" unless k.kind_of? Symbol
|
||||
(@items.include?(k) ? @defaults : @requirements)[k] = v
|
||||
end
|
||||
|
||||
# Add in defaults for :action and :id.
|
||||
[[:action, 'index'], [:id, nil]].each do |name, default|
|
||||
@defaults[name] = default if @items.include?(name) && ! (@requirements.key?(name) || @defaults.key?(name))
|
||||
end
|
||||
end
|
||||
|
||||
# Generate a URL given the provided options.
|
||||
# All values in options should be symbols.
|
||||
# Returns the path and the unused names in a 2 element array.
|
||||
# If generation fails, [nil, nil] is returned
|
||||
# Generation can fail because of a missing value, or because an equality check fails.
|
||||
#
|
||||
# Generate urls will be as short as possible. If the last component of a url is equal to the default value,
|
||||
# then that component is removed. This is applied as many times as possible. So, your index controller's
|
||||
# index action will generate []
|
||||
def generate(options, defaults={})
|
||||
non_matching = @requirements.inject([]) {|a, (k, v)| ((options[k] || defaults[k]) == v) ? a : a << k}
|
||||
return nil, "Options mismatch requirements: #{non_matching.join ', '}" unless non_matching.empty?
|
||||
|
||||
used_names = @requirements.inject({}) {|hash, (k, v)| hash[k] = true; hash}
|
||||
components = @items.collect do |item|
|
||||
if item.kind_of? Symbol
|
||||
used_names[item] = true
|
||||
value = options[item] || defaults[item] || @defaults[item]
|
||||
return nil, "#{item.inspect} was not given and has no default." if value.nil? && ! (@defaults.key?(item) && @defaults[item].nil?) # Don't leave if nil value.
|
||||
defaults = {} unless defaults == {} || value == defaults[item] # Stop using defaults if this component isn't the same as the default.
|
||||
value
|
||||
else item
|
||||
end
|
||||
end
|
||||
|
||||
@items.reverse_each do |item| # Remove default components from the end of the generated url.
|
||||
break unless item.kind_of?(Symbol) && @defaults[item] == components.last
|
||||
components.pop
|
||||
end
|
||||
|
||||
# If we have any nil components then we can't proceed.
|
||||
# This might need to be changed. In some cases we may be able to return all componets after nil as extras.
|
||||
missing = []; components.each_with_index {|c, i| missing << @items[i] if c.nil?}
|
||||
return nil, "No values provided for component#{'s' if missing.length > 1} #{missing.join ', '} but values are required due to use of later components" unless missing.empty? # how wide is your screen?
|
||||
|
||||
unused = (options.keys - used_names.keys).inject({}) do |unused, key|
|
||||
unused[key] = options[key] if options[key] != @defaults[key]
|
||||
unused
|
||||
end
|
||||
|
||||
components.collect! {|c| c.to_s}
|
||||
components.unshift(components.shift + '/') if components.length == 1 && @items.first == :controller # Add '/' to controllers
|
||||
|
||||
return components, unused
|
||||
end
|
||||
|
||||
# Recognize the provided path, returning a hash of recognized values, or [nil, reason] if the path isn't recognized.
|
||||
# The path should be a list of component strings.
|
||||
# Options is a hash of the ?k=v pairs
|
||||
def recognize(components, options={})
|
||||
options = options.clone
|
||||
components = components.clone
|
||||
controller_class = nil
|
||||
|
||||
@items.each do |item|
|
||||
if item == :controller # Special case for controller
|
||||
if components.empty? && @defaults[:controller]
|
||||
controller_class, leftover = eat_path_to_controller(@defaults[:controller].split('/'))
|
||||
raise RoutingError, "Default controller does not exist: #{@defaults[:controller]}" if controller_class.nil? || leftover.empty? == false
|
||||
else
|
||||
controller_class, remaining_components = eat_path_to_controller(components)
|
||||
return nil, "No controller found at subpath #{components.join('/')}" if controller_class.nil?
|
||||
components = remaining_components
|
||||
end
|
||||
options[:controller] = controller_class.controller_path
|
||||
elsif item.kind_of? Symbol
|
||||
value = components.shift || @defaults[item]
|
||||
return nil, "No value or default for parameter #{item.inspect}" if value.nil? && ! (@defaults.key?(item) && @defaults[item].nil?)
|
||||
options[item] = value
|
||||
else
|
||||
return nil, "No value available for component #{item.inspect}" if components.empty?
|
||||
component = components.shift
|
||||
return nil, "Value for component #{item.inspect} doesn't match #{component}" if component != item
|
||||
end
|
||||
end
|
||||
|
||||
if controller_class.nil? && @requirements[:controller] # Load a default controller
|
||||
controller_class, extras = eat_path_to_controller(@requirements[:controller].split('/'))
|
||||
raise RoutingError, "Illegal controller path for route default: #{@requirements[:controller]}" unless controller_class && extras.empty?
|
||||
options[:controller] = controller_class.controller_path
|
||||
end
|
||||
options = @requirements.merge(options)
|
||||
|
||||
return nil, "Route recognition didn't find a controller class!" unless controller_class
|
||||
return nil, "Unused components were left: #{components.join '/'}" unless components.empty?
|
||||
options.delete_if {|k, v| v.nil?} # Remove nil values.
|
||||
return controller_class, options
|
||||
end
|
||||
|
||||
def inspect
|
||||
when_str = @requirements.empty? ? "" : " when #{@requirements.inspect}"
|
||||
default_str = @defaults.empty? ? "" : " || #{@defaults.inspect}"
|
||||
"<#{self.class.to_s} #{@items.collect{|c| c.kind_of?(String) ? c : c.inspect}.join('/').inspect}#{default_str}#{when_str}>"
|
||||
end
|
||||
|
||||
protected
|
||||
# Find the controller given a list of path components.
|
||||
# Return the controller class and the unused path components.
|
||||
def eat_path_to_controller(path)
|
||||
path.inject([Controllers, 1]) do |(mod, length), name|
|
||||
name = name.camelize
|
||||
controller_name = name + "Controller"
|
||||
return mod.const_get(controller_name), path[length..-1] if mod.const_available? controller_name
|
||||
return nil, nil unless mod.const_available? name
|
||||
[mod.const_get(name), length + 1]
|
||||
end
|
||||
return nil, nil # Path ended, but no controller found.
|
||||
end
|
||||
|
||||
def items=(path)
|
||||
items = path.split('/').collect {|c| (/^:(\w+)$/ =~ c) ? $1.intern : c} if path.kind_of?(String) # split and convert ':xyz' to symbols
|
||||
items.shift if items.first == ""
|
||||
items.pop if items.last == ""
|
||||
@items = items
|
||||
|
||||
# Verify uniqueness of each component.
|
||||
@items.inject({}) do |seen, item|
|
||||
if item.kind_of? Symbol
|
||||
raise ArgumentError, "Illegal route path -- duplicate item #{item}\n #{path.inspect}" if seen.key? item
|
||||
seen[item] = true
|
||||
end
|
||||
seen
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class RouteSet
|
||||
def initialize
|
||||
@routes = []
|
||||
end
|
||||
|
||||
def add_route(route)
|
||||
raise TypeError, "#{route.inspect} is not a Route instance!" unless route.kind_of?(Route)
|
||||
@routes << route
|
||||
end
|
||||
def empty?
|
||||
@routes.empty?
|
||||
end
|
||||
def each
|
||||
@routes.each {|route| yield route}
|
||||
end
|
||||
|
||||
# Generate a path for the provided options
|
||||
# Returns the path as an array of components and a hash of unused names
|
||||
# Raises RoutingError if not route can handle the provided components.
|
||||
#
|
||||
# Note that we don't return the first generated path. We do this so that when a route
|
||||
# generates a path from a subset of the available options we can keep looking for a
|
||||
# route which can generate a path that uses more options.
|
||||
# Note that we *do* return immediately if
|
||||
def generate(options, request)
|
||||
raise RoutingError, "There are no routes defined!" if @routes.empty?
|
||||
options = options.symbolize_keys
|
||||
defaults = request.path_parameters.symbolize_keys
|
||||
expand_controller_path!(options, defaults)
|
||||
|
||||
failures = []
|
||||
selected = nil
|
||||
self.each do |route|
|
||||
path, unused = route.generate(options, defaults)
|
||||
if path.nil?
|
||||
failures << [route, unused] if ActionController::Base.debug_routes
|
||||
else
|
||||
return path, unused if unused.empty? # Found a perfect route -- we're finished.
|
||||
if selected.nil? || unused.length < selected.last.length
|
||||
failures << [selected.first, "A better url than #{selected[1]} was found."] if selected
|
||||
selected = [route, path, unused]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return selected[1..-1] unless selected.nil?
|
||||
raise RoutingError.new("Generation failure: No route for url_options #{options.inspect}, defaults: #{defaults.inspect}", failures)
|
||||
end
|
||||
|
||||
# Recognize the provided path.
|
||||
# Raise RoutingError if the path can't be recognized.
|
||||
def recognize!(request)
|
||||
path = ((%r{^/?(.*)/?$} =~ request.path) ? $1 : request.path).split('/')
|
||||
raise RoutingError, "There are no routes defined!" if @routes.empty?
|
||||
|
||||
failures = []
|
||||
self.each do |route|
|
||||
controller, options = route.recognize(path)
|
||||
if controller.nil?
|
||||
failures << [route, options] if ActionController::Base.debug_routes
|
||||
else
|
||||
options.each {|k, v| request.path_parameters[k] = CGI.unescape(v)}
|
||||
return controller
|
||||
end
|
||||
end
|
||||
|
||||
raise RoutingError.new("No route for path: #{path.join('/').inspect}", failures)
|
||||
end
|
||||
|
||||
def expand_controller_path!(options, defaults)
|
||||
if options[:controller]
|
||||
if /^\// =~ options[:controller]
|
||||
options[:controller] = options[:controller][1..-1]
|
||||
defaults.clear # Sending to absolute controller implies fresh defaults
|
||||
else
|
||||
relative_to = defaults[:controller] ? defaults[:controller].split('/')[0..-2].join('/') : ''
|
||||
options[:controller] = relative_to.empty? ? options[:controller] : "#{relative_to}/#{options[:controller]}"
|
||||
end
|
||||
else
|
||||
options[:controller] = defaults[:controller]
|
||||
end
|
||||
end
|
||||
|
||||
def route(*args)
|
||||
add_route(Route.new(*args))
|
||||
end
|
||||
alias :connect :route
|
||||
|
||||
def reload
|
||||
begin require_dependency(ROUTE_FILE)
|
||||
rescue LoadError, ScriptError => e
|
||||
raise RoutingError, "Cannot load config/routes.rb:\n #{e.message}"
|
||||
ensure # Ensure that there is at least one route:
|
||||
connect(':controller/:action/:id', :action => 'index', :id => nil) if @routes.empty?
|
||||
end
|
||||
end
|
||||
|
||||
def draw
|
||||
@routes.clear
|
||||
yield self
|
||||
end
|
||||
end
|
||||
|
||||
def self.draw(*args, &block)
|
||||
Routes.draw(*args) {|*args| block.call(*args)}
|
||||
end
|
||||
|
||||
Routes = RouteSet.new
|
||||
#Routes.reload # Do this here, so that server will die on load if SyntaxError or whatnot.
|
||||
end
|
||||
end
|
|
@ -149,7 +149,7 @@ module ActionController
|
|||
|
||||
private
|
||||
def render#{suffix}_scaffold(action = caller_method_name(caller))
|
||||
if template_exists?("\#{controller_name}/\#{action}")
|
||||
if template_exists?("\#{self.class.controller_path}/\#{action}")
|
||||
render_action(action)
|
||||
else
|
||||
@scaffold_class = #{class_name}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<h1>Routing Error</h1>
|
||||
<p><%=h @exception.message %></p>
|
||||
<% unless @exception.failures.empty? %><p>
|
||||
<h2>Failure reasons:</h2>
|
||||
<% @exception.failures.each do |route, reason| %>
|
||||
<%=h route.inspect.gsub('\\', '') %> failed because <%=h reason.downcase %><br />
|
||||
<% end %>
|
||||
</p><% end %>
|
|
@ -31,8 +31,8 @@ module ActionController #:nodoc:
|
|||
|
||||
class TestRequest < AbstractRequest #:nodoc:
|
||||
attr_accessor :cookies
|
||||
attr_accessor :query_parameters, :request_parameters, :session, :env
|
||||
attr_accessor :host, :path, :request_uri, :remote_addr
|
||||
attr_accessor :query_parameters, :request_parameters, :path, :session, :env
|
||||
attr_accessor :host, :remote_addr
|
||||
|
||||
def initialize(query_parameters = nil, request_parameters = nil, session = nil)
|
||||
@query_parameters = query_parameters || {}
|
||||
|
@ -58,11 +58,28 @@ module ActionController #:nodoc:
|
|||
@parameters = nil
|
||||
end
|
||||
|
||||
# Used to check AbstractRequest's request_uri functionality.
|
||||
# Disables the use of @path and @request_uri so superclass can handle those.
|
||||
def set_REQUEST_URI(value)
|
||||
@env["REQUEST_URI"] = value
|
||||
@request_uri = nil
|
||||
@path = nil
|
||||
end
|
||||
|
||||
def request_uri=(uri)
|
||||
@request_uri = uri
|
||||
@path = uri.split("?").first
|
||||
end
|
||||
|
||||
def request_uri
|
||||
@request_uri || super()
|
||||
end
|
||||
|
||||
def path
|
||||
@path || super()
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def initialize_containers
|
||||
@env, @cookies = {}, {}
|
||||
|
@ -237,6 +254,7 @@ module Test
|
|||
def process(action, parameters = nil, session = nil)
|
||||
@request.env['REQUEST_METHOD'] ||= "GET"
|
||||
@request.action = action.to_s
|
||||
@request.path_parameters = { :controller => @controller.class.controller_path }
|
||||
@request.parameters.update(parameters) unless parameters.nil?
|
||||
@request.session = ActionController::TestSession.new(session) unless session.nil?
|
||||
@controller.process(@request, @response)
|
||||
|
|
|
@ -1,41 +1,29 @@
|
|||
module ActionController
|
||||
# Rewrites URLs for Base.redirect_to and Base.url_for in the controller.
|
||||
|
||||
class UrlRewriter #:nodoc:
|
||||
VALID_OPTIONS = [:action, :action_prefix, :action_suffix, :application_prefix, :module, :controller, :controller_prefix, :anchor, :params, :path_params, :id, :only_path, :overwrite_params, :host, :protocol ]
|
||||
|
||||
def initialize(request, controller, action)
|
||||
@request, @controller, @action = request, controller, action
|
||||
RESERVED_OPTIONS = [:anchor, :params, :path_params, :only_path, :host, :protocol]
|
||||
def initialize(request, parameters)
|
||||
@request, @parameters = request, parameters
|
||||
@rewritten_path = @request.path ? @request.path.dup : ""
|
||||
end
|
||||
|
||||
def rewrite(options = {})
|
||||
validate_options(VALID_OPTIONS, options.keys)
|
||||
|
||||
rewrite_url(
|
||||
rewrite_path(@rewritten_path, resolve_aliases(options)),
|
||||
options
|
||||
)
|
||||
end
|
||||
|
||||
def to_s
|
||||
to_str
|
||||
rewrite_url(rewrite_path(options), options)
|
||||
end
|
||||
|
||||
def to_str
|
||||
"#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@controller}, #{@action}, #{@request.parameters.inspect}"
|
||||
"#{@request.protocol}, #{@request.host_with_port}, #{@request.path}, #{@parameters[:controller]}, #{@parameters[:action]}, #{@request.parameters.inspect}"
|
||||
end
|
||||
|
||||
alias_method :to_s, :to_str
|
||||
|
||||
private
|
||||
def validate_options(valid_option_keys, supplied_option_keys)
|
||||
unknown_option_keys = supplied_option_keys - valid_option_keys
|
||||
raise(ActionController::ActionControllerError, "Unknown options: #{unknown_option_keys}") unless unknown_option_keys.empty?
|
||||
end
|
||||
|
||||
def resolve_aliases(options)
|
||||
options[:controller_prefix] = options[:module] unless options[:module].nil?
|
||||
options
|
||||
end
|
||||
|
||||
|
||||
def rewrite_url(path, options)
|
||||
rewritten_url = ""
|
||||
rewritten_url << (options[:protocol] || @request.protocol) unless options[:only_path]
|
||||
|
@ -45,15 +33,18 @@ module ActionController
|
|||
rewritten_url << path
|
||||
rewritten_url << build_query_string(new_parameters(options)) if options[:params] || options[:overwrite_params]
|
||||
rewritten_url << "##{options[:anchor]}" if options[:anchor]
|
||||
|
||||
return rewritten_url
|
||||
end
|
||||
|
||||
def rewrite_path(path, options)
|
||||
include_id_in_path_params(options)
|
||||
|
||||
path = rewrite_action(path, options) if options[:action] || options[:action_prefix]
|
||||
path = rewrite_path_params(path, options) if options[:path_params]
|
||||
path = rewrite_controller(path, options) if options[:controller] || options[:controller_prefix]
|
||||
def rewrite_path(options)
|
||||
options = options.symbolize_keys
|
||||
RESERVED_OPTIONS.each {|k| options.delete k}
|
||||
|
||||
path, extras = Routing::Routes.generate(options, @request)
|
||||
path = "/#{path.join('/')}"
|
||||
path += build_query_string(extras)
|
||||
|
||||
return path
|
||||
end
|
||||
|
||||
|
@ -76,49 +67,6 @@ module ActionController
|
|||
end
|
||||
end
|
||||
|
||||
def rewrite_action(path, options)
|
||||
# This regex assumes that "index" actions won't be included in the URL
|
||||
all, controller_prefix, action_prefix, action_suffix =
|
||||
/^\/(.*)#{@controller}\/(.*)#{@action == "index" ? "" : @action}(.*)/.match(path).to_a
|
||||
|
||||
if @action == "index"
|
||||
if action_prefix == "index"
|
||||
# we broke the parsing assumption that this would be excluded, so
|
||||
# don't tell action_name about our little boo-boo
|
||||
path = path.sub(action_prefix, action_name(options, nil))
|
||||
elsif action_prefix && !action_prefix.empty?
|
||||
path = path.sub(%r(/#{action_prefix}/?), "/" + action_name(options, action_prefix))
|
||||
else
|
||||
path = path.sub(%r(#{@controller}/?$), @controller + "/" + action_name(options)) # " ruby-mode
|
||||
end
|
||||
else
|
||||
path = path.sub(
|
||||
@controller + "/" + (action_prefix || "") + @action + (action_suffix || ""),
|
||||
@controller + "/" + action_name(options, action_prefix)
|
||||
)
|
||||
end
|
||||
|
||||
if options[:controller_prefix] && !options[:controller]
|
||||
ensure_slash_suffix(options, :controller_prefix)
|
||||
if controller_prefix
|
||||
path = path.sub(controller_prefix, options[:controller_prefix])
|
||||
else
|
||||
path = options[:controller_prefix] + path
|
||||
end
|
||||
end
|
||||
|
||||
return path
|
||||
end
|
||||
|
||||
def rewrite_controller(path, options)
|
||||
all, controller_prefix = /^\/(.*?)#{@controller}/.match(path).to_a
|
||||
path = "/"
|
||||
path << controller_name(options, controller_prefix)
|
||||
path << action_name(options) if options[:action]
|
||||
path << path_params_in_list(options) if options[:path_params]
|
||||
return path
|
||||
end
|
||||
|
||||
def action_name(options, action_prefix = nil, action_suffix = nil)
|
||||
ensure_slash_suffix(options, :action_prefix)
|
||||
ensure_slash_prefix(options, :action_suffix)
|
||||
|
@ -174,16 +122,16 @@ module ActionController
|
|||
def build_query_string(hash)
|
||||
elements = []
|
||||
query_string = ""
|
||||
|
||||
|
||||
hash.each do |key, value|
|
||||
key = key.to_s
|
||||
key = CGI.escape key
|
||||
key += '[]' if value.class == Array
|
||||
value = [ value ] unless value.class == Array
|
||||
value.each { |val| elements << "#{key}=#{CGI.escape(val.to_s)}" }
|
||||
end
|
||||
|
||||
unless elements.empty? then query_string << ("?" + elements.join("&")) end
|
||||
end
|
||||
|
||||
query_string << ("?" + elements.join("&")) unless elements.empty?
|
||||
return query_string
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ module ActionView
|
|||
if partial_path.include?('/')
|
||||
return File.dirname(partial_path), File.basename(partial_path)
|
||||
else
|
||||
return controller.send(:controller_name), partial_path
|
||||
return controller.class.controller_path, partial_path
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -28,10 +28,6 @@ class CookieTest < Test::Unit::TestCase
|
|||
render_text "hello world"
|
||||
end
|
||||
|
||||
def access_frozen_cookies
|
||||
@cookies["wont"] = "work"
|
||||
end
|
||||
|
||||
def rescue_action(e) raise end
|
||||
end
|
||||
|
||||
|
@ -67,11 +63,6 @@ class CookieTest < Test::Unit::TestCase
|
|||
assert_equal 2, process_request.headers["cookie"].size
|
||||
end
|
||||
|
||||
def test_setting_cookie_on_frozen_instance_variable
|
||||
@request.action = "access_frozen_cookies"
|
||||
assert_raises(TypeError) { process_request }
|
||||
end
|
||||
|
||||
private
|
||||
def process_request
|
||||
TestController.process(@request, @response)
|
||||
|
|
|
@ -1,21 +1,31 @@
|
|||
require File.dirname(__FILE__) + '/../abstract_unit'
|
||||
$:.unshift(File.dirname(__FILE__) + '/../fixtures/helpers')
|
||||
|
||||
class TestController < ActionController::Base
|
||||
attr_accessor :delegate_attr
|
||||
def delegate_method() end
|
||||
def rescue_action(e) raise end
|
||||
end
|
||||
|
||||
module Fun
|
||||
class GamesController < ActionController::Base
|
||||
def render_hello_world
|
||||
render_template "hello: <%= stratego %>"
|
||||
end
|
||||
|
||||
def rescue_action(e) raise end
|
||||
end
|
||||
end
|
||||
|
||||
module LocalAbcHelper
|
||||
def a() end
|
||||
def b() end
|
||||
def c() end
|
||||
end
|
||||
|
||||
class HelperTest < Test::Unit::TestCase
|
||||
HELPER_PATHS = %w(/../fixtures/helpers)
|
||||
|
||||
class TestController < ActionController::Base
|
||||
attr_accessor :delegate_attr
|
||||
def delegate_method() end
|
||||
def rescue_action(e) raise end
|
||||
end
|
||||
|
||||
module LocalAbcHelper
|
||||
def a() end
|
||||
def b() end
|
||||
def c() end
|
||||
end
|
||||
|
||||
|
||||
def setup
|
||||
# Increment symbol counter.
|
||||
@symbol = (@@counter ||= 'A0').succ!.dup
|
||||
|
@ -102,6 +112,13 @@ class HelperTest < Test::Unit::TestCase
|
|||
assert template_methods.include?('delegate_attr=')
|
||||
end
|
||||
|
||||
def test_helper_for_nested_controller
|
||||
@request = ActionController::TestRequest.new
|
||||
@response = ActionController::TestResponse.new
|
||||
@request.action = "render_hello_world"
|
||||
|
||||
assert_equal "hello: Iz guuut!", Fun::GamesController.process(@request, @response).body
|
||||
end
|
||||
|
||||
private
|
||||
def helper_methods; TestHelper.instance_methods end
|
||||
|
|
|
@ -2,86 +2,91 @@ require File.dirname(__FILE__) + '/../abstract_unit'
|
|||
|
||||
Customer = Struct.new("Customer", :name)
|
||||
|
||||
class RenderTest < Test::Unit::TestCase
|
||||
class TestController < ActionController::Base
|
||||
layout :determine_layout
|
||||
|
||||
module Fun
|
||||
class GamesController < ActionController::Base
|
||||
def hello_world
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def render_hello_world
|
||||
render "test/hello_world"
|
||||
end
|
||||
|
||||
def render_hello_world_from_variable
|
||||
@person = "david"
|
||||
render_text "hello #{@person}"
|
||||
end
|
||||
class TestController < ActionController::Base
|
||||
layout :determine_layout
|
||||
|
||||
def render_action_hello_world
|
||||
render_action "hello_world"
|
||||
end
|
||||
|
||||
def render_text_hello_world
|
||||
render_text "hello world"
|
||||
end
|
||||
|
||||
def render_custom_code
|
||||
render_text "hello world", "404 Moved"
|
||||
end
|
||||
|
||||
def render_xml_hello
|
||||
@name = "David"
|
||||
render "test/hello"
|
||||
end
|
||||
|
||||
def greeting
|
||||
# let's just rely on the template
|
||||
end
|
||||
|
||||
def layout_test
|
||||
render_action "hello_world"
|
||||
end
|
||||
|
||||
def builder_layout_test
|
||||
render_action "hello"
|
||||
end
|
||||
|
||||
def partials_list
|
||||
@customers = [ Customer.new("david"), Customer.new("mary") ]
|
||||
render_action "list"
|
||||
end
|
||||
|
||||
def modgreet
|
||||
end
|
||||
|
||||
def rescue_action(e) raise end
|
||||
|
||||
private
|
||||
def determine_layout
|
||||
case action_name
|
||||
when "layout_test": "layouts/standard"
|
||||
when "builder_layout_test": "layouts/builder"
|
||||
end
|
||||
end
|
||||
def hello_world
|
||||
end
|
||||
|
||||
TestController.template_root = File.dirname(__FILE__) + "/../fixtures/"
|
||||
def render_hello_world
|
||||
render "test/hello_world"
|
||||
end
|
||||
|
||||
def render_hello_world_from_variable
|
||||
@person = "david"
|
||||
render_text "hello #{@person}"
|
||||
end
|
||||
|
||||
def render_action_hello_world
|
||||
render_action "hello_world"
|
||||
end
|
||||
|
||||
class TestLayoutController < ActionController::Base
|
||||
layout "layouts/standard"
|
||||
|
||||
def hello_world
|
||||
end
|
||||
|
||||
def hello_world_outside_layout
|
||||
end
|
||||
|
||||
def rescue_action(e)
|
||||
raise unless ActionController::MissingTemplate === e
|
||||
end
|
||||
def render_text_hello_world
|
||||
render_text "hello world"
|
||||
end
|
||||
|
||||
def render_custom_code
|
||||
render_text "hello world", "404 Moved"
|
||||
end
|
||||
|
||||
def render_xml_hello
|
||||
@name = "David"
|
||||
render "test/hello"
|
||||
end
|
||||
|
||||
def greeting
|
||||
# let's just rely on the template
|
||||
end
|
||||
|
||||
def layout_test
|
||||
render_action "hello_world"
|
||||
end
|
||||
|
||||
def builder_layout_test
|
||||
render_action "hello"
|
||||
end
|
||||
|
||||
def partials_list
|
||||
@customers = [ Customer.new("david"), Customer.new("mary") ]
|
||||
render_action "list"
|
||||
end
|
||||
|
||||
def rescue_action(e) raise end
|
||||
|
||||
private
|
||||
def determine_layout
|
||||
case action_name
|
||||
when "layout_test": "layouts/standard"
|
||||
when "builder_layout_test": "layouts/builder"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
TestController.template_root = File.dirname(__FILE__) + "/../fixtures/"
|
||||
|
||||
class TestLayoutController < ActionController::Base
|
||||
layout "layouts/standard"
|
||||
|
||||
def hello_world
|
||||
end
|
||||
|
||||
def hello_world_outside_layout
|
||||
end
|
||||
|
||||
def rescue_action(e)
|
||||
raise unless ActionController::MissingTemplate === e
|
||||
end
|
||||
end
|
||||
|
||||
class RenderTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@request = ActionController::TestRequest.new
|
||||
@response = ActionController::TestResponse.new
|
||||
|
@ -170,10 +175,9 @@ class RenderTest < Test::Unit::TestCase
|
|||
assert_equal "Hello: davidHello: mary", process_request.body
|
||||
end
|
||||
|
||||
def test_module_rendering
|
||||
@request.action = "modgreet"
|
||||
@request.parameters["module"] = "scope"
|
||||
assert_equal "<p>Beautiful modules!</p>", process_request.body
|
||||
def test_nested_rendering
|
||||
@request.action = "hello_world"
|
||||
assert_equal "Living in a nested world", Fun::GamesController.process(@request, @response).body
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -31,6 +31,28 @@ class RequestTest < Test::Unit::TestCase
|
|||
@request.port = 8080
|
||||
assert_equal ":8080", @request.port_string
|
||||
end
|
||||
|
||||
def test_request_uri
|
||||
@request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri?mapped=1"
|
||||
assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
|
||||
assert_equal "/path/of/some/uri", @request.path
|
||||
|
||||
@request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri"
|
||||
assert_equal "/path/of/some/uri", @request.request_uri
|
||||
assert_equal "/path/of/some/uri", @request.path
|
||||
|
||||
@request.set_REQUEST_URI "/path/of/some/uri"
|
||||
assert_equal "/path/of/some/uri", @request.request_uri
|
||||
assert_equal "/path/of/some/uri", @request.path
|
||||
|
||||
@request.set_REQUEST_URI "/"
|
||||
assert_equal "/", @request.request_uri
|
||||
assert_equal "/", @request.path
|
||||
|
||||
@request.set_REQUEST_URI "/?m=b"
|
||||
assert_equal "/?m=b", @request.request_uri
|
||||
assert_equal "/", @request.path
|
||||
end
|
||||
|
||||
def test_host_with_port
|
||||
@request.env['HTTP_HOST'] = "rubyonrails.org:8080"
|
||||
|
|
409
actionpack/test/controller/routing_tests.rb
Normal file
409
actionpack/test/controller/routing_tests.rb
Normal file
|
@ -0,0 +1,409 @@
|
|||
# Code Generated by ZenTest v. 2.3.0
|
||||
# Couldn't find class for name Routing
|
||||
# classname: asrt / meth = ratio%
|
||||
# ActionController::Routing::RouteSet: 0 / 16 = 0.00%
|
||||
# ActionController::Routing::RailsRoute: 0 / 4 = 0.00%
|
||||
# ActionController::Routing::Route: 0 / 8 = 0.00%
|
||||
|
||||
RAILS_ROOT = ""
|
||||
require File.dirname(__FILE__) + '/../abstract_unit'
|
||||
require 'test/unit'
|
||||
require 'cgi'
|
||||
|
||||
class FakeController
|
||||
attr_reader :controller_path
|
||||
attr_reader :name
|
||||
def initialize(name, controller_path)
|
||||
@name = name
|
||||
@controller_path = controller_path
|
||||
end
|
||||
def kind_of?(x)
|
||||
x === Class || x == FakeController
|
||||
end
|
||||
end
|
||||
|
||||
module Controllers
|
||||
module Admin
|
||||
UserController = FakeController.new 'Admin::UserController', 'admin/user'
|
||||
AccessController = FakeController.new 'Admin::AccessController', 'admin/access'
|
||||
end
|
||||
module Editing
|
||||
PageController = FakeController.new 'Editing::PageController', 'editing/page'
|
||||
ImageController = FakeController.new 'Editing::ImageController', 'editing/image'
|
||||
end
|
||||
module User
|
||||
NewsController = FakeController.new 'User::NewsController', 'user/news'
|
||||
PaymentController = FakeController.new 'User::PaymentController', 'user/payment'
|
||||
end
|
||||
ContentController = FakeController.new 'ContentController', 'content'
|
||||
ResourceController = FakeController.new 'ResourceController', 'resource'
|
||||
end
|
||||
|
||||
# Extend the modules with the required methods...
|
||||
[Controllers, Controllers::Admin, Controllers::Editing, Controllers::User].each do |mod|
|
||||
mod.instance_eval('alias :const_available? :const_defined?')
|
||||
mod.constants.each {|k| Object.const_set(k, mod.const_get(k))} # export the modules & controller classes.
|
||||
end
|
||||
|
||||
|
||||
class RouteTests < Test::Unit::TestCase
|
||||
def route(*args)
|
||||
return @route if @route && (args.empty? || @args == args)
|
||||
@args = args
|
||||
@route = ActionController::Routing::Route.new(*args)
|
||||
return @route
|
||||
end
|
||||
|
||||
def setup
|
||||
self.route '/:controller/:action/:id'
|
||||
@defaults = {:controller => 'content', :action => 'show', :id => '314'}
|
||||
end
|
||||
|
||||
# Don't put a leading / on the url.
|
||||
# Make sure the controller is one from the above fake Controllers module.
|
||||
def verify_recognize(url, expected_options, reason='')
|
||||
url = url.split('/') if url.kind_of? String
|
||||
reason = ": #{reason}" unless reason.empty?
|
||||
controller_class, options = @route.recognize(url)
|
||||
assert_not_equal nil, controller_class, "#{@route.inspect} didn't recognize #{url}#{reason}\n #{options}"
|
||||
assert_equal expected_options, options, "#{@route.inspect} produced wrong options for #{url}#{reason}"
|
||||
end
|
||||
|
||||
# The expected url should not have a leading /
|
||||
# You can use @defaults if you want a set of plausible defaults
|
||||
def verify_generate(expected_url, expected_extras, options, defaults, reason='')
|
||||
reason = "#{reason}: " unless reason.empty?
|
||||
components, extras = @route.generate(options, defaults)
|
||||
assert_not_equal nil, components, "#{reason}#{@route.inspect} didn't generate for \n options = #{options.inspect}\n defaults = #{defaults.inspect}\n #{extras}"
|
||||
assert_equal expected_extras, extras, "#{reason} #{@route.inspect}.generate: incorrect extra's"
|
||||
assert_equal expected_url, components.join('/'), "#{reason} #{@route.inspect}.generate: incorrect url"
|
||||
end
|
||||
|
||||
def test_recognize_default_unnested_with_action_and_id
|
||||
verify_recognize('content/action/id', {:controller => 'content', :action => 'action', :id => 'id'})
|
||||
verify_recognize('content/show/10', {:controller => 'content', :action => 'show', :id => '10'})
|
||||
end
|
||||
def test_generate_default_unnested_with_action_and_id_no_extras
|
||||
verify_generate('content/action/id', {}, {:controller => 'content', :action => 'action', :id => 'id'}, @defaults)
|
||||
verify_generate('content/show/10', {}, {:controller => 'content', :action => 'show', :id => '10'}, @defaults)
|
||||
end
|
||||
def test_generate_default_unnested_with_action_and_id
|
||||
verify_generate('content/action/id', {:a => 'a'}, {:controller => 'content', :action => 'action', :id => 'id', :a => 'a'}, @defaults)
|
||||
verify_generate('content/show/10', {:a => 'a'}, {:controller => 'content', :action => 'show', :id => '10', :a => 'a'}, @defaults)
|
||||
end
|
||||
|
||||
# Note that we can't put tests here for proper relative controller handline
|
||||
# because that is handled by RouteSet.
|
||||
def test_recognize_default_nested_with_action_and_id
|
||||
verify_recognize('admin/user/action/id', {:controller => 'admin/user', :action => 'action', :id => 'id'})
|
||||
verify_recognize('admin/user/show/10', {:controller => 'admin/user', :action => 'show', :id => '10'})
|
||||
end
|
||||
def test_generate_default_nested_with_action_and_id_no_extras
|
||||
verify_generate('admin/user/action/id', {}, {:controller => 'admin/user', :action => 'action', :id => 'id'}, @defaults)
|
||||
verify_generate('admin/user/show/10', {}, {:controller => 'admin/user', :action => 'show', :id => '10'}, @defaults)
|
||||
end
|
||||
def test_generate_default_nested_with_action_and_id_relative_to_root
|
||||
verify_generate('admin/user/action/id', {:a => 'a'}, {:controller => 'admin/user', :action => 'action', :id => 'id', :a => 'a'}, @defaults)
|
||||
verify_generate('admin/user/show/10', {:a => 'a'}, {:controller => 'admin/user', :action => 'show', :id => '10', :a => 'a'}, @defaults)
|
||||
end
|
||||
|
||||
def test_recognize_default_nested_with_action
|
||||
verify_recognize('admin/user/action', {:controller => 'admin/user', :action => 'action'})
|
||||
verify_recognize('admin/user/show', {:controller => 'admin/user', :action => 'show'})
|
||||
end
|
||||
def test_generate_default_nested_with_action_no_extras
|
||||
verify_generate('admin/user/action', {}, {:controller => 'admin/user', :action => 'action'}, @defaults)
|
||||
verify_generate('admin/user/show', {}, {:controller => 'admin/user', :action => 'show'}, @defaults)
|
||||
end
|
||||
def test_generate_default_nested_with_action
|
||||
verify_generate('admin/user/action', {:a => 'a'}, {:controller => 'admin/user', :action => 'action', :a => 'a'}, @defaults)
|
||||
verify_generate('admin/user/show', {:a => 'a'}, {:controller => 'admin/user', :action => 'show', :a => 'a'}, @defaults)
|
||||
end
|
||||
|
||||
def test_recognize_default_nested_with_id_and_index
|
||||
verify_recognize('admin/user/index/hello', {:controller => 'admin/user', :id => 'hello', :action => 'index'})
|
||||
verify_recognize('admin/user/index/10', {:controller => 'admin/user', :id => "10", :action => 'index'})
|
||||
end
|
||||
def test_generate_default_nested_with_id_no_extras
|
||||
verify_generate('admin/user/index/hello', {}, {:controller => 'admin/user', :id => 'hello'}, @defaults)
|
||||
verify_generate('admin/user/index/10', {}, {:controller => 'admin/user', :id => 10}, @defaults)
|
||||
end
|
||||
def test_generate_default_nested_with_id
|
||||
verify_generate('admin/user/index/hello', {:a => 'a'}, {:controller => 'admin/user', :id => 'hello', :a => 'a'}, @defaults)
|
||||
verify_generate('admin/user/index/10', {:a => 'a'}, {:controller => 'admin/user', :id => 10, :a => 'a'}, @defaults)
|
||||
end
|
||||
|
||||
def test_recognize_default_nested
|
||||
verify_recognize('admin/user', {:controller => 'admin/user', :action => 'index'})
|
||||
verify_recognize('admin/user', {:controller => 'admin/user', :action => 'index'})
|
||||
end
|
||||
def test_generate_default_nested_no_extras
|
||||
verify_generate('admin/user/', {}, {:controller => 'admin/user'}, @defaults)
|
||||
verify_generate('admin/user/', {}, {:controller => 'admin/user'}, @defaults)
|
||||
end
|
||||
def test_generate_default_nested
|
||||
verify_generate('admin/user/', {:a => 'a'}, {:controller => 'admin/user', :a => 'a'}, @defaults)
|
||||
verify_generate('admin/user/', {:a => 'a'}, {:controller => 'admin/user', :a => 'a'}, @defaults)
|
||||
end
|
||||
|
||||
# Test generate with a default controller set.
|
||||
def test_generate_default_controller
|
||||
route '/:controller/:action/:id', :action => 'index', :id => nil, :controller => 'content'
|
||||
@defaults[:controller] = 'resource'
|
||||
|
||||
verify_generate('', {}, {:controller => 'content'}, @defaults)
|
||||
verify_generate('', {}, {:controller => 'content', :action => 'index'}, @defaults)
|
||||
verify_generate('content/not-index', {}, {:controller => 'content', :action => 'not-index'}, @defaults)
|
||||
verify_generate('content/index/10', {}, {:controller => 'content', :id => 10}, @defaults)
|
||||
verify_generate('content/index/hi', {}, {:controller => 'content', :action => 'index', :id => 'hi'}, @defaults)
|
||||
verify_generate('', {:a => 'a'}, {:controller => 'content', :a => 'a'}, @defaults)
|
||||
verify_generate('', {:a => 'a'}, {:controller => 'content', :a => 'a'}, @defaults)
|
||||
|
||||
# Call some other generator tests
|
||||
test_generate_default_unnested_with_action_and_id
|
||||
test_generate_default_nested_with_action_and_id_no_extras
|
||||
test_generate_default_nested_with_id
|
||||
test_generate_default_nested_with_id_no_extras
|
||||
end
|
||||
|
||||
# Test generate with a default controller set.
|
||||
def test_generate_default_controller
|
||||
route '/:controller/:action/:id', :action => 'index', :id => nil, :controller => 'content'
|
||||
@defaults[:controller] = 'resource'
|
||||
verify_recognize('', {:controller => 'content', :action => 'index'})
|
||||
verify_recognize('content', {:controller => 'content', :action => 'index'})
|
||||
verify_recognize('content/index', {:controller => 'content', :action => 'index'})
|
||||
verify_recognize('content/index/10', {:controller => 'content', :action => 'index', :id => '10'})
|
||||
end
|
||||
# Make sure generation & recognition don't happen in some cases:
|
||||
def test_no_generate_on_no_options
|
||||
assert_equal nil, @route.generate({}, {})[0]
|
||||
end
|
||||
def test_requirements
|
||||
route 'some_static/route', :controller => 'content'
|
||||
assert_equal nil, @route.generate({}, {})[0]
|
||||
assert_equal nil, @route.generate({:controller => "dog"}, {})[0]
|
||||
assert_equal nil, @route.recognize([])[0]
|
||||
assert_equal nil, @route.recognize(%w{some_static route with more than expected})[0]
|
||||
end
|
||||
|
||||
def test_basecamp
|
||||
route 'clients/', :controller => 'content'
|
||||
verify_generate('clients', {}, {:controller => 'content'}, {}) # Would like to have clients/
|
||||
verify_generate('clients', {}, {:controller => 'content'}, @defaults)
|
||||
end
|
||||
|
||||
def test_basecamp2
|
||||
route 'clients/:client_name/:project_name/', :controller => 'content', :action => 'start_page_redirect'
|
||||
verify_recognize('clients/projects/2', {:controller => 'content', :client_name => 'projects', :project_name => '2', :action => 'start_page_redirect'})
|
||||
end
|
||||
|
||||
def test_xal_style_dates
|
||||
route 'articles/:category/:year/:month/:day', :controller => 'content', :action => 'list_articles', :category => 'all', :year => nil, :month => nil, :day =>nil
|
||||
verify_recognize('articles', {:controller => 'content', :action => 'list_articles', :category => 'all'})
|
||||
verify_recognize('articles/porn', {:controller => 'content', :action => 'list_articles', :category => 'porn'})
|
||||
verify_recognize('articles/news/2005/08', {:controller => 'content', :action => 'list_articles', :category => 'news', :year => '2005', :month => '08'})
|
||||
verify_recognize('articles/news/2005/08/04', {:controller => 'content', :action => 'list_articles', :category => 'news', :year => '2005', :month => '08', :day => '04'})
|
||||
assert_equal nil, @route.recognize(%w{articles too many components are here})[0]
|
||||
assert_equal nil, @route.recognize('')[0]
|
||||
|
||||
verify_generate('articles', {}, {:controller => 'content', :action => 'list_articles'}, @defaults)
|
||||
verify_generate('articles', {}, {:controller => 'content', :action => 'list_articles', :category => 'all'}, @defaults)
|
||||
verify_generate('articles/news', {}, {:controller => 'content', :action => 'list_articles', :category => 'news'}, @defaults)
|
||||
verify_generate('articles/news/2005', {}, {:controller => 'content', :action => 'list_articles', :category => 'news', :year => '2005'}, @defaults)
|
||||
verify_generate('articles/news/2005/05', {}, {:controller => 'content', :action => 'list_articles', :category => 'news', :year => '2005', :month => '05'}, @defaults)
|
||||
verify_generate('articles/news/2005/05/16', {}, {:controller => 'content', :action => 'list_articles', :category => 'news', :year => '2005', :month => '05', :day => '16'}, @defaults)
|
||||
|
||||
assert_equal nil, @route.generate({:controller => 'content', :action => 'list_articles', :day => '2'}, @defaults)[0]
|
||||
# The above case should fail because a nil value cannot be present in a path.
|
||||
# In other words, since :day is given, :month and :year must be given too.
|
||||
end
|
||||
|
||||
|
||||
def test_no_controller
|
||||
route 'some/:special/:route', :controller => 'a/missing/controller', :action => 'anything'
|
||||
assert_raises(ActionController::RoutingError, "Should raise due to nonexistant controller") {@route.recognize(%w{some matching path})}
|
||||
end
|
||||
def test_bad_controller_path
|
||||
assert_equal nil, @route.recognize(%w{no such controller fake_action id})[0]
|
||||
end
|
||||
def test_too_short_path
|
||||
assert_equal nil, @route.recognize([])[0]
|
||||
route 'some/static/route', :controller => 'content', :action => 'show'
|
||||
assert_equal nil, route.recognize([])[0]
|
||||
end
|
||||
def test_too_long_path
|
||||
assert_equal nil, @route.recognize(%w{content action id some extra components})[0]
|
||||
end
|
||||
def test_incorrect_static_component
|
||||
route 'some/static/route', :controller => 'content', :action => 'show'
|
||||
assert_equal nil, route.recognize(%w{an non_matching path})[0]
|
||||
end
|
||||
def test_no_controller_defined
|
||||
route 'some/:path/:without/a/controller'
|
||||
assert_equal nil, route.recognize(%w{some matching path a controller})[0]
|
||||
end
|
||||
|
||||
def test_mismatching_requirements
|
||||
route 'some/path', :controller => 'content', :action => 'fish'
|
||||
assert_equal nil, route.generate({:controller => 'admin/user', :action => 'list'})[0]
|
||||
assert_equal nil, route.generate({:controller => 'content', :action => 'list'})[0]
|
||||
assert_equal nil, route.generate({:controller => 'admin/user', :action => 'fish'})[0]
|
||||
end
|
||||
|
||||
def test_missing_value_for_generate
|
||||
assert_equal nil, route.generate({})[0] # :controller is missing
|
||||
end
|
||||
def test_nils_inside_generated_path
|
||||
route 'show/:year/:month/:day', :month => nil, :day => nil, :controller => 'content', :action => 'by_date'
|
||||
assert_equal nil, route.generate({:year => 2005, :day => 10})[0]
|
||||
end
|
||||
|
||||
def test_expand_controller_path_non_nested_no_leftover
|
||||
controller, leftovers = @route.send :eat_path_to_controller, %w{content}
|
||||
assert_equal Controllers::ContentController, controller
|
||||
assert_equal [], leftovers
|
||||
end
|
||||
def test_expand_controller_path_non_nested_with_leftover
|
||||
controller, leftovers = @route.send :eat_path_to_controller, %w{content action id}
|
||||
assert_equal Controllers::ContentController, controller
|
||||
assert_equal %w{action id}, leftovers
|
||||
end
|
||||
def test_expand_controller_path_nested_no_leftover
|
||||
controller, leftovers = @route.send :eat_path_to_controller, %w{admin user}
|
||||
assert_equal Controllers::Admin::UserController, controller
|
||||
assert_equal [], leftovers
|
||||
end
|
||||
def test_expand_controller_path_nested_no_leftover
|
||||
controller, leftovers = @route.send :eat_path_to_controller, %w{admin user action id}
|
||||
assert_equal Controllers::Admin::UserController, controller
|
||||
assert_equal %w{action id}, leftovers
|
||||
end
|
||||
end
|
||||
|
||||
class RouteSetTests < Test::Unit::TestCase
|
||||
def setup
|
||||
@set = ActionController::Routing::RouteSet.new
|
||||
@rails_route = ActionController::Routing::Route.new '/:controller/:action/:id', :action => 'index', :id => nil
|
||||
@request = ActionController::TestRequest.new({}, {}, nil)
|
||||
end
|
||||
def test_emptyness
|
||||
assert_equal true, @set.empty?, "New RouteSets should respond to empty? with true."
|
||||
@set.each { flunk "New RouteSets should be empty." }
|
||||
end
|
||||
def test_add_illegal_route
|
||||
assert_raises(TypeError) {@set.add_route "I'm not actually a route."}
|
||||
end
|
||||
def test_add_normal_route
|
||||
@set.add_route @rails_route
|
||||
seen = false
|
||||
@set.each do |route|
|
||||
assert_equal @rails_route, route
|
||||
flunk("Each should have yielded only a single route!") if seen
|
||||
seen = true
|
||||
end
|
||||
end
|
||||
|
||||
def test_expand_controller_path_non_relative
|
||||
defaults = {:controller => 'admin/user', :action => 'list'}
|
||||
options = {:controller => '/content'}
|
||||
@set.expand_controller_path!(options, defaults)
|
||||
assert_equal({:controller => 'content'}, options)
|
||||
end
|
||||
def test_expand_controller_path_relative_to_nested
|
||||
defaults = {:controller => 'admin/user', :action => 'list'}
|
||||
options = {:controller => 'access'}
|
||||
@set.expand_controller_path!(options, defaults)
|
||||
assert_equal({:controller => 'admin/access'}, options)
|
||||
end
|
||||
def test_expand_controller_path_relative_to_root
|
||||
defaults = {:controller => 'content', :action => 'list'}
|
||||
options = {:controller => 'resource'}
|
||||
@set.expand_controller_path!(options, defaults)
|
||||
assert_equal({:controller => 'resource'}, options)
|
||||
end
|
||||
def test_expand_controller_path_into_module
|
||||
defaults = {:controller => 'content', :action => 'list'}
|
||||
options = {:controller => 'admin/user'}
|
||||
@set.expand_controller_path!(options, defaults)
|
||||
assert_equal({:controller => 'admin/user'}, options)
|
||||
end
|
||||
def test_expand_controller_path_switch_module_with_absolute
|
||||
defaults = {:controller => 'user/news', :action => 'list'}
|
||||
options = {:controller => '/admin/user'}
|
||||
@set.expand_controller_path!(options, defaults)
|
||||
assert_equal({:controller => 'admin/user'}, options)
|
||||
end
|
||||
def test_expand_controller_no_default
|
||||
options = {:controller => 'content'}
|
||||
@set.expand_controller_path!(options, {})
|
||||
assert_equal({:controller => 'content'}, options)
|
||||
end
|
||||
|
||||
# Don't put a leading / on the url.
|
||||
# Make sure the controller is one from the above fake Controllers module.
|
||||
def verify_recognize(expected_controller, expected_path_parameters=nil, path=nil)
|
||||
@set.add_route(@rails_route) if @set.empty?
|
||||
@request.path = path if path
|
||||
controller = @set.recognize!(@request)
|
||||
assert_equal expected_controller, controller
|
||||
assert_equal expected_path_parameters, @request.path_parameters if expected_path_parameters
|
||||
end
|
||||
|
||||
# The expected url should not have a leading /
|
||||
# You can use @defaults if you want a set of plausible defaults
|
||||
def verify_generate(expected_url, options, expected_extras={})
|
||||
@set.add_route(@rails_route) if @set.empty?
|
||||
components, extras = @set.generate(options, @request)
|
||||
assert_equal expected_extras, extras, "#incorrect extra's"
|
||||
assert_equal expected_url, components.join('/'), "incorrect url"
|
||||
end
|
||||
def typical_request
|
||||
@request.path_parameters = {:controller => 'content', :action => 'show', :id => '10'}
|
||||
end
|
||||
def typical_nested_request
|
||||
@request.path_parameters = {:controller => 'admin/user', :action => 'grant', :id => '02seckar'}
|
||||
end
|
||||
|
||||
def test_generate_typical_controller_action_path
|
||||
typical_request
|
||||
verify_generate('content/list', {:controller => 'content', :action => 'list'})
|
||||
end
|
||||
def test_generate_typical_controller_index_path_explicit_index
|
||||
typical_request
|
||||
verify_generate('content/', {:controller => 'content', :action => 'index'})
|
||||
end
|
||||
def test_generate_typical_controller_index_path_explicit_index
|
||||
typical_request
|
||||
verify_generate('content/', {:controller => 'content', :action => 'index'})
|
||||
end
|
||||
def test_generate_typical_controller_index_path_implicit_index
|
||||
typical_request
|
||||
@request.path_parameters[:controller] = 'resource'
|
||||
verify_generate('content/', {:controller => 'content'})
|
||||
end
|
||||
|
||||
def test_generate_no_perfect_route
|
||||
typical_request
|
||||
verify_generate('admin/user/show/43seckar', {:controller => 'admin/user', :action => 'show', :id => '43seckar', :likes_fishing => 'fuzzy(0.3)'}, {:likes_fishing => 'fuzzy(0.3)'})
|
||||
end
|
||||
|
||||
def test_generate_no_match
|
||||
@set.add_route(@rails_route)
|
||||
@request.path_parameters = {}
|
||||
assert_raises(ActionController::RoutingError) {@set.generate({}, @request)}
|
||||
end
|
||||
|
||||
|
||||
def test_encoded_strings
|
||||
verify_recognize(Controllers::Admin::UserController, {:controller => 'admin/user', :action => 'info', :id => "Nicholas Seckar"}, path='/admin/user/info/Nicholas%20Seckar')
|
||||
end
|
||||
end
|
||||
|
||||
#require '../assertions/action_pack_assertions.rb'
|
||||
class AssertionRoutingTests < Test::Unit::TestCase
|
||||
def test_assert_routing
|
||||
ActionController::Routing::Routes.reload rescue nil
|
||||
assert_routing('content/', {:controller => 'content', :action => 'index'})
|
||||
end
|
||||
end
|
487
actionpack/test/controller/url_obsolete.rb
Normal file
487
actionpack/test/controller/url_obsolete.rb
Normal file
|
@ -0,0 +1,487 @@
|
|||
require File.dirname(__FILE__) + '/../abstract_unit'
|
||||
require 'action_controller/url_rewriter'
|
||||
|
||||
MockRequest = Struct.new("MockRequest", :protocol, :host, :port, :path, :parameters, :path_parameters)
|
||||
class MockRequest
|
||||
def host_with_port
|
||||
if (protocol == "http://" && port == 80) || (protocol == "https://" && port == 443)
|
||||
host
|
||||
else
|
||||
host + ":#{port}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class UrlMockFactory
|
||||
def self.create(path, parameters)
|
||||
ActionController::UrlRewriter.new(
|
||||
MockRequest.new("http://", "example.com", 80, path, parameters),
|
||||
parameters
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
# old-style support for .new
|
||||
module ActionController
|
||||
class UrlRewriter
|
||||
def self.old_new(request, controller, action)
|
||||
request.parameters[:controller] = controller
|
||||
request.parameters[:action] = action
|
||||
return new(request, request.parameters)
|
||||
end
|
||||
end
|
||||
end
|
||||
class UrlTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@library_url = ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://",
|
||||
"www.singlefile.com",
|
||||
80,
|
||||
"/library/books/ISBN/0743536703/show",
|
||||
{ "type" => "ISBN", "code" => "0743536703" }
|
||||
), "books", "show")
|
||||
|
||||
@library_url_using_module = ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://",
|
||||
"www.singlefile.com",
|
||||
80,
|
||||
"/library/books/ISBN/0743536703/show",
|
||||
{ "type" => "ISBN", "code" => "0743536703", "module" => "library" }
|
||||
), "books", "show")
|
||||
|
||||
@library_url_on_index = ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://",
|
||||
"www.singlefile.com",
|
||||
80,
|
||||
"/library/books/ISBN/0743536703/",
|
||||
{ "type" => "ISBN", "code" => "0743536703" }
|
||||
), "books", "index")
|
||||
|
||||
@clean_urls = [
|
||||
ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://", "www.singlefile.com", 80, "/identity/", {}
|
||||
), "identity", "index"),
|
||||
ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://", "www.singlefile.com", 80, "/identity", {}
|
||||
), "identity", "index")
|
||||
]
|
||||
|
||||
@clean_url_with_id = ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://", "www.singlefile.com", 80, "/identity/show/5", { "id" => "5" }
|
||||
), "identity", "show")
|
||||
|
||||
@clean_url_with_same_action_and_controller_name = ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://", "www.singlefile.com", 80, "/login/login", { }
|
||||
), "login", "login")
|
||||
|
||||
@clean_url_with_same_action_and_controller_and_module_name = ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://", "www.singlefile.com", 80, "/login/login/login", { "module" => "login" }
|
||||
), "login", "login")
|
||||
|
||||
@clean_url_with_id_as_char = ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://", "www.singlefile.com", 80, "/teachers/show/t", { "id" => "t" }
|
||||
), "teachers", "show")
|
||||
end
|
||||
|
||||
def test_clean_action
|
||||
assert_equal "http://www.singlefile.com/library/books/ISBN/0743536703/edit", @library_url.rewrite(:action => "edit")
|
||||
end
|
||||
|
||||
def test_clean_action_to_another_host
|
||||
assert_equal(
|
||||
"http://www.booksphere.com/library/books/ISBN/0743536703/edit",
|
||||
@library_url.rewrite(:action => "edit", :host => "www.booksphere.com")
|
||||
)
|
||||
end
|
||||
|
||||
def test_clean_action_to_another_host_and_protocol
|
||||
assert_equal(
|
||||
"https://www.booksphere.com/library/books/ISBN/0743536703/edit",
|
||||
@library_url.rewrite(:action => "edit", :host => "www.booksphere.com", :protocol => "https://")
|
||||
)
|
||||
end
|
||||
|
||||
def test_clean_action_with_only_path
|
||||
assert_equal "/library/books/ISBN/0743536703/edit", @library_url.rewrite(:action => "edit", :only_path => true)
|
||||
end
|
||||
|
||||
def test_action_from_index
|
||||
assert_equal "http://www.singlefile.com/library/books/ISBN/0743536703/edit", @library_url_on_index.rewrite(:action => "edit")
|
||||
end
|
||||
|
||||
def test_action_from_index_on_clean
|
||||
@clean_urls.each do |url|
|
||||
assert_equal "http://www.singlefile.com/identity/edit", url.rewrite(:action => "edit")
|
||||
end
|
||||
end
|
||||
|
||||
def test_action_without_prefix
|
||||
assert_equal "http://www.singlefile.com/library/books/", @library_url.rewrite(:action => "index", :action_prefix => "")
|
||||
end
|
||||
|
||||
def test_action_with_prefix
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/books/XTC/123/show",
|
||||
@library_url.rewrite(:action => "show", :action_prefix => "XTC/123")
|
||||
)
|
||||
end
|
||||
|
||||
def test_action_prefix_alone
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/books/XTC/123/",
|
||||
@library_url.rewrite(:action_prefix => "XTC/123")
|
||||
)
|
||||
end
|
||||
|
||||
def test_action_with_suffix
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/books/show/XTC/123",
|
||||
@library_url.rewrite(:action => "show", :action_prefix => "", :action_suffix => "XTC/123")
|
||||
)
|
||||
end
|
||||
|
||||
def test_clean_controller
|
||||
assert_equal "http://www.singlefile.com/library/settings/", @library_url.rewrite(:controller => "settings")
|
||||
end
|
||||
|
||||
def test_clean_controller_prefix
|
||||
assert_equal "http://www.singlefile.com/shop/", @library_url.rewrite(:controller_prefix => "shop")
|
||||
end
|
||||
|
||||
def test_clean_controller_with_module
|
||||
assert_equal "http://www.singlefile.com/shop/purchases/", @library_url.rewrite(:module => "shop", :controller => "purchases")
|
||||
end
|
||||
|
||||
def test_getting_out_of_a_module
|
||||
assert_equal "http://www.singlefile.com/purchases/", @library_url_using_module.rewrite(:module => false, :controller => "purchases")
|
||||
end
|
||||
|
||||
def test_controller_and_action
|
||||
assert_equal "http://www.singlefile.com/library/settings/show", @library_url.rewrite(:controller => "settings", :action => "show")
|
||||
end
|
||||
|
||||
def test_controller_and_action_and_anchor
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/settings/show#5",
|
||||
@library_url.rewrite(:controller => "settings", :action => "show", :anchor => "5")
|
||||
)
|
||||
end
|
||||
|
||||
def test_controller_and_action_and_empty_overwrite_params_and_anchor
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/settings/show?code=0743536703&type=ISBN#5",
|
||||
@library_url.rewrite(:controller => "settings", :action => "show", :overwrite_params => {}, :anchor => "5")
|
||||
)
|
||||
end
|
||||
|
||||
def test_controller_and_action_and_overwrite_params_and_anchor
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/settings/show?code=0000001&type=ISBN#5",
|
||||
@library_url.rewrite(:controller => "settings", :action => "show", :overwrite_params => {"code"=>"0000001"}, :anchor => "5")
|
||||
)
|
||||
end
|
||||
|
||||
def test_controller_and_action_and_overwrite_params_with_nil_value_and_anchor
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/settings/show?type=ISBN#5",
|
||||
@library_url.rewrite(:controller => "settings", :action => "show", :overwrite_params => {"code" => nil}, :anchor => "5")
|
||||
)
|
||||
end
|
||||
|
||||
def test_controller_and_action_params_and_overwrite_params_and_anchor
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/settings/show?code=0000001&version=5.0#5",
|
||||
@library_url.rewrite(:controller => "settings", :action => "show", :params=>{"version" => "5.0"}, :overwrite_params => {"code"=>"0000001"}, :anchor => "5")
|
||||
)
|
||||
end
|
||||
|
||||
def test_controller_and_action_and_params_anchor
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/settings/show?update=1#5",
|
||||
@library_url.rewrite(:controller => "settings", :action => "show", :params => { "update" => "1"}, :anchor => "5")
|
||||
)
|
||||
end
|
||||
|
||||
def test_controller_and_index_action
|
||||
assert_equal "http://www.singlefile.com/library/settings/", @library_url.rewrite(:controller => "settings", :action => "index")
|
||||
end
|
||||
|
||||
def test_same_controller_and_action_names
|
||||
assert_equal "http://www.singlefile.com/login/logout", @clean_url_with_same_action_and_controller_name.rewrite(:action => "logout")
|
||||
end
|
||||
|
||||
def xtest_same_module_and_controller_and_action_names
|
||||
assert_equal "http://www.singlefile.com/login/login/logout", @clean_url_with_same_action_and_controller_and_module_name.rewrite(:action => "logout")
|
||||
end
|
||||
|
||||
def test_controller_and_action_with_same_name_as_controller
|
||||
@clean_urls.each do |url|
|
||||
assert_equal "http://www.singlefile.com/anything/identity", url.rewrite(:controller => "anything", :action => "identity")
|
||||
end
|
||||
end
|
||||
|
||||
def test_controller_and_index_action_without_controller_prefix
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/settings/",
|
||||
@library_url.rewrite(:controller => "settings", :action => "index", :controller_prefix => "")
|
||||
)
|
||||
end
|
||||
|
||||
def test_controller_and_index_action_with_controller_prefix
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/fantastic/settings/show",
|
||||
@library_url.rewrite(:controller => "settings", :action => "show", :controller_prefix => "fantastic")
|
||||
)
|
||||
end
|
||||
|
||||
def test_path_parameters
|
||||
assert_equal "http://www.singlefile.com/library/books/EXBC/0743536703/show", @library_url.rewrite(:path_params => {"type" => "EXBC"})
|
||||
end
|
||||
|
||||
def test_parameters
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/books/ISBN/0743536703/show?delete=1&name=David",
|
||||
@library_url.rewrite(:params => {"delete" => "1", "name" => "David"})
|
||||
)
|
||||
end
|
||||
|
||||
def test_parameters_with_id
|
||||
@clean_urls.each do |url|
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/show?name=David&id=5",
|
||||
url.rewrite(
|
||||
:action => "show",
|
||||
:params => { "id" => "5", "name" => "David" }
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_parameters_with_array
|
||||
@clean_urls.each do |url|
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/show?id[]=3&id[]=5&id[]=10",
|
||||
url.rewrite(
|
||||
:action => "show",
|
||||
:params => { 'id' => [ 3, 5, 10 ] } )
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_action_with_id
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/show/7",
|
||||
@clean_url_with_id.rewrite(
|
||||
:action => "show",
|
||||
:id => 7
|
||||
)
|
||||
)
|
||||
@clean_urls.each do |url|
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/index/7",
|
||||
url.rewrite(:id => 7)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_parameters_with_id_and_away
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/show/25?name=David",
|
||||
@clean_url_with_id.rewrite(
|
||||
:path_params => { "id" => "25" },
|
||||
:params => { "name" => "David" }
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def test_parameters_with_index_and_id
|
||||
@clean_urls.each do |url|
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/index/25?name=David",
|
||||
url.rewrite(
|
||||
:path_params => { "id" => "25" },
|
||||
:params => { "name" => "David" }
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_action_going_away_from_id
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/list",
|
||||
@clean_url_with_id.rewrite(
|
||||
:action => "list"
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def test_parameters_with_direct_id_and_away
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/show/25?name=David",
|
||||
@clean_url_with_id.rewrite(
|
||||
:id => "25",
|
||||
:params => { "name" => "David" }
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def test_parameters_with_direct_id_and_away
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/store/open/25?name=David",
|
||||
@clean_url_with_id.rewrite(
|
||||
:controller => "store",
|
||||
:action => "open",
|
||||
:id => "25",
|
||||
:params => { "name" => "David" }
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def test_parameters_to_id
|
||||
@clean_urls.each do |url|
|
||||
%w(show index).each do |action|
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/#{action}/25?name=David",
|
||||
url.rewrite(
|
||||
:action => action,
|
||||
:path_params => { "id" => "25" },
|
||||
:params => { "name" => "David" }
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_parameters_from_id
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/",
|
||||
@clean_url_with_id.rewrite(
|
||||
:action => "index"
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def test_id_as_char_and_part_of_controller
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/teachers/skill/5",
|
||||
@clean_url_with_id_as_char.rewrite(
|
||||
:action => "skill",
|
||||
:id => 5
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def test_from_clean_to_library
|
||||
@clean_urls.each do |url|
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/library/books/ISBN/0743536703/show?delete=1&name=David",
|
||||
url.rewrite(
|
||||
:controller_prefix => "library",
|
||||
:controller => "books",
|
||||
:action_prefix => "ISBN/0743536703",
|
||||
:action => "show",
|
||||
:params => { "delete" => "1", "name" => "David" }
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def test_from_library_to_clean
|
||||
assert_equal(
|
||||
"http://www.singlefile.com/identity/",
|
||||
@library_url.rewrite(
|
||||
:controller => "identity", :controller_prefix => ""
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def test_from_another_port
|
||||
@library_url = ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://",
|
||||
"www.singlefile.com",
|
||||
8080,
|
||||
"/library/books/ISBN/0743536703/show",
|
||||
{ "type" => "ISBN", "code" => "0743536703" }
|
||||
), "books", "show")
|
||||
|
||||
assert_equal(
|
||||
"http://www.singlefile.com:8080/identity/",
|
||||
@library_url.rewrite(
|
||||
:controller => "identity", :controller_prefix => ""
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def test_basecamp
|
||||
basecamp_url = ActionController::UrlRewriter.old_new(MockRequest.new(
|
||||
"http://",
|
||||
"projects.basecamp",
|
||||
80,
|
||||
"/clients/disarray/1/msg/transcripts/",
|
||||
{"category_name"=>"transcripts", "client_name"=>"disarray", "action"=>"index", "controller"=>"msg", "project_name"=>"1"}
|
||||
), "msg", "index")
|
||||
|
||||
assert_equal(
|
||||
"http://projects.basecamp/clients/disarray/1/msg/transcripts/1/comments",
|
||||
basecamp_url.rewrite(:action_prefix => "transcripts/1", :action => "comments")
|
||||
)
|
||||
end
|
||||
|
||||
def test_on_explicit_index_page # My index page is very modest, thank you...
|
||||
url = ActionController::UrlRewriter.old_new(
|
||||
MockRequest.new(
|
||||
"http://", "example.com", 80, "/controller/index",
|
||||
{"controller"=>"controller", "action"=>"index"}
|
||||
), "controller", "index"
|
||||
)
|
||||
assert_equal("http://example.com/controller/foo", url.rewrite(:action => 'foo'))
|
||||
end
|
||||
|
||||
def test_rewriting_on_similar_fragments
|
||||
url = UrlMockFactory.create("/advertisements/advert/", {"controller"=>"advert", "action"=>"index"})
|
||||
assert_equal("http://example.com/advertisements/advert/news", url.rewrite(:action => 'news'))
|
||||
end
|
||||
|
||||
def test_rewriting_on_similar_fragments_with_action_prefixes
|
||||
url = UrlMockFactory.create(
|
||||
"/clients/prall/1/msg/all/",
|
||||
{ "category_name"=>"all", "client_name"=>"prall", "action"=>"index", "controller"=>"msg", "project_name"=>"1"}
|
||||
)
|
||||
|
||||
assert_equal(
|
||||
"http://example.com/clients/prall/1/msg/all/new",
|
||||
url.rewrite({ :controller => "msg", :action_prefix => "all", :action => "new" })
|
||||
)
|
||||
|
||||
url = UrlMockFactory.create(
|
||||
"/clients/prall/1/msg/all/",
|
||||
{ "category_name"=>"all", "client_name"=>"prall", "action"=>"index", "controller"=>"msg", "project_name"=>"1"}
|
||||
)
|
||||
|
||||
assert_equal(
|
||||
"http://example.com/clients/prall/1/msg/allous/new",
|
||||
url.rewrite({ :controller => "msg", :action_prefix => "allous", :action => "new" })
|
||||
)
|
||||
end
|
||||
|
||||
def test_clean_application_prefix
|
||||
assert_equal "http://www.singlefile.com/namespace/library/books/ISBN/0743536703/show",
|
||||
@library_url.rewrite(:application_prefix => "/namespace")
|
||||
end
|
||||
|
||||
def test_clean_application_prefix_with_controller_prefix
|
||||
assert_equal "http://www.singlefile.com/namespace/shop/",
|
||||
@library_url.rewrite(:application_prefix => "/namespace",
|
||||
:controller_prefix => "shop" )
|
||||
end
|
||||
|
||||
def test_blank_application_prefix
|
||||
assert_equal "http://www.singlefile.com/library/books/ISBN/0743536703/show",
|
||||
@library_url.rewrite(:application_prefix => "")
|
||||
end
|
||||
|
||||
def test_nil_application_prefix
|
||||
assert_equal "http://www.singlefile.com/library/books/ISBN/0743536703/show",
|
||||
@library_url.rewrite(:application_prefix => nil)
|
||||
end
|
||||
end
|
1
actionpack/test/fixtures/fun/games/hello_world.rhtml
vendored
Normal file
1
actionpack/test/fixtures/fun/games/hello_world.rhtml
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
Living in a nested world
|
3
actionpack/test/fixtures/helpers/fun/games_helper.rb
vendored
Normal file
3
actionpack/test/fixtures/helpers/fun/games_helper.rb
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
module Fun::GamesHelper
|
||||
def stratego() "Iz guuut!" end
|
||||
end
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
* Added IndifferentAccess as a way to wrap a hash by a symbol-based store that also can be accessed by string keys
|
||||
|
||||
* Added Inflector.constantize to turn "Admin::User" into a reference for the constant Admin::User
|
||||
|
||||
* Added that Inflector.camelize and Inflector.underscore can deal with modules like turning "Admin::User" into "admin/user" and back
|
||||
|
||||
* Added Inflector.humanize to turn attribute names like employee_salary into "Employee salary". Used by automated error reporting in AR.
|
||||
|
||||
* Added availability of class inheritable attributes to the masses #477 [bitsweat]
|
||||
|
|
|
@ -8,17 +8,17 @@ class HashWithIndifferentAccess < Hash
|
|||
end
|
||||
end
|
||||
|
||||
alias_method :regular_read, :[]
|
||||
alias_method :regular_reader, :[] unless method_defined?(:regular_reader)
|
||||
|
||||
def [](key)
|
||||
case key
|
||||
when Symbol: regular_read(key) || regular_read(key.to_s)
|
||||
when String: regular_read(key) || regular_read(key.to_sym)
|
||||
else regular_read(key)
|
||||
when Symbol: regular_reader(key) || regular_reader(key.to_s)
|
||||
when String: regular_reader(key) || regular_reader(key.to_sym)
|
||||
else regular_reader(key)
|
||||
end
|
||||
end
|
||||
|
||||
alias_method :regular_writer, :[]=
|
||||
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
|
||||
|
||||
def []=(key, value)
|
||||
regular_writer(key.is_a?(String) ? key.to_sym : key, value)
|
||||
|
|
|
@ -39,6 +39,10 @@ module ActiveSupport #:nodoc:
|
|||
def foreign_key(separate_class_name_and_id_with_underscore = true)
|
||||
Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
|
||||
end
|
||||
|
||||
def constantize
|
||||
Inflector.constantize(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/module_attribute_accessors'
|
|||
|
||||
module Dependencies
|
||||
extend self
|
||||
|
||||
|
||||
@@loaded = [ ]
|
||||
mattr_accessor :loaded
|
||||
|
||||
|
@ -41,6 +41,68 @@ module Dependencies
|
|||
def remove_subclasses_for(*classes)
|
||||
classes.each { |klass| klass.remove_subclasses }
|
||||
end
|
||||
|
||||
# LoadingModules implement namespace-safe dynamic loading.
|
||||
# They support automatic loading via const_missing, allowing contained items to be automatically
|
||||
# loaded when required. No extra syntax is required, as expressions such as Controller::Admin::UserController
|
||||
# load the relavent files automatically.
|
||||
#
|
||||
# Ruby-style modules are supported, as a folder named 'submodule' will load 'submodule.rb' when available.
|
||||
class LoadingModule < Module
|
||||
attr_reader :path
|
||||
|
||||
def initialize(filesystem_root, path=[])
|
||||
@path = path
|
||||
@filesystem_root = filesystem_root
|
||||
end
|
||||
|
||||
# The path to this module in the filesystem.
|
||||
# Any subpath provided is taken to be composed of filesystem names.
|
||||
def filesystem_path(subpath=[])
|
||||
File.join(@filesystem_root, self.path, subpath)
|
||||
end
|
||||
|
||||
# Load missing constants if possible.
|
||||
def const_missing(name)
|
||||
return const_get(name) if const_defined?(name) == false && const_load!(name)
|
||||
super(name)
|
||||
end
|
||||
|
||||
# Load the controller class or a parent module.
|
||||
def const_load!(name)
|
||||
name = name.to_s if name.kind_of? Symbol
|
||||
|
||||
if File.directory? filesystem_path(name.underscore)
|
||||
# Is it a submodule? If so, create a new LoadingModule *before* loading it.
|
||||
# This ensures that subitems will be loadable
|
||||
new_module = LoadingModule.new(@filesystem_root, self.path + [name.underscore])
|
||||
const_set(name, new_module)
|
||||
Object.const_set(name, new_module) if @path.empty?
|
||||
end
|
||||
|
||||
source_file = filesystem_path("#{(name == 'ApplicationController' ? 'Application' : name).underscore}.rb")
|
||||
self.load_file(source_file) if File.file?(source_file)
|
||||
self.const_defined?(name.camelize)
|
||||
end
|
||||
|
||||
# Is this name present or loadable?
|
||||
# This method is used by Routes to find valid controllers.
|
||||
def const_available?(name)
|
||||
name = name.to_s unless name.kind_of? String
|
||||
File.directory?(filesystem_path(name.underscore)) || File.file?(filesystem_path("#{name.underscore}.rb"))
|
||||
end
|
||||
|
||||
def clear
|
||||
constants.each do |name|
|
||||
Object.send(:remove_const, name) if Object.const_defined?(name) && @path.empty?
|
||||
self.send(:remove_const, name)
|
||||
end
|
||||
end
|
||||
|
||||
def load_file(file_path)
|
||||
Controllers.module_eval(IO.read(file_path), file_path, 1) # Hard coded Controller line here!!!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Object.send(:define_method, :require_or_load) { |file_name| Dependencies.require_or_load(file_name) } unless Object.respond_to?(:require_or_load)
|
||||
|
@ -52,6 +114,9 @@ class Object #:nodoc:
|
|||
# Use const_missing to autoload associations so we don't have to
|
||||
# require_association when using single-table inheritance.
|
||||
def const_missing(class_id)
|
||||
if Object.const_defined?(:Controllers) and Object::Controllers.const_available?(class_id)
|
||||
return Object::Controllers.const_get(class_id)
|
||||
end
|
||||
begin
|
||||
require_or_load(class_id.to_s.demodulize.underscore)
|
||||
if Object.const_defined?(class_id) then return Object.const_get(class_id) else raise LoadError end
|
||||
|
|
|
@ -20,11 +20,11 @@ module Inflector
|
|||
end
|
||||
|
||||
def camelize(lower_case_and_underscored_word)
|
||||
lower_case_and_underscored_word.to_s.gsub(/(^|_)(.)/){$2.upcase}
|
||||
lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
|
||||
end
|
||||
|
||||
def underscore(camel_cased_word)
|
||||
camel_cased_word.to_s.gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
|
||||
camel_cased_word.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z])/,'\1_\2').gsub(/([a-z])([A-Z])/,'\1_\2').downcase
|
||||
end
|
||||
|
||||
def humanize(lower_case_and_underscored_word)
|
||||
|
@ -47,7 +47,13 @@ module Inflector
|
|||
Inflector.underscore(Inflector.demodulize(class_name)) +
|
||||
(separate_class_name_and_id_with_underscore ? "_id" : "id")
|
||||
end
|
||||
|
||||
|
||||
def constantize(camel_cased_word)
|
||||
camel_cased_word.split("::").inject(Object) do |final_type, part|
|
||||
final_type = final_type.const_get(part)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def plural_rules #:doc:
|
||||
[
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
require 'test/unit'
|
||||
require File.dirname(__FILE__) + '/../lib/inflector'
|
||||
|
||||
module A
|
||||
module B
|
||||
class C
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class InflectorTest < Test::Unit::TestCase
|
||||
SingularToPlural = {
|
||||
"search" => "searches",
|
||||
|
@ -50,6 +57,12 @@ class InflectorTest < Test::Unit::TestCase
|
|||
"SpecialGuest" => "special_guest",
|
||||
"ApplicationController" => "application_controller"
|
||||
}
|
||||
|
||||
CamelWithModuleToUnderscoreWithSlash = {
|
||||
"Admin::Product" => "admin/product",
|
||||
"Users::Commission::Department" => "users/commission/department",
|
||||
"UsersSection::CommissionDepartment" => "users_section/commission_department",
|
||||
}
|
||||
|
||||
ClassNameToForeignKeyWithUnderscore = {
|
||||
"Person" => "person_id",
|
||||
|
@ -100,6 +113,18 @@ class InflectorTest < Test::Unit::TestCase
|
|||
assert_equal "html_tidy_generator", Inflector.underscore("HTMLTidyGenerator")
|
||||
end
|
||||
|
||||
def test_camelize_with_module
|
||||
CamelWithModuleToUnderscoreWithSlash.each do |camel, underscore|
|
||||
assert_equal(camel, Inflector.camelize(underscore))
|
||||
end
|
||||
end
|
||||
|
||||
def test_underscore_with_slashes
|
||||
CamelWithModuleToUnderscoreWithSlash.each do |camel, underscore|
|
||||
assert_equal(underscore, Inflector.underscore(camel))
|
||||
end
|
||||
end
|
||||
|
||||
def test_demodulize
|
||||
assert_equal "Account", Inflector.demodulize("MyApplication::Billing::Account")
|
||||
end
|
||||
|
@ -131,4 +156,10 @@ class InflectorTest < Test::Unit::TestCase
|
|||
assert_equal(human, Inflector.humanize(underscore))
|
||||
end
|
||||
end
|
||||
|
||||
def test_constantize
|
||||
assert_equal A::B::C, Inflector.constantize("A::B::C")
|
||||
assert_equal InflectorTest, Inflector.constantize("InflectorTest")
|
||||
assert_raises(NameError) { Inflector.constantize("UnknownClass") }
|
||||
end
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
class Admin::AccessController
|
||||
end
|
|
@ -0,0 +1,2 @@
|
|||
class Admin::UserController
|
||||
end
|
2
activesupport/test/loading_module/content_controller.rb
Normal file
2
activesupport/test/loading_module/content_controller.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
class ContentController
|
||||
end
|
2
activesupport/test/loading_module/resource_controller.rb
Normal file
2
activesupport/test/loading_module/resource_controller.rb
Normal file
|
@ -0,0 +1,2 @@
|
|||
class ResourceController
|
||||
end
|
63
activesupport/test/loading_module_tests.rb
Normal file
63
activesupport/test/loading_module_tests.rb
Normal file
|
@ -0,0 +1,63 @@
|
|||
require 'test/unit'
|
||||
require '../lib/core_ext.rb'
|
||||
require '../lib/dependencies.rb'
|
||||
|
||||
STAGING_DIRECTORY = 'loading_module'
|
||||
|
||||
class LoadingModuleTests < Test::Unit::TestCase
|
||||
def setup
|
||||
@loading_module = Dependencies::LoadingModule.new(STAGING_DIRECTORY)
|
||||
Object.const_set(:Controllers, @loading_module)
|
||||
end
|
||||
def teardown
|
||||
@loading_module.clear
|
||||
Object.send :remove_const, :Controllers
|
||||
end
|
||||
|
||||
def test_setup
|
||||
assert_kind_of Dependencies::LoadingModule, @loading_module
|
||||
end
|
||||
|
||||
def test_const_available
|
||||
assert @loading_module.const_available?(:Admin)
|
||||
assert @loading_module.const_available?(:ResourceController)
|
||||
assert @loading_module.const_available?(:ContentController)
|
||||
assert @loading_module.const_available?("ContentController")
|
||||
|
||||
assert_equal false, @loading_module.const_available?(:AdminController)
|
||||
assert_equal false, @loading_module.const_available?(:RandomName)
|
||||
end
|
||||
|
||||
def test_const_load_module
|
||||
assert @loading_module.const_load!(:Admin)
|
||||
assert_kind_of Module, @loading_module::Admin
|
||||
assert_kind_of Dependencies::LoadingModule, @loading_module::Admin
|
||||
end
|
||||
|
||||
def test_const_load_controller
|
||||
assert @loading_module.const_load!(:ContentController)
|
||||
assert_kind_of Class, @loading_module::ContentController
|
||||
end
|
||||
|
||||
def test_const_load_nested_controller
|
||||
assert @loading_module.const_load!(:Admin)
|
||||
assert @loading_module::Admin.const_available?(:UserController)
|
||||
assert @loading_module::Admin.const_load!(:UserController)
|
||||
assert_kind_of Class, @loading_module::Admin::UserController
|
||||
end
|
||||
|
||||
def test_pretty_access
|
||||
assert_kind_of Module, @loading_module::Admin
|
||||
assert_kind_of Dependencies::LoadingModule, @loading_module::Admin
|
||||
|
||||
assert_kind_of Class, @loading_module::Admin::UserController
|
||||
assert_kind_of Class, @loading_module::Admin::AccessController
|
||||
assert_kind_of Class, @loading_module::ResourceController
|
||||
assert_kind_of Class, @loading_module::ContentController
|
||||
end
|
||||
|
||||
def test_missing_name
|
||||
assert_raises(NameError) {@loading_module::PersonController}
|
||||
assert_raises(NameError) {@loading_module::Admin::FishController}
|
||||
end
|
||||
end
|
|
@ -132,6 +132,7 @@ end
|
|||
|
||||
task :copy_configs do
|
||||
cp "configs/database.yml", "#{PKG_DESTINATION}/config/database.yml"
|
||||
cp "configs/routes.rb", "#{PKG_DESTINATION}/config/routes.rb"
|
||||
|
||||
cp "configs/apache.conf", "#{PKG_DESTINATION}/public/.htaccess"
|
||||
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require File.dirname(__FILE__) + '/../config/environment'
|
||||
require 'rails_generator'
|
||||
require 'rails_generator/simple_logger'
|
||||
require 'rails_generator/scripts/destroy'
|
||||
|
||||
Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)
|
||||
Rails::Generator::Scripts::Destroy.new.run(ARGV)
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require File.dirname(__FILE__) + '/../config/environment'
|
||||
require 'rails_generator'
|
||||
require 'rails_generator/simple_logger'
|
||||
require 'rails_generator/scripts/generate'
|
||||
|
||||
Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)
|
||||
Rails::Generator::Scripts::Generate.new.run(ARGV)
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
require File.dirname(__FILE__) + '/../lib/rails_generator'
|
||||
require 'rails_generator/simple_logger'
|
||||
require 'rails_generator/scripts/generate'
|
||||
|
||||
Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)
|
||||
Rails::Generator::Base.use_application_sources!
|
||||
Rails::Generator::Scripts::Generate.new.run(ARGV, :generator => 'app')
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
#!/usr/local/bin/ruby
|
||||
require File.dirname(__FILE__) + '/../config/environment'
|
||||
require 'rails_generator'
|
||||
require 'rails_generator/simple_logger'
|
||||
require 'rails_generator/scripts/update'
|
||||
|
||||
Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)
|
||||
Rails::Generator::Scripts::Update.new.run(ARGV)
|
||||
|
|
|
@ -1,61 +1,5 @@
|
|||
# General Apache options
|
||||
AddHandler fastcgi-script .fcgi
|
||||
AddHandler cgi-script .cgi
|
||||
Options +FollowSymLinks +ExecCGI
|
||||
|
||||
# Make sure that mod_ruby.c has been added and loaded as a module with Apache
|
||||
RewriteEngine On
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(.*)$ /dispatch.fcgi?$1 [QSA,L]
|
||||
|
||||
# Change extension from .cgi to .fcgi to switch to FCGI and to .rb to switch to mod_ruby
|
||||
RewriteBase /dispatch.cgi
|
||||
|
||||
# Enable this rewrite rule to point to the controller/action that should serve root.
|
||||
# RewriteRule ^$ /controller/action [R]
|
||||
|
||||
# <caching>
|
||||
# no query string?
|
||||
RewriteCond %{QUERY_STRING} ^$
|
||||
|
||||
# no POST method?
|
||||
RewriteCond %{REQUEST_METHOD} !^POST$ [NC]
|
||||
|
||||
# Request filename is a directory?
|
||||
RewriteCond %{REQUEST_FILENAME} -d
|
||||
|
||||
# Request filename + '/index' is a file?
|
||||
RewriteCond %{REQUEST_FILENAME}/index -f
|
||||
|
||||
# Rewrite to request filename + '/index' and finish
|
||||
RewriteRule ^(.*)/?$ $1/index [QSA,L]
|
||||
|
||||
# no query string?
|
||||
RewriteCond %{QUERY_STRING} ^$
|
||||
|
||||
# no POST method?
|
||||
RewriteCond %{REQUEST_METHOD} !^POST$ [NC]
|
||||
|
||||
# Request filename is a file?
|
||||
RewriteCond %{REQUEST_FILENAME} -f
|
||||
|
||||
# Finish rewriting
|
||||
RewriteRule .* - [L]
|
||||
|
||||
# Set default type of cached files to text/html
|
||||
DefaultType text/html
|
||||
# </caching>
|
||||
|
||||
# Add missing slash
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)$ /$1/ [R]
|
||||
|
||||
# Default rewriting rules.
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ ?controller=$1&action=$2&id=$3 [QSA,L]
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ ?controller=$1&action=$2 [QSA,L]
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/$ ?controller=$1&action=index [QSA,L]
|
||||
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([0-9]+)$ ?module=$1&controller=$2&action=$3&id=$4 [QSA,L]
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)$ ?module=$1&controller=$2&action=$3 [QSA,L]
|
||||
RewriteRule ^([-_a-zA-Z0-9]+)/([-_a-zA-Z0-9]+)/$ ?module=$1&controller=$2&action=index [QSA,L]
|
||||
|
||||
# You can also point these error messages to a controller/action
|
||||
ErrorDocument 500 /500.html
|
||||
ErrorDocument 404 /404.html
|
11
railties/configs/routes.rb
Normal file
11
railties/configs/routes.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
ActionController::Routing::Routes.draw do |map|
|
||||
# Add your own custom routes here.
|
||||
# The priority is based upon order of creation: first created -> highest priority.
|
||||
|
||||
# Here's a sample route:
|
||||
# map.connect 'products/:id', :controller => 'catalog', :action => 'view'
|
||||
# Keep in mind you can assign values other than :controller and :action
|
||||
|
||||
# Install the default route as the lowest priority.
|
||||
map.connect ':controller/:action/:id'
|
||||
end
|
|
@ -39,6 +39,8 @@ require_dependency "environments/#{RAILS_ENV}"
|
|||
ActiveRecord::Base.configurations = YAML::load(File.open("#{RAILS_ROOT}/config/database.yml"))
|
||||
ActiveRecord::Base.establish_connection
|
||||
|
||||
Controllers = Dependencies::LoadingModule.new(File.expand_path(File.join(RAILS_ROOT, 'app', 'controllers')))
|
||||
|
||||
|
||||
# Configure defaults if the included environment did not.
|
||||
begin
|
||||
|
|
|
@ -36,6 +36,8 @@ require_dependency "environments/#{RAILS_ENV}"
|
|||
ActiveRecord::Base.configurations = YAML::load(File.open("#{RAILS_ROOT}/config/database.yml"))
|
||||
ActiveRecord::Base.establish_connection
|
||||
|
||||
Controllers = Dependencies::LoadingModule.new(File.expand_path(File.join(RAILS_ROOT, 'app', 'controllers')))
|
||||
|
||||
|
||||
# Configure defaults if the included environment did not.
|
||||
begin
|
||||
|
|
|
@ -27,53 +27,31 @@ class Dispatcher
|
|||
class <<self
|
||||
def dispatch(cgi = CGI.new, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS)
|
||||
begin
|
||||
Breakpoint.activate_drb("druby://localhost:#{BREAKPOINT_SERVER_PORT}", nil, !defined?(FastCGI)) if defined?(BREAKPOINT_SERVER_PORT)
|
||||
|
||||
request = ActionController::CgiRequest.new(cgi, session_options)
|
||||
response = ActionController::CgiResponse.new(cgi)
|
||||
|
||||
controller_name, module_name = controller_name(request.parameters), module_name(request.parameters)
|
||||
|
||||
require_or_load("application")
|
||||
require_or_load(controller_path(controller_name, module_name))
|
||||
|
||||
controller_class(controller_name).process(request, response).out
|
||||
prepare_application
|
||||
request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
|
||||
ActionController::Routing::Routes.recognize!(request).process(request, response).out
|
||||
rescue Object => exception
|
||||
ActionController::Base.process_with_exception(request, response, exception).out
|
||||
ensure
|
||||
reset_application if Dependencies.load?
|
||||
Breakpoint.deactivate_drb if defined?(BREAKPOINT_SERVER_PORT)
|
||||
reset_application
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def reset_application
|
||||
Dependencies.clear
|
||||
Dependencies.remove_subclasses_for(ActiveRecord::Base, ActiveRecord::Observer, ActionController::Base)
|
||||
def prepare_application
|
||||
ActionController::Routing::Routes.reload if Dependencies.load?
|
||||
Breakpoint.activate_drb("druby://localhost:#{BREAKPOINT_SERVER_PORT}", nil, !defined?(FastCGI)) if defined?(BREAKPOINT_SERVER_PORT)
|
||||
Controllers.const_load!("application") unless Controllers.const_defined?(:ApplicationController)
|
||||
end
|
||||
|
||||
def controller_path(controller_name, module_name = nil)
|
||||
if module_name
|
||||
"#{module_name}/#{controller_name.underscore}_controller"
|
||||
else
|
||||
"#{controller_name.underscore}_controller"
|
||||
def reset_application
|
||||
if Dependencies.load?
|
||||
Controllers.clear
|
||||
Dependencies.clear
|
||||
Dependencies.remove_subclasses_for(ActiveRecord::Base, ActiveRecord::Observer, ActionController::Base)
|
||||
end
|
||||
end
|
||||
|
||||
def controller_class(controller_name)
|
||||
Object.const_get(controller_class_name(controller_name))
|
||||
end
|
||||
|
||||
def controller_class_name(controller_name)
|
||||
"#{controller_name.camelize}Controller"
|
||||
end
|
||||
|
||||
def controller_name(parameters)
|
||||
parameters["controller"].downcase.gsub(/[^_a-zA-Z0-9]/, "").untaint
|
||||
end
|
||||
|
||||
def module_name(parameters)
|
||||
parameters["module"].downcase.gsub(/[^_a-zA-Z0-9]/, "").untaint if parameters["module"]
|
||||
Breakpoint.deactivate_drb if defined?(BREAKPOINT_SERVER_PORT)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
$:.unshift(File.dirname(__FILE__))
|
||||
|
||||
require 'support/core_ext'
|
||||
require 'rails_generator/support/core_ext'
|
||||
|
||||
require 'rails_generator/base'
|
||||
require 'rails_generator/lookup'
|
||||
|
@ -31,3 +31,7 @@ require 'rails_generator/commands'
|
|||
|
||||
Rails::Generator::Base.send(:include, Rails::Generator::Lookup)
|
||||
Rails::Generator::Base.send(:include, Rails::Generator::Commands)
|
||||
|
||||
# Set up a default logger for convenience.
|
||||
require 'rails_generator/simple_logger'
|
||||
Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new(STDOUT)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
require File.dirname(__FILE__) + '/../support/class_attribute_accessors'
|
||||
require File.dirname(__FILE__) + '/../support/inflector'
|
||||
require File.dirname(__FILE__) + '/support/class_attribute_accessors'
|
||||
require File.dirname(__FILE__) + '/support/inflector'
|
||||
require File.dirname(__FILE__) + '/options'
|
||||
require File.dirname(__FILE__) + '/manifest'
|
||||
require File.dirname(__FILE__) + '/spec'
|
||||
|
@ -69,8 +69,8 @@ module Rails
|
|||
@source_root = options[:source] || File.join(spec.path, 'templates')
|
||||
if options[:destination]
|
||||
@destination_root = options[:destination]
|
||||
elsif Object.const_defined?(:RAILS_ROOT)
|
||||
@destination_root = Object.const_get(:RAILS_ROOT)
|
||||
elsif defined? ::RAILS_ROOT
|
||||
@destination_root = ::RAILS_ROOT
|
||||
end
|
||||
|
||||
# Silence the logger if requested.
|
||||
|
@ -173,11 +173,20 @@ module Rails
|
|||
def assign_names!(name)
|
||||
@name = name
|
||||
base_name, @class_path, @class_nesting = extract_modules(@name)
|
||||
@class_name, @singular_name, @plural_name = inflect_names(base_name)
|
||||
@class_name_without_nesting, @singular_name, @plural_name = inflect_names(base_name)
|
||||
if @class_nesting.empty?
|
||||
@class_name = @class_name_without_nesting
|
||||
else
|
||||
@class_name = "#{@class_nesting}::#{@class_name_without_nesting}"
|
||||
end
|
||||
end
|
||||
|
||||
# Extract modules from filesystem-style or ruby-style path:
|
||||
# good/fun/stuff
|
||||
# Good::Fun::Stuff
|
||||
# produce the same results.
|
||||
def extract_modules(name)
|
||||
modules = name.split('/')
|
||||
modules = name.include?('/') ? name.split('/') : name.split('::')
|
||||
name = modules.pop
|
||||
path = modules.map { |m| m.underscore }
|
||||
nesting = modules.map { |m| m.camelize }.join('::')
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
require 'rbconfig'
|
||||
|
||||
class AppGenerator < Rails::Generator::Base
|
||||
DEFAULT_SHEBANG = File.join(Config::CONFIG['bindir'],
|
||||
Config::CONFIG['ruby_install_name'])
|
||||
|
||||
default_options :gem => true, :shebang => DEFAULT_SHEBANG
|
||||
mandatory_options :source => "#{File.dirname(__FILE__)}/../.."
|
||||
mandatory_options :source => "#{File.dirname(__FILE__)}/../../../../.."
|
||||
|
||||
def initialize(runtime_args, runtime_options = {})
|
||||
super
|
||||
usage if args.empty?
|
||||
@destination_root = args.shift
|
||||
puts "eek! #{destination_root.inspect}"
|
||||
end
|
||||
|
||||
def manifest
|
||||
|
@ -32,6 +33,7 @@ class AppGenerator < Rails::Generator::Base
|
|||
|
||||
# database.yml and .htaccess
|
||||
m.template "configs/database.yml", "config/database.yml"
|
||||
m.template "configs/routes.rb", "config/routes.rb"
|
||||
m.template "configs/apache.conf", "public/.htaccess"
|
||||
|
||||
# Environments
|
||||
|
|
|
@ -4,8 +4,11 @@ class ControllerGenerator < Rails::Generator::NamedBase
|
|||
# Check for class naming collisions.
|
||||
m.class_collisions "#{class_name}Controller", "#{class_name}ControllerTest", "#{class_name}Helper"
|
||||
|
||||
# Views directory even if there are no actions.
|
||||
# Controller, helper, views, and test directories.
|
||||
m.directory File.join('app/controllers', class_path)
|
||||
m.directory File.join('app/helpers', class_path)
|
||||
m.directory File.join('app/views', class_path, file_name)
|
||||
m.directory File.join('test/functional', class_path)
|
||||
|
||||
# Controller class, functional test, and helper class.
|
||||
m.template 'controller.rb',
|
||||
|
|
|
@ -7,7 +7,8 @@ class <%= class_name %>Controller; def rescue_action(e) raise e end; end
|
|||
class <%= class_name %>ControllerTest < Test::Unit::TestCase
|
||||
def setup
|
||||
@controller = <%= class_name %>Controller.new
|
||||
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
|
||||
@request = ActionController::TestRequest.new
|
||||
@response = ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
# Replace this with your real tests.
|
||||
|
|
|
@ -4,21 +4,28 @@ class MailerGenerator < Rails::Generator::NamedBase
|
|||
# Check for class naming collisions.
|
||||
m.class_collisions class_name, "#{class_name}Test"
|
||||
|
||||
# Mailer class and unit test.
|
||||
m.template "mailer.rb", "app/models/#{file_name}.rb"
|
||||
m.template "unit_test.rb", "test/unit/#{file_name}_test.rb"
|
||||
# Mailer, view, test, and fixture directories.
|
||||
m.directory File.join('app/models', class_path)
|
||||
m.directory File.join('app/views', class_path, file_name)
|
||||
m.directory File.join('test/unit', class_path)
|
||||
m.directory File.join('test/fixtures', class_path, table_name)
|
||||
|
||||
# Views and fixtures directories.
|
||||
m.directory "app/views/#{file_name}"
|
||||
m.directory "test/fixtures/#{table_name}"
|
||||
# Mailer class and unit test.
|
||||
m.template "mailer.rb", File.join('app/models',
|
||||
class_path,
|
||||
"#{file_name}.rb")
|
||||
m.template "unit_test.rb", File.join('test/unit',
|
||||
class_path,
|
||||
"#{file_name}_test.rb")
|
||||
|
||||
# View template and fixture for each action.
|
||||
actions.each do |action|
|
||||
m.template "view.rhtml",
|
||||
"app/views/#{file_name}/#{action}.rhtml",
|
||||
File.join('app/views', class_path, file_name, "#{action}.rhtml"),
|
||||
:assigns => { :action => action }
|
||||
m.template "fixture.rhtml",
|
||||
"test/fixtures/#{table_name}/#{action}",
|
||||
File.join('test/fixtures', class_path, table_name, action),
|
||||
:assigns => { :action => action }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,11 @@ class ModelGenerator < Rails::Generator::NamedBase
|
|||
# Check for class naming collisions.
|
||||
m.class_collisions class_name, "#{class_name}Test"
|
||||
|
||||
# Model, test, and fixture directories.
|
||||
m.directory File.join('app/models', class_path)
|
||||
m.directory File.join('test/unit', class_path)
|
||||
m.directory File.join('test/fixtures', class_path)
|
||||
|
||||
# Model class, unit test, and fixtures.
|
||||
m.template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
|
||||
m.template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb")
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
||||
# Set the $base_id variable in the setup method of your tests.
|
||||
# It's used to ensure that ids don't clash in some databases.
|
||||
<%% $base_id ||= 100000 %>
|
||||
|
||||
first_<%= singular_name %>:
|
||||
id: <%%= $base_id %>
|
||||
id: 1
|
||||
|
||||
another_<%= singular_name %>:
|
||||
id: <%%= $base_id + 1 %>
|
||||
id: 2
|
||||
|
|
|
@ -4,11 +4,11 @@ class <%= class_name %>Test < Test::Unit::TestCase
|
|||
fixtures :<%= table_name %>
|
||||
|
||||
def setup
|
||||
$base_id = 1000001
|
||||
@<%= singular_name %> = <%= class_name %>.find(1)
|
||||
end
|
||||
|
||||
# Replace this with your real tests.
|
||||
def test_truth
|
||||
assert true
|
||||
assert_kind_of <%= class_name %>, @<%= singular_name %>
|
||||
end
|
||||
end
|
||||
|
|
|
@ -41,7 +41,12 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
|
|||
super
|
||||
@controller_name = args.shift || @name.pluralize
|
||||
base_name, @controller_class_path, @controller_class_nesting = extract_modules(@controller_name)
|
||||
@controller_class_name, @controller_singular_name, @controller_plural_name = inflect_names(base_name)
|
||||
@controller_class_name_without_nesting, @controller_singular_name, @controller_plural_name = inflect_names(base_name)
|
||||
if @controller_class_nesting.empty?
|
||||
@controller_class_name = @controller_class_name_without_nesting
|
||||
else
|
||||
@controller_class_name = "#{@controller_class_nesting}::#{@controller_class_name_without_nesting}"
|
||||
end
|
||||
end
|
||||
|
||||
def manifest
|
||||
|
@ -52,8 +57,12 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
|
|||
# Check for class naming collisions.
|
||||
m.class_collisions "#{controller_class_name}Controller", "#{controller_class_name}ControllerTest", "#{controller_class_name}Helper"
|
||||
|
||||
# Views directory.
|
||||
# Controller, helper, views, and test directories.
|
||||
m.directory File.join('app/controllers', controller_class_path)
|
||||
m.directory File.join('app/helpers', controller_class_path)
|
||||
m.directory File.join('app/views', controller_class_path, controller_file_name)
|
||||
m.directory File.join('test/functional', controller_class_path)
|
||||
|
||||
|
||||
# Controller class, functional test, helper, and views.
|
||||
m.template 'controller.rb',
|
||||
|
@ -79,7 +88,8 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
|
|||
scaffold_views.each do |action|
|
||||
m.template "view_#{action}.rhtml",
|
||||
File.join('app/views',
|
||||
controller_class_path, controller_file_name,
|
||||
controller_class_path,
|
||||
controller_file_name,
|
||||
"#{action}.rhtml"),
|
||||
:assigns => { :action => action }
|
||||
end
|
||||
|
@ -103,7 +113,8 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
|
|||
unscaffolded_actions.each do |action|
|
||||
m.template "controller:view.rhtml",
|
||||
File.join('app/views',
|
||||
controller_class_path, controller_file_name,
|
||||
controller_class_path,
|
||||
controller_file_name,
|
||||
"#{action}.rhtml"),
|
||||
:assigns => { :action => action }
|
||||
end
|
||||
|
@ -153,9 +164,13 @@ class ScaffoldGenerator < Rails::Generator::NamedBase
|
|||
end
|
||||
|
||||
def model_instance
|
||||
unless Object.const_defined?(class_name)
|
||||
Object.const_set(class_name, Class.new(ActiveRecord::Base))
|
||||
base = class_nesting.split('::').inject(Object) do |base, nested|
|
||||
break base.const_get(nested) if base.const_defined?(nested)
|
||||
base.const_set(nested, Module.new)
|
||||
end
|
||||
Object.const_get(class_name).new
|
||||
unless base.const_defined?(@class_name_without_nesting)
|
||||
base.const_set(@class_name_without_nesting, Class.new(ActiveRecord::Base))
|
||||
end
|
||||
class_name.constantize.new
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,9 +8,9 @@ class <%= controller_class_name %>ControllerTest < Test::Unit::TestCase
|
|||
fixtures :<%= table_name %>
|
||||
|
||||
def setup
|
||||
$base_id = 1000001
|
||||
@controller = <%= controller_class_name %>Controller.new
|
||||
@request, @response = ActionController::TestRequest.new, ActionController::TestResponse.new
|
||||
@request = ActionController::TestRequest.new
|
||||
@response = ActionController::TestResponse.new
|
||||
end
|
||||
|
||||
<% for action in unscaffolded_actions -%>
|
||||
|
@ -34,7 +34,7 @@ class <%= controller_class_name %>ControllerTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_show<%= suffix %>
|
||||
process :show<%= suffix %>, 'id' => $base_id
|
||||
process :show<%= suffix %>, 'id' => 1
|
||||
assert_rendered_file 'show'
|
||||
assert_template_has '<%= singular_name %>'
|
||||
assert_valid_record '<%= singular_name %>'
|
||||
|
@ -56,25 +56,25 @@ class <%= controller_class_name %>ControllerTest < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_edit<%= suffix %>
|
||||
process :edit<%= suffix %>, 'id' => $base_id
|
||||
process :edit<%= suffix %>, 'id' => 1
|
||||
assert_rendered_file 'edit<%= suffix %>'
|
||||
assert_template_has '<%= singular_name %>'
|
||||
assert_valid_record '<%= singular_name %>'
|
||||
end
|
||||
|
||||
def test_update<%= suffix %>
|
||||
process :update<%= suffix %>, '<%= singular_name %>' => { 'id' => $base_id }
|
||||
assert_redirected_to :action => 'show<%= suffix %>', :id => $base_id
|
||||
process :update<%= suffix %>, '<%= singular_name %>' => { 'id' => 1 }
|
||||
assert_redirected_to :action => 'show<%= suffix %>', :id => 1
|
||||
end
|
||||
|
||||
def test_destroy<%= suffix %>
|
||||
assert_not_nil <%= class_name %>.find($base_id)
|
||||
assert_not_nil <%= class_name %>.find(1)
|
||||
|
||||
process :destroy, 'id' => $base_id
|
||||
process :destroy, 'id' => 1
|
||||
assert_redirected_to :action => 'list<%= suffix %>'
|
||||
|
||||
assert_raise(ActiveRecord::RecordNotFound) {
|
||||
<%= singular_name %> = <%= class_name %>.find($base_id)
|
||||
<%= singular_name %> = <%= class_name %>.find(1)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<%% for <%= singular_name %> in @<%= plural_name %> %>
|
||||
<tr>
|
||||
<%% for column in <%= class_name %>.content_columns %>
|
||||
<td><%%=h <%= singular_name %>[column.name] %></td>
|
||||
<td><%%=h <%= singular_name %>.send(column.name) %></td>
|
||||
<%% end %>
|
||||
<td><%%= link_to 'Show', :action => 'show<%= suffix %>', :id => <%= singular_name %>.id %></td>
|
||||
<td><%%= link_to 'Edit', :action => 'edit<%= suffix %>', :id => <%= singular_name %>.id %></td>
|
||||
|
|
|
@ -4,24 +4,20 @@ class Object
|
|||
class << self
|
||||
# Lookup missing generators using const_missing. This allows any
|
||||
# generator to reference another without having to know its location:
|
||||
# RubyGems, ~/.rails/generators, and RAILS_ROOT/script/generators all
|
||||
# cooperate to get the job done. The greatest use of const_missing
|
||||
# autoloading is to easily subclass existing generators. Example:
|
||||
# class HorsebackGenerator < PostbackGenerator
|
||||
# We don't know whether the postback generator is built in, installed
|
||||
# as a gem, or in the user's home directory, and we shouldn't have to.
|
||||
unless respond_to?(:pre_generator_const_missing)
|
||||
alias_method :pre_generator_const_missing, :const_missing
|
||||
|
||||
def const_missing(class_id)
|
||||
if md = /(.+)Generator$/.match(class_id.to_s)
|
||||
name = md.captures.first.demodulize.underscore
|
||||
Rails::Generator::Base.lookup(name).klass
|
||||
else
|
||||
pre_generator_const_missing(class_id)
|
||||
end
|
||||
# RubyGems, ~/.rails/generators, and RAILS_ROOT/script/generators.
|
||||
def lookup_missing_generator(class_id)
|
||||
if md = /(.+)Generator$/.match(class_id.to_s)
|
||||
name = md.captures.first.demodulize.underscore
|
||||
Rails::Generator::Base.lookup(name).klass
|
||||
else
|
||||
const_missing_before_generators(class_id)
|
||||
end
|
||||
end
|
||||
|
||||
unless respond_to?(:const_missing_before_generators)
|
||||
alias_method :const_missing_before_generators, :const_missing
|
||||
alias_method :const_missing, :lookup_missing_generator
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -102,7 +98,7 @@ module Rails
|
|||
# 4. Builtins. Model, controller, mailer, scaffold.
|
||||
def use_component_sources!
|
||||
reset_sources
|
||||
sources << PathSource.new(:app, "#{Object.const_get(:RAILS_ROOT)}/script/generators") if Object.const_defined?(:RAILS_ROOT)
|
||||
sources << PathSource.new(:app, "#{::RAILS_ROOT}/script/generators") if defined? ::RAILS_ROOT
|
||||
sources << PathSource.new(:user, "#{Dir.user_home}/.rails/generators")
|
||||
sources << GemSource.new if Object.const_defined?(:Gem)
|
||||
sources << PathSource.new(:builtin, "#{File.dirname(__FILE__)}/generators/components")
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
require 'optparse'
|
||||
require File.dirname(__FILE__) + '/../support/class_inheritable_attributes'
|
||||
require File.dirname(__FILE__) + '/support/class_inheritable_attributes'
|
||||
|
||||
module Rails
|
||||
module Generator
|
||||
# Implement add_options! to add your options to the parser:
|
||||
# def add_options!(opt)
|
||||
# opt.on('-v', '--verbose') { |value| options[:verbose] = value }
|
||||
# end
|
||||
module Options
|
||||
def self.append_features(base)
|
||||
super
|
||||
|
@ -85,13 +89,14 @@ module Rails
|
|||
|
||||
@option_parser = OptionParser.new do |opt|
|
||||
opt.banner = banner
|
||||
add_options!(opt)
|
||||
add_options!(opt) if respond_to?(:add_options!)
|
||||
add_general_options!(opt)
|
||||
opt.parse!(args)
|
||||
end
|
||||
|
||||
return args
|
||||
ensure
|
||||
self.options = full_options(runtime_options)
|
||||
args
|
||||
end
|
||||
|
||||
# Raise a usage error. Override usage_message to provide a blurb
|
||||
|
@ -109,14 +114,6 @@ module Rails
|
|||
"Usage: #{$0} [options]"
|
||||
end
|
||||
|
||||
# Override with a method that adds options to the parser.
|
||||
# Added options should use the options hash. For example,
|
||||
# def add_options!(opt)
|
||||
# opt.on('-v', '--verbose') { |value| options[:verbose] = value }
|
||||
# end
|
||||
def add_options!(opt)
|
||||
end
|
||||
|
||||
# Adds general options like -h and --quiet. Usually don't override.
|
||||
def add_general_options!(opt)
|
||||
opt.separator ''
|
||||
|
|
|
@ -16,21 +16,23 @@ module Rails
|
|||
# or first remaining argument, and invokes the requested command.
|
||||
def run(args = [], runtime_options = {})
|
||||
begin
|
||||
parse!(args, runtime_options)
|
||||
|
||||
# Generator name is the only required option.
|
||||
unless options[:generator]
|
||||
usage if args.empty?
|
||||
options[:generator] ||= args.shift
|
||||
end
|
||||
|
||||
# Look up generator instance and invoke command on it.
|
||||
Rails::Generator::Base.instance(options[:generator], args, options).command(options[:command]).invoke!
|
||||
rescue => e
|
||||
puts e
|
||||
puts " #{e.backtrace.join("\n ")}\n" if options[:backtrace]
|
||||
raise SystemExit
|
||||
parse!(args.dup, runtime_options)
|
||||
rescue OptionParser::InvalidOption => e
|
||||
# Don't cry, script. Generators want what you think is invalid.
|
||||
end
|
||||
|
||||
# Generator name is the only required option.
|
||||
unless options[:generator]
|
||||
usage if args.empty?
|
||||
options[:generator] ||= args.shift
|
||||
end
|
||||
|
||||
# Look up generator instance and invoke command on it.
|
||||
Rails::Generator::Base.instance(options[:generator], args, options).command(options[:command]).invoke!
|
||||
rescue => e
|
||||
puts e
|
||||
puts " #{e.backtrace.join("\n ")}\n" if options[:backtrace]
|
||||
raise SystemExit
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
|
@ -3,9 +3,5 @@ require File.dirname(__FILE__) + '/../scripts'
|
|||
module Rails::Generator::Scripts
|
||||
class Destroy < Base
|
||||
mandatory_options :command => :destroy
|
||||
|
||||
protected
|
||||
def add_options!(opt)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,9 +3,5 @@ require File.dirname(__FILE__) + '/../scripts'
|
|||
module Rails::Generator::Scripts
|
||||
class Generate < Base
|
||||
mandatory_options :command => :create
|
||||
|
||||
protected
|
||||
def add_options!(opt)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,9 +5,6 @@ module Rails::Generator::Scripts
|
|||
mandatory_options :command => :update
|
||||
|
||||
protected
|
||||
def add_options!(opt)
|
||||
end
|
||||
|
||||
def banner
|
||||
"Usage: #{$0} [options] scaffold"
|
||||
end
|
||||
|
|
|
@ -27,14 +27,10 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
|
|||
|
||||
def do_GET(req, res)
|
||||
begin
|
||||
unless handle_index(req, res)
|
||||
unless handle_file(req, res)
|
||||
REQUEST_MUTEX.lock
|
||||
unless handle_dispatch(req, res)
|
||||
unless handle_file(req, res)
|
||||
REQUEST_MUTEX.lock
|
||||
unless handle_mapped(req, res)
|
||||
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
|
||||
end
|
||||
end
|
||||
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
|
||||
end
|
||||
end
|
||||
ensure
|
||||
|
@ -44,20 +40,6 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
|
|||
|
||||
alias :do_POST :do_GET
|
||||
|
||||
def handle_index(req, res)
|
||||
if req.request_uri.path == "/"
|
||||
if @server_options[:index_controller]
|
||||
res.set_redirect WEBrick::HTTPStatus::MovedPermanently, "/#{@server_options[:index_controller]}/"
|
||||
else
|
||||
res.set_redirect WEBrick::HTTPStatus::MovedPermanently, "/_doc/"
|
||||
end
|
||||
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def handle_file(req, res)
|
||||
begin
|
||||
@file_handler.send(:do_GET, req, res)
|
||||
|
@ -70,22 +52,7 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
|
|||
end
|
||||
end
|
||||
|
||||
def handle_mapped(req, res)
|
||||
if mappings = DispatchServlet.parse_uri(req.request_uri.path)
|
||||
query = mappings.collect { |pair| "#{pair.first}=#{pair.last}" }.join("&")
|
||||
query << "&#{req.request_uri.query}" if req.request_uri.query
|
||||
origin = req.request_uri.path + "?" + query
|
||||
req.request_uri.path = "/dispatch.rb"
|
||||
req.request_uri.query = query
|
||||
handle_dispatch(req, res, origin)
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def handle_dispatch(req, res, origin = nil)
|
||||
return false unless /^\/dispatch\.(?:cgi|rb|fcgi)$/.match(req.request_uri.path)
|
||||
|
||||
env = req.meta_vars.clone
|
||||
env["QUERY_STRING"] = req.request_uri.query
|
||||
env["REQUEST_URI"] = origin if origin
|
||||
|
@ -120,35 +87,4 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
|
|||
p err, err.backtrace
|
||||
return false
|
||||
end
|
||||
|
||||
def self.parse_uri(path)
|
||||
component, id = /([-_a-zA-Z0-9]+)/, /([0-9]+)/
|
||||
|
||||
case path.sub(%r{^/(?:fcgi|mruby|cgi)/}, "/")
|
||||
when %r{^/#{component}/?$} then
|
||||
{ :controller => $1, :action => "index" }
|
||||
when %r{^/#{component}/#{component}$} then
|
||||
{ :controller => $1, :action => $2 }
|
||||
when %r{^/#{component}/#{component}/#{id}$} then
|
||||
{ :controller => $1, :action => $2, :id => $3 }
|
||||
|
||||
when %r{^/#{component}/#{component}/$} then
|
||||
{ :module => $1, :controller => $2, :action => "index" }
|
||||
when %r{^/#{component}/#{component}/#{component}$} then
|
||||
if DispatchServlet.modules(component).include?($1)
|
||||
{ :module => $1, :controller => $2, :action => $3 }
|
||||
else
|
||||
{ :controller => $1, :action => $2, :id => $3 }
|
||||
end
|
||||
when %r{^/#{component}/#{component}/#{component}/#{id}$} then
|
||||
{ :module => $1, :controller => $2, :action => $3, :id => $4 }
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
def self.modules(module_pattern = '[^.]+')
|
||||
path = RAILS_ROOT + '/app/controllers'
|
||||
Dir.entries(path).grep(/^#{module_pattern}$/).find_all {|e| File.directory?("#{path}/#{e}")}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,22 +1,29 @@
|
|||
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
|
||||
RAILS_ROOT = File.dirname(__FILE__)
|
||||
|
||||
require 'test/unit'
|
||||
|
||||
require 'rails_generator'
|
||||
require 'rails_generator/simple_logger'
|
||||
Rails::Generator::Base.logger = Rails::Generator::SimpleLogger.new
|
||||
|
||||
# Optionally load RubyGems.
|
||||
begin
|
||||
require 'rubygems'
|
||||
require_gem 'actionpack'
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
# Must set before requiring generator libs.
|
||||
RAILS_ROOT = File.dirname(__FILE__)
|
||||
|
||||
# Preemptively load the rest of Rails so Gems don't hijack our requires.
|
||||
require File.dirname(__FILE__) + '/../../activerecord/lib/active_record'
|
||||
require File.dirname(__FILE__) + '/../../actionpack/lib/action_controller'
|
||||
require File.dirname(__FILE__) + '/../lib/rails_generator'
|
||||
|
||||
class RailsGeneratorTest < Test::Unit::TestCase
|
||||
BUILTINS = %w(controller mailer model scaffold)
|
||||
CAPITALIZED_BUILTINS = BUILTINS.map { |b| b.capitalize }
|
||||
|
||||
def test_sources
|
||||
expected = [:app, :user, :RubyGems, :builtin]
|
||||
expected.delete(:gem) unless Object.const_defined?(:Gem)
|
||||
assert_equal expected, Rails::Generator::Base.sources.map { |s| s.label }
|
||||
end
|
||||
|
||||
def test_lookup_builtins
|
||||
(BUILTINS + CAPITALIZED_BUILTINS).each do |name|
|
||||
assert_nothing_raised do
|
||||
|
@ -71,7 +78,7 @@ class RailsGeneratorTest < Test::Unit::TestCase
|
|||
assert_equal 'admin/foo', g.name
|
||||
assert_equal %w(admin), g.class_path
|
||||
assert_equal 'Admin', g.class_nesting
|
||||
assert_equal 'Foo', g.class_name
|
||||
assert_equal 'Admin::Foo', g.class_name
|
||||
assert_equal 'foo', g.singular_name
|
||||
assert_equal 'foos', g.plural_name
|
||||
assert_equal g.singular_name, g.file_name
|
||||
|
|
Loading…
Reference in a new issue