1
0
Fork 0
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:
David Heinemeier Hansson 2005-02-15 01:45:35 +00:00
parent 88a3343ed5
commit b1999be5a7
62 changed files with 1815 additions and 492 deletions

View file

@ -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

View file

@ -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:
@ -206,6 +216,12 @@ module ActionController #:nodoc:
@@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".
cattr_accessor :template_root
@ -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

View file

@ -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

View file

@ -51,20 +51,17 @@ module ActionController #:nodoc:
when Module
add_template_helper(arg)
when String, Symbol
file_name = Inflector.underscore(arg.to_s.downcase) + '_helper'
class_name = Inflector.camelize(file_name)
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]
if requiree == file_name
raise LoadError, "Missing helper file helpers/#{file_name}.rb"
else
raise LoadError, "Can't load file: #{requiree}"
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))
add_template_helper(class_name.constantize)
else
raise ArgumentError, 'helper expects String, Symbol, or Module argument'
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

View file

@ -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
@ -101,6 +102,15 @@ module ActionController
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
#++

View file

@ -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

View 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

View file

@ -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}

View file

@ -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 %>

View file

@ -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)

View file

@ -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
class UrlRewriter #:nodoc:
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)
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)
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]
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)
@ -176,14 +124,14 @@ module ActionController
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
query_string << ("?" + elements.join("&")) unless elements.empty?
return query_string
end
end

View file

@ -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

View file

@ -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)

View file

@ -1,20 +1,30 @@
require File.dirname(__FILE__) + '/../abstract_unit'
$:.unshift(File.dirname(__FILE__) + '/../fixtures/helpers')
class HelperTest < Test::Unit::TestCase
HELPER_PATHS = %w(/../fixtures/helpers)
class TestController < ActionController::Base
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
module LocalAbcHelper
def rescue_action(e) raise end
end
end
module LocalAbcHelper
def a() end
def b() end
def c() end
end
end
class HelperTest < Test::Unit::TestCase
HELPER_PATHS = %w(/../fixtures/helpers)
def setup
# Increment symbol counter.
@ -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

View file

@ -2,8 +2,15 @@ require File.dirname(__FILE__) + '/../abstract_unit'
Customer = Struct.new("Customer", :name)
class RenderTest < Test::Unit::TestCase
class TestController < ActionController::Base
module Fun
class GamesController < ActionController::Base
def hello_world
end
end
end
class TestController < ActionController::Base
layout :determine_layout
def hello_world
@ -52,9 +59,6 @@ class RenderTest < Test::Unit::TestCase
render_action "list"
end
def modgreet
end
def rescue_action(e) raise end
private
@ -64,11 +68,11 @@ class RenderTest < Test::Unit::TestCase
when "builder_layout_test": "layouts/builder"
end
end
end
end
TestController.template_root = File.dirname(__FILE__) + "/../fixtures/"
TestController.template_root = File.dirname(__FILE__) + "/../fixtures/"
class TestLayoutController < ActionController::Base
class TestLayoutController < ActionController::Base
layout "layouts/standard"
def hello_world
@ -80,8 +84,9 @@ class RenderTest < Test::Unit::TestCase
def rescue_action(e)
raise unless ActionController::MissingTemplate === e
end
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

View file

@ -32,6 +32,28 @@ class RequestTest < Test::Unit::TestCase
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"
assert_equal "rubyonrails.org:8080", @request.host_with_port

View 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

View 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

View file

@ -0,0 +1 @@
Living in a nested world

View file

@ -0,0 +1,3 @@
module Fun::GamesHelper
def stratego() "Iz guuut!" end
end

View file

@ -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]

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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)
@ -48,6 +48,12 @@ module Inflector
(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:
[

View file

@ -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",
@ -51,6 +58,12 @@ class InflectorTest < Test::Unit::TestCase
"ApplicationController" => "application_controller"
}
CamelWithModuleToUnderscoreWithSlash = {
"Admin::Product" => "admin/product",
"Users::Commission::Department" => "users/commission/department",
"UsersSection::CommissionDepartment" => "users_section/commission_department",
}
ClassNameToForeignKeyWithUnderscore = {
"Person" => "person_id",
"MyApplication::Billing::Account" => "account_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

View file

@ -0,0 +1,2 @@
class Admin::AccessController
end

View file

@ -0,0 +1,2 @@
class Admin::UserController
end

View file

@ -0,0 +1,2 @@
class ContentController
end

View file

@ -0,0 +1,2 @@
class ResourceController
end

View 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

View file

@ -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"

View file

@ -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)

View file

@ -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)

View file

@ -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')

View file

@ -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)

View file

@ -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

View 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

View file

@ -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

View file

@ -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

View file

@ -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 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 reset_application
if Dependencies.load?
Controllers.clear
Dependencies.clear
Dependencies.remove_subclasses_for(ActiveRecord::Base, ActiveRecord::Observer, ActionController::Base)
end
def controller_path(controller_name, module_name = nil)
if module_name
"#{module_name}/#{controller_name.underscore}_controller"
else
"#{controller_name.underscore}_controller"
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

View file

@ -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)

View file

@ -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('::')

View file

@ -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

View file

@ -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',

View file

@ -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.

View file

@ -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

View file

@ -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")

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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>

View file

@ -4,23 +4,19 @@ 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)
# 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
pre_generator_const_missing(class_id)
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")

View file

@ -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 ''

View file

@ -16,7 +16,10 @@ module Rails
# or first remaining argument, and invokes the requested command.
def run(args = [], runtime_options = {})
begin
parse!(args, runtime_options)
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]
@ -31,7 +34,6 @@ module Rails
puts " #{e.backtrace.join("\n ")}\n" if options[:backtrace]
raise SystemExit
end
end
protected
# Override with your own script usage banner.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -27,16 +27,12 @@ class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
def do_GET(req, res)
begin
unless handle_index(req, res)
unless handle_dispatch(req, res)
unless handle_file(req, res)
REQUEST_MUTEX.lock
unless handle_mapped(req, res)
unless handle_dispatch(req, res)
raise WEBrick::HTTPStatus::NotFound, "`#{req.path}' not found."
end
end
end
end
ensure
REQUEST_MUTEX.unlock if REQUEST_MUTEX.locked?
end
@ -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

View file

@ -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