Merge commit 'mainstream/master'

This commit is contained in:
Pratik Naik
2009-09-21 21:14:04 +01:00
427 changed files with 5184 additions and 3676 deletions

6
.gitignore vendored
View File

@@ -1,16 +1,20 @@
.DS_Store
debug.log
doc/rdoc
activemodel/doc
activeresource/doc
activerecord/doc
actionpack/doc
actionmailer/doc
activesupport/doc
activemodel/pkg
activeresource/pkg
activerecord/pkg
actionpack/pkg
activemodel/test/fixtures/fixture_database.sqlite3
actionmailer/pkg
activesupport/pkg
actionpack/test/tmp
activesupport/test/fixtures/isolation_test
railties/pkg
railties/test/500.html
@@ -23,3 +27,5 @@ railties/guides/output
*.rbc
*.swp
*.swo
actionpack/bin
*/vendor/gems

View File

@@ -3,7 +3,7 @@ require 'rake/rdoctask'
env = %(PKG_BUILD="#{ENV['PKG_BUILD']}") if ENV['PKG_BUILD']
PROJECTS = %w(activesupport actionpack actionmailer activeresource activerecord railties)
PROJECTS = %w(activesupport actionpack actionmailer activeresource activerecord activemodel railties)
Dir["#{File.dirname(__FILE__)}/*/lib/*/version.rb"].each do |version_path|
require version_path
@@ -12,7 +12,7 @@ end
desc 'Run all tests by default'
task :default => :test
%w(test isolated_test rdoc pgem package release gem).each do |task_name|
%w(test isolated_test rdoc pgem package release gem gemspec).each do |task_name|
desc "Run #{task_name} task for all projects"
task task_name do
errors = []
@@ -30,7 +30,6 @@ task :install => :gem do
system("gem install railties/pkg/rails-#{ActionPack::VERSION::STRING}.gem --no-ri --no-rdoc")
end
desc "Generate documentation for the Rails framework"
Rake::RDocTask.new do |rdoc|
rdoc.rdoc_dir = 'doc/rdoc'

View File

@@ -78,6 +78,11 @@ Rake::GemPackageTask.new(spec) do |p|
p.need_zip = true
end
task :gemspec do
File.open(File.join(File.dirname(__FILE__), "#{spec.name}.gemspec"), "w") do |file|
file.puts spec.to_ruby
end
end
desc "Publish the API documentation"
task :pgem => [:package] do

File diff suppressed because one or more lines are too long

View File

@@ -256,6 +256,8 @@ module ActionMailer #:nodoc:
# +implicit_parts_order+.
class Base
include AdvAttrAccessor, PartContainer, Quoting, Utils
extend AbstractController::RenderingController
if Object.const_defined?(:ActionController)
include ActionController::UrlWriter
include ActionController::Layout
@@ -479,58 +481,62 @@ module ActionMailer #:nodoc:
# Initialize the mailer via the given +method_name+. The body will be
# rendered and a new TMail::Mail object created.
def create!(method_name, *parameters) #:nodoc:
initialize_defaults(method_name)
__send__(method_name, *parameters)
# If an explicit, textual body has not been set, we check assumptions.
unless String === @body
# First, we look to see if there are any likely templates that match,
# which include the content-type in their file name (i.e.,
# "the_template_file.text.html.erb", etc.). Only do this if parts
# have not already been specified manually.
# if @parts.empty?
template_root.find_all_by_parts(@template, {}, template_path).each do |template|
@parts << Part.new(
:content_type => template.mime_type ? template.mime_type.to_s : "text/plain",
:disposition => "inline",
:charset => charset,
:body => render_template(template, @body)
)
end
if @parts.size > 1
@content_type = "multipart/alternative" if @content_type !~ /^multipart/
@parts = sort_parts(@parts, @implicit_parts_order)
end
# end
# Then, if there were such templates, we check to see if we ought to
# also render a "normal" template (without the content type). If a
# normal template exists (or if there were no implicit parts) we render
# it.
# ====
# TODO: Revisit this
# template_exists = @parts.empty?
# template_exists ||= template_root.find("#{mailer_name}/#{@template}")
# @body = render_message(@template, @body) if template_exists
ActiveSupport::Orchestra.instrument(:create_mail, :name => method_name) do
initialize_defaults(method_name)
__send__(method_name, *parameters)
# Finally, if there are other message parts and a textual body exists,
# we shift it onto the front of the parts and set the body to nil (so
# that create_mail doesn't try to render it in addition to the parts).
# ====
# TODO: Revisit this
# if !@parts.empty? && String === @body
# @parts.unshift Part.new(:charset => charset, :body => @body)
# @body = nil
# end
# If an explicit, textual body has not been set, we check assumptions.
unless String === @body
# First, we look to see if there are any likely templates that match,
# which include the content-type in their file name (i.e.,
# "the_template_file.text.html.erb", etc.). Only do this if parts
# have not already been specified manually.
# if @parts.empty?
template_root.find_all(@template, {}, template_path).each do |template|
@parts << Part.new(
:content_type => template.mime_type ? template.mime_type.to_s : "text/plain",
:disposition => "inline",
:charset => charset,
:body => render_template(template, @body)
)
end
if @parts.size > 1
@content_type = "multipart/alternative" if @content_type !~ /^multipart/
@parts = sort_parts(@parts, @implicit_parts_order)
end
# end
# Then, if there were such templates, we check to see if we ought to
# also render a "normal" template (without the content type). If a
# normal template exists (or if there were no implicit parts) we render
# it.
# ====
# TODO: Revisit this
# template_exists = @parts.empty?
# template_exists ||= template_root.find("#{mailer_name}/#{@template}")
# @body = render_message(@template, @body) if template_exists
# Finally, if there are other message parts and a textual body exists,
# we shift it onto the front of the parts and set the body to nil (so
# that create_mail doesn't try to render it in addition to the parts).
# ====
# TODO: Revisit this
# if !@parts.empty? && String === @body
# @parts.unshift Part.new(:charset => charset, :body => @body)
# @body = nil
# end
end
# If this is a multipart e-mail add the mime_version if it is not
# already set.
@mime_version ||= "1.0" if !@parts.empty?
# build the mail object itself
@mail = create_mail
end
# If this is a multipart e-mail add the mime_version if it is not
# already set.
@mime_version ||= "1.0" if !@parts.empty?
# build the mail object itself
@mail = create_mail
@mail
end
# Delivers a TMail::Mail object. By default, it delivers the cached mail
@@ -538,19 +544,21 @@ module ActionMailer #:nodoc:
# no alternate has been given as the parameter, this will fail.
def deliver!(mail = @mail)
raise "no mail object available for delivery!" unless mail
unless logger.nil?
logger.info "Sent mail to #{Array(recipients).join(', ')}"
logger.debug "\n#{mail.encoded}"
end
begin
__send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries
rescue Exception => e # Net::SMTP errors or sendmail pipe errors
raise e if raise_delivery_errors
ActiveSupport::Orchestra.instrument(:deliver_mail, :mail => @mail) do
begin
__send__("perform_delivery_#{delivery_method}", mail) if perform_deliveries
rescue Exception => e # Net::SMTP errors or sendmail pipe errors
raise e if raise_delivery_errors
end
end
return mail
mail
end
private

View File

@@ -1 +0,0 @@
require 'action_mailer'

14
actionpack/Gemfile Normal file
View File

@@ -0,0 +1,14 @@
rails_root = Pathname.new(File.dirname(__FILE__)).join("..")
gem "rack", "~> 1.0.0"
gem "rack-test", "~> 0.4.2"
gem "activesupport", "3.0.pre", :vendored_at => rails_root.join("activesupport")
gem "activemodel", "3.0.pre", :vendored_at => rails_root.join("activemodel")
only :test do
gem "mocha"
gem "sqlite3-ruby"
gem "RedCloth"
end
disable_system_gems

View File

@@ -17,68 +17,48 @@ RUBY_FORGE_PROJECT = "actionpack"
RUBY_FORGE_USER = "webster132"
desc "Default Task"
task :default => [ :test ]
task :default => :test
task :bundle do
puts "Checking if the bundled testing requirements are up to date..."
result = system "gem bundle"
unless result
puts "The gem bundler is not installed. Installing."
system "gem install bundler"
system "gem bundle"
end
end
# Run the unit tests
desc "Run all unit tests"
task :test => [:test_action_pack, :test_active_record_integration, :test_new_base]
task :test => [:test_action_pack, :test_active_record_integration]
TESTS_GLOB = "test/{abstract,controller,dispatch,new_base,template,html-scanner}/**/*_test.rb"
test_lib_dirs = ENV["NEW"] ? ["test/new_base"] : []
test_lib_dirs.push "test", "test/lib"
# test_lib_dirs = [ENV["NEW"] ? "test/new_base" : "test", "test/lib"]
Rake::TestTask.new(:test_action_pack) do |t|
t.libs.concat test_lib_dirs
t.libs << 'test'
# make sure we include the tests in alphabetical order as on some systems
# this will not happen automatically and the tests (as a whole) will error
t.test_files = Dir.glob( "test/{controller,dispatch,template,html-scanner}/**/*_test.rb" ).sort
t.test_files = Dir.glob(TESTS_GLOB).sort
t.verbose = true
#t.warning = true
# t.warning = true
end
task :isolated_test do
ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
Dir.glob("test/{controller,dispatch,template}/**/*_test.rb").all? do |file|
system(ruby, "-Ilib:#{test_lib_dirs * ':'}", file)
end or raise "Failures"
Dir.glob(TESTS_GLOB).all? { |file| system(ruby, '-Ilib:test', file) } or raise "Failures"
end
desc 'ActiveRecord Integration Tests'
Rake::TestTask.new(:test_active_record_integration) do |t|
t.libs.concat test_lib_dirs
t.libs << 'test'
t.test_files = Dir.glob("test/activerecord/*_test.rb")
t.verbose = true
end
desc 'New Controller Tests'
Rake::TestTask.new(:test_new_base) do |t|
t.libs << "test/new_base" << "test/lib"
t.test_files = Dir.glob("test/{abstract_controller,new_base}/*_test.rb")
t.verbose = true
end
desc 'Old Controller Tests on New Base'
Rake::TestTask.new(:test_new_base_on_old_tests) do |t|
t.libs << "test/new_base" << "test/lib"
t.verbose = true
# ==== Not ported
# * filters
t.test_files = Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + %w(
action_pack_assertions addresses_render assert_select
base benchmark caching capture content_type cookie dispatcher
filter_params flash helper http_basic_authentication
http_digest_authentication integration layout logging mime_responds
record_identifier redirect render render_js render_json
render_other render_xml request_forgery_protection rescue
resources routing selector send_file test url_rewriter
verification view_paths webservice
).map { |name| "test/controller/#{name}_test.rb" }
end
# Genereate the RDoc documentation
Rake::RDocTask.new { |rdoc|
@@ -116,6 +96,7 @@ spec = Gem::Specification.new do |s|
s.requirements << 'none'
s.add_dependency('activesupport', '= 3.0.pre' + PKG_BUILD)
s.add_dependency('activemodel', '= 3.0.pre' + PKG_BUILD)
s.add_dependency('rack', '~> 1.0.0')
s.add_dependency('rack-test', '~> 0.4.2')
@@ -134,6 +115,12 @@ Rake::GemPackageTask.new(spec) do |p|
p.need_zip = true
end
task :gemspec do
File.open(File.join(File.dirname(__FILE__), "#{spec.name}.gemspec"), "w") do |file|
file.puts spec.to_ruby
end
end
task :lines do
lines, codelines, total_lines, total_codelines = 0, 0, 0, 0

File diff suppressed because one or more lines are too long

View File

@@ -3,7 +3,6 @@ require "active_support/core_ext/module/delegation"
module AbstractController
autoload :Base, "abstract_controller/base"
autoload :Benchmarker, "abstract_controller/benchmarker"
autoload :Callbacks, "abstract_controller/callbacks"
autoload :Helpers, "abstract_controller/helpers"
autoload :Layouts, "abstract_controller/layouts"

View File

@@ -1,38 +0,0 @@
module AbstractController
module Benchmarker
extend ActiveSupport::Concern
include Logger
module ClassMethods
# Execute the passed in block, timing the duration of the block in ms.
#
# ==== Parameters
# title<#to_s>:: The title of block to benchmark
# log_level<Integer>:: A valid log level. Defaults to Logger::DEBUG
# use_silence<TrueClass, FalseClass>:: Whether or not to silence the
# logger for the duration of the block.
#
# ==== Returns
# Object:: The result of the block
def benchmark(title, log_level = ::Logger::DEBUG, use_silence = true)
if logger && logger.level >= log_level
result = nil
ms = Benchmark.ms { result = use_silence ? silence { yield } : yield }
logger.add(log_level, "#{title} (#{('%.1f' % ms)}ms)")
result
else
yield
end
end
# Silences the logger for the duration of the block.
def silence
old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger
yield
ensure
logger.level = old_logger_level if logger
end
end
end
end

View File

@@ -10,7 +10,7 @@ module AbstractController
include ActiveSupport::NewCallbacks
included do
define_callbacks :process_action, "response_body"
define_callbacks :process_action, :terminator => "response_body"
end
# Override AbstractController::Base's process_action to run the

View File

@@ -119,17 +119,17 @@ module AbstractController
when true
raise ArgumentError, "Layouts must be specified as a String, Symbol, false, or nil"
when nil
self.class_eval <<-ruby_eval, __FILE__, __LINE__ + 1
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def _layout(details)
self.class.cache_layout(details) do
if view_paths.exists?("#{_implied_layout_name}", details, "layouts")
if template_exists?("#{_implied_layout_name}", details, :_prefix => "layouts")
"#{_implied_layout_name}"
else
super
end
end
end
ruby_eval
RUBY
end
self.class_eval { private :_layout }
end
@@ -167,7 +167,7 @@ module AbstractController
# details<Hash{Symbol => Object}>:: A list of details to restrict
# the lookup to. By default, layout lookup is limited to the
# formats specified for the current request.
def _layout_for_name(name, details = {:formats => formats})
def _layout_for_name(name, details)
name && _find_layout(name, details)
end
@@ -183,7 +183,7 @@ module AbstractController
def _find_layout(name, details)
# TODO: Make prefix actually part of details in ViewPath#find_by_parts
prefix = details.key?(:prefix) ? details.delete(:prefix) : "layouts"
view_paths.find(name, details, prefix)
find_template(name, details, :_prefix => prefix)
end
# Returns the default layout for this controller and a given set of details.

View File

@@ -4,6 +4,26 @@ module AbstractController
module Logger
extend ActiveSupport::Concern
included do
cattr_accessor :logger
end
module ClassMethods #:nodoc:
# Logs a message appending the value measured.
def log_with_time(message, time, log_level=::Logger::DEBUG)
return unless logger && logger.level >= log_level
logger.add(log_level, "#{message} (%.1fms)" % time)
end
# Silences the logger for the duration of the block.
def silence
old_logger_level, logger.level = logger.level, ::Logger::ERROR if logge
yield
ensure
logger.level = old_logger_level if logger
end
end
# A class that allows you to defer expensive processing
# until the logger actually tries to log. Otherwise, you are
# forced to do the processing in advance, and send the
@@ -11,43 +31,44 @@ module AbstractController
# just discard the String if the log level is too low.
#
# TODO: Require that Rails loggers accept a block.
class DelayedLog
def initialize(&blk)
@blk = blk
class DelayedLog < ActiveSupport::BasicObject
def initialize(&block)
@str, @block = nil, block
end
def to_s
@blk.call
def method_missing(*args, &block)
unless @str
@str, @block = @block.call, nil
end
@str.send(*args, &block)
end
alias to_str to_s
end
included do
cattr_accessor :logger
end
# Override process_action in the AbstractController::Base
# to log details about the method.
def process_action(action)
retval = super
event = ActiveSupport::Orchestra.instrument(:process_action,
:controller => self, :action => action) do
super
end
if logger
log = DelayedLog.new do
"\n\nProcessing #{self.class.name}\##{action_name} " \
"to #{request.formats} " \
"(for #{request_origin}) [#{request.method.to_s.upcase}]"
"to #{request.formats} (for #{request_origin}) " \
"(%.1fms) [#{request.method.to_s.upcase}]" % event.duration
end
logger.info(log)
end
retval
event.result
end
private
# Returns the request origin with the IP and time. This needs to be cached,
# otherwise we would get different results for each time it calls.
def request_origin
# this *needs* to be cached!
# otherwise you'd get different results if calling it more than once
@request_origin ||= "#{request.remote_ip} at #{Time.now.to_s(:db)}"
end
end

View File

@@ -112,12 +112,18 @@ module AbstractController
name = (options[:_template_name] || action_name).to_s
options[:_template] ||= with_template_cache(name) do
view_paths.find(
name, { :formats => formats }, options[:_prefix], options[:_partial]
)
find_template(name, { :formats => formats }, options)
end
end
def find_template(name, details, options)
view_paths.find(name, details, options[:_prefix], options[:_partial])
end
def template_exists?(name, details, options)
view_paths.exists?(name, details, options[:_prefix], options[:_partial])
end
def with_template_cache(name)
yield
end

View File

@@ -2,7 +2,6 @@ module ActionController
class Base < Metal
abstract!
include AbstractController::Benchmarker
include AbstractController::Callbacks
include AbstractController::Logger
@@ -51,7 +50,7 @@ module ActionController
def method_for_action(action_name)
super || begin
if view_paths.exists?(action_name.to_s, {:formats => formats, :locales => [I18n.locale]}, controller_path)
if template_exists?(action_name.to_s, {:formats => formats}, :_prefix => controller_path)
"default_render"
end
end

View File

@@ -53,11 +53,11 @@ module ActionController #:nodoc:
return content unless cache_configured?
key = fragment_cache_key(key)
self.class.benchmark "Cached fragment miss: #{key}" do
event = ActiveSupport::Orchestra.instrument(:write_fragment, :key => key) do
cache_store.write(key, content, options)
end
self.class.log_with_time("Cached fragment miss: #{key}", event.duration)
content
end
@@ -66,10 +66,12 @@ module ActionController #:nodoc:
return unless cache_configured?
key = fragment_cache_key(key)
self.class.benchmark "Cached fragment hit: #{key}" do
event = ActiveSupport::Orchestra.instrument(:read_fragment, :key => key) do
cache_store.read(key, options)
end
self.class.log_with_time("Cached fragment hit: #{key}", event.duration)
event.result
end
# Check if a cached fragment from the location signified by <tt>key</tt> exists (see <tt>expire_fragment</tt> for acceptable formats)
@@ -77,10 +79,12 @@ module ActionController #:nodoc:
return unless cache_configured?
key = fragment_cache_key(key)
self.class.benchmark "Cached fragment exists?: #{key}" do
event = ActiveSupport::Orchestra.instrument(:fragment_exist?, :key => key) do
cache_store.exist?(key, options)
end
self.class.log_with_time("Cached fragment exists?: #{key}", event.duration)
event.result
end
# Removes fragments from the cache.
@@ -103,17 +107,21 @@ module ActionController #:nodoc:
def expire_fragment(key, options = nil)
return unless cache_configured?
key = key.is_a?(Regexp) ? key : fragment_cache_key(key)
key = fragment_cache_key(key) unless key.is_a?(Regexp)
message = nil
if key.is_a?(Regexp)
self.class.benchmark "Expired fragments matching: #{key.source}" do
event = ActiveSupport::Orchestra.instrument(:expire_fragment, :key => key) do
if key.is_a?(Regexp)
message = "Expired fragments matching: #{key.source}"
cache_store.delete_matched(key, options)
end
else
self.class.benchmark "Expired fragment: #{key}" do
else
message = "Expired fragment: #{key}"
cache_store.delete(key, options)
end
end
self.class.log_with_time(message, event.duration)
event.result
end
end
end

View File

@@ -62,21 +62,29 @@ module ActionController #:nodoc:
# expire_page "/lists/show"
def expire_page(path)
return unless perform_caching
path = page_cache_path(path)
benchmark "Expired page: #{page_cache_file(path)}" do
File.delete(page_cache_path(path)) if File.exist?(page_cache_path(path))
event = ActiveSupport::Orchestra.instrument(:expire_page, :path => path) do
File.delete(path) if File.exist?(path)
end
log_with_time("Expired page: #{path}", event.duration)
event.result
end
# Manually cache the +content+ in the key determined by +path+. Example:
# cache_page "I'm the cached content", "/lists/show"
def cache_page(content, path)
return unless perform_caching
path = page_cache_path(path)
benchmark "Cached page: #{page_cache_file(path)}" do
FileUtils.makedirs(File.dirname(page_cache_path(path)))
File.open(page_cache_path(path), "wb+") { |f| f.write(content) }
event = ActiveSupport::Orchestra.instrument(:cache_page, :path => path) do
FileUtils.makedirs(File.dirname(path))
File.open(path, "wb+") { |f| f.write(content) }
end
log_with_time("Cached page: #{path}", event.duration)
event.result
end
# Caches the +actions+ using the page-caching approach that'll store the cache in a path within the page_cache_directory that
@@ -149,4 +157,4 @@ module ActionController #:nodoc:
end
end
end
end
end

View File

@@ -54,7 +54,7 @@ module ActionController
end
end
delegate :to_prepare, :prepare_dispatch, :before_dispatch, :after_dispatch,
delegate :to_prepare, :before_dispatch, :around_dispatch, :after_dispatch,
:to => ActionDispatch::Callbacks
def new

View File

@@ -4,15 +4,13 @@ use "Rack::Lock", :if => lambda {
use "ActionDispatch::ShowExceptions", lambda { ActionController::Base.consider_all_requests_local }
use "ActionDispatch::Callbacks", lambda { ActionController::Dispatcher.prepare_each_request }
use "ActionDispatch::Rescue", lambda {
controller = (::ApplicationController rescue ActionController::Base)
# TODO: Replace with controller.action(:_rescue_action)
controller.method(:rescue_action)
}
# TODO: Redirect global exceptions somewhere?
# use "ActionDispatch::Rescue"
use lambda { ActionController::Base.session_store },
lambda { ActionController::Base.session_options }
use "ActionDispatch::ParamsParser"
use "Rack::MethodOverride"
use "Rack::Head"
use "Rack::Head"

View File

@@ -191,7 +191,7 @@ module ActionController #:nodoc:
def memoized_find_layout(layout, formats) #:nodoc:
return layout if layout.nil? || layout.respond_to?(:render)
prefix = layout.to_s =~ /layouts\// ? nil : "layouts"
view_paths.find(layout.to_s, {:formats => formats}, prefix)
find_template(layout.to_s, {:formats => formats}, :_prefix => prefix)
end
def find_layout(*args)
@@ -200,7 +200,7 @@ module ActionController #:nodoc:
end
def layout_list #:nodoc:
Array(view_paths).sum([]) { |path| Dir["#{path.to_str}/layouts/**/*"] }
Array(view_paths).sum([]) { |path| Dir["#{path}/layouts/**/*"] }
end
memoize :layout_list

View File

@@ -1,3 +1,5 @@
require 'active_support/core_ext/class/inheritable_attributes'
module ActionController
# ActionController::Metal provides a way to get a valid Rack application from a controller.
#
@@ -79,6 +81,15 @@ module ActionController
end
class ActionEndpoint
@@endpoints = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
def self.for(controller, action, stack)
@@endpoints[controller][action][stack] ||= begin
endpoint = new(controller, action)
stack.build(endpoint)
end
end
def initialize(controller, action)
@controller, @action = controller, action
end
@@ -88,6 +99,16 @@ module ActionController
end
end
extlib_inheritable_accessor(:middleware_stack) { ActionDispatch::MiddlewareStack.new }
def self.use(*args)
middleware_stack.use(*args)
end
def self.middleware
middleware_stack
end
# Return a rack endpoint for the given action. Memoize the endpoint, so
# multiple calls into MyController.action will return the same object
# for the same action.
@@ -98,8 +119,7 @@ module ActionController
# ==== Returns
# Proc:: A rack application
def self.action(name)
@actions ||= {}
@actions[name.to_s] ||= ActionEndpoint.new(self, name)
ActionEndpoint.for(self, name, middleware_stack)
end
end
end

View File

@@ -49,7 +49,7 @@ module ActionController
end
elsif block_given?
key = key.dup
value = value.dup if value
value = value.dup if value.duplicable?
yield key, value
filtered_parameters[key] = value
else

View File

@@ -1,52 +1,13 @@
module ActionController #:nodoc:
# Actions that fail to perform as expected throw exceptions. These
# exceptions can either be rescued for the public view (with a nice
# user-friendly explanation) or for the developers view (with tons of
# debugging information). The developers view is already implemented by
# the Action Controller, but the public view should be tailored to your
# specific application.
#
# The default behavior for public exceptions is to render a static html
# file with the name of the error code thrown. If no such file exists, an
# empty response is sent with the correct status code.
#
# You can override what constitutes a local request by overriding the
# <tt>local_request?</tt> method in your own controller. Custom rescue
# behavior is achieved by overriding the <tt>rescue_action_in_public</tt>
# and <tt>rescue_action_locally</tt> methods.
module Rescue
extend ActiveSupport::Concern
included do
include ActiveSupport::Rescuable
end
module ClassMethods
# This can be removed once we can move action(:_rescue_action) into middlewares.rb
# Currently, it does controller.method(:rescue_action), which is hiding the implementation
# difference between the old and new base.
def rescue_action(env)
action(:_rescue_action).call(env)
end
end
attr_internal :rescued_exception
include ActiveSupport::Rescuable
private
def method_for_action(action_name)
return action_name if self.rescued_exception = request.env.delete("action_dispatch.rescue.exception")
super
end
def _rescue_action
rescue_with_handler(rescued_exception) || raise(rescued_exception)
end
def process_action(*)
def process_action(*args)
super
rescue Exception => exception
self.rescued_exception = exception
_rescue_action
rescue_with_handler(exception) || raise(exception)
end
end
end

View File

@@ -2,9 +2,7 @@ require 'stringio'
require 'uri'
require 'active_support/test_case'
require 'active_support/core_ext/object/metaclass'
require 'rack/mock_session'
require 'rack/test/cookie_jar'
require 'rack/test'
module ActionController
module Integration #:nodoc:
@@ -251,7 +249,7 @@ module ActionController
end
end
opts = {
env = {
:method => method,
:params => parameters,
@@ -261,25 +259,24 @@ module ActionController
"rack.url_scheme" => https? ? "https" : "http",
"REQUEST_URI" => path,
"PATH_INFO" => path,
"HTTP_HOST" => host,
"REMOTE_ADDR" => remote_addr,
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
"HTTP_ACCEPT" => accept
}
env = ActionDispatch::TestRequest.env_for(path, opts)
(rack_environment || {}).each do |key, value|
env[key] = value
end
session = Rack::Test::Session.new(@mock_session)
@controller = ActionController::Base.capture_instantiation do
@mock_session.request(URI.parse(path), env)
session.request(path, env)
end
@request_count += 1
@request = ActionDispatch::Request.new(env)
@request = ActionDispatch::Request.new(session.last_request.env)
@response = ActionDispatch::TestResponse.from_response(@mock_session.last_response)
@html_document = nil

View File

@@ -84,7 +84,7 @@ module ActionController #:nodoc:
#
# Pass a true third parameter to ensure the uploaded file is opened in binary mode (only required for Windows):
# post :change_avatar, :avatar => ActionController::TestUploadedFile.new(ActionController::TestCase.fixture_path + '/files/spongebob.png', 'image/png', :binary)
TestUploadedFile = ActionDispatch::TestRequest::Multipart::UploadedFile
TestUploadedFile = Rack::Test::UploadedFile
module TestProcess
def self.included(base)
@@ -133,7 +133,7 @@ module ActionController #:nodoc:
@request.env['REQUEST_METHOD'] = http_method
parameters ||= {}
@request.assign_parameters(@controller.class.controller_path, action.to_s, parameters)
@request.assign_parameters(@controller.class.name.underscore.sub(/_controller$/, ''), action.to_s, parameters)
@request.session = ActionController::TestSession.new(session) unless session.nil?
@request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash

View File

@@ -21,10 +21,6 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift activesupport_path if File.directory?(activesupport_path)
require 'active_support'
require 'rack'
module Rack
@@ -59,3 +55,7 @@ module ActionDispatch
end
autoload :Mime, 'action_dispatch/http/mime_type'
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift activesupport_path if File.directory?(activesupport_path)
require 'active_support'

View File

@@ -1,40 +1,55 @@
module ActionDispatch
class Callbacks
include ActiveSupport::Callbacks
define_callbacks :prepare, :before, :after
include ActiveSupport::NewCallbacks
define_callbacks :call, :terminator => "result == false", :scope => :kind
define_callbacks :prepare, :scope => :name
# Add a preparation callback. Preparation callbacks are run before every
# request in development mode, and before the first request in production mode.
#
# If a symbol with a block is given, the symbol is used as an identifier.
# That allows to_prepare to be called again with the same identifier to
# replace the existing callback. Passing an identifier is a suggested
# practice if the code adding a preparation block may be reloaded.
def self.to_prepare(*args, &block)
if args.first.is_a?(Symbol) && block_given?
define_method :"__#{args.first}", &block
set_callback(:prepare, :"__#{args.first}")
else
set_callback(:prepare, *args, &block)
end
end
def self.before(*args, &block)
set_callback(:call, :before, *args, &block)
end
def self.around(*args, &block)
set_callback(:call, :around, *args, &block)
end
def self.after(*args, &block)
set_callback(:call, :after, *args, &block)
end
class << self
# DEPRECATED
alias_method :prepare_dispatch, :prepare
alias_method :before_dispatch, :before
alias_method :around_dispatch, :around
alias_method :after_dispatch, :after
end
# Add a preparation callback. Preparation callbacks are run before every
# request in development mode, and before the first request in production
# mode.
#
# An optional identifier may be supplied for the callback. If provided,
# to_prepare may be called again with the same identifier to replace the
# existing callback. Passing an identifier is a suggested practice if the
# code adding a preparation block may be reloaded.
def self.to_prepare(identifier = nil, &block)
@prepare_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new
callback = ActiveSupport::Callbacks::Callback.new(:prepare, block, :identifier => identifier)
@prepare_callbacks.replace_or_append!(callback)
end
def initialize(app, prepare_each_request = false)
@app, @prepare_each_request = app, prepare_each_request
run_callbacks :prepare
_run_prepare_callbacks
end
def call(env)
run_callbacks :before
run_callbacks :prepare if @prepare_each_request
@app.call(env)
ensure
run_callbacks :after, :enumerator => :reverse_each
_run_call_callbacks do
_run_prepare_callbacks if @prepare_each_request
@app.call(env)
end
end
end
end

View File

@@ -1,14 +1,26 @@
module ActionDispatch
class Rescue
def initialize(app, rescuer)
@app, @rescuer = app, rescuer
def initialize(app, rescuers = {}, &block)
@app, @rescuers = app, {}
rescuers.each { |exception, rescuer| rescue_from(exception, rescuer) }
instance_eval(&block) if block_given?
end
def call(env)
@app.call(env)
rescue Exception => exception
env['action_dispatch.rescue.exception'] = exception
@rescuer.call(env)
if rescuer = @rescuers[exception.class.name]
env['action_dispatch.rescue.exception'] = exception
rescuer.call(env)
else
raise exception
end
end
protected
def rescue_from(exception, rescuer)
exception = exception.class.name if exception.is_a?(Exception)
@rescuers[exception.to_s] = rescuer
end
end
end

View File

@@ -49,7 +49,18 @@ module ActionDispatch
:expire_after => nil,
:httponly => true
}.freeze
class OptionsHash < Hash
def initialize(by, env, default_options)
@session_data = env[CookieStore::ENV_SESSION_KEY]
default_options.each { |key, value| self[key] = value }
end
def [](key)
key == :id ? @session_data[:session_id] : super(key)
end
end
ENV_SESSION_KEY = "rack.session".freeze
ENV_SESSION_OPTIONS_KEY = "rack.session.options".freeze
HTTP_SET_COOKIE = "Set-Cookie".freeze
@@ -90,8 +101,8 @@ module ActionDispatch
def call(env)
env[ENV_SESSION_KEY] = AbstractStore::SessionHash.new(self, env)
env[ENV_SESSION_OPTIONS_KEY] = @default_options.dup
env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
status, headers, body = @app.call(env)
session_data = env[ENV_SESSION_KEY]

View File

@@ -1,52 +1,47 @@
require "active_support/core_ext/kernel/requires"
begin
require_library_or_gem 'memcache'
module ActionDispatch
module Session
class MemCacheStore < AbstractStore
def initialize(app, options = {})
require 'memcache'
module ActionDispatch
module Session
class MemCacheStore < AbstractStore
def initialize(app, options = {})
# Support old :expires option
options[:expire_after] ||= options[:expires]
# Support old :expires option
options[:expire_after] ||= options[:expires]
super
super
@default_options = {
:namespace => 'rack:session',
:memcache_server => 'localhost:11211'
}.merge(@default_options)
@default_options = {
:namespace => 'rack:session',
:memcache_server => 'localhost:11211'
}.merge(@default_options)
@pool = options[:cache] || MemCache.new(@default_options[:memcache_server], @default_options)
unless @pool.servers.any? { |s| s.alive? }
raise "#{self} unable to find server during initialization."
@pool = options[:cache] || MemCache.new(@default_options[:memcache_server], @default_options)
unless @pool.servers.any? { |s| s.alive? }
raise "#{self} unable to find server during initialization."
end
@mutex = Mutex.new
super
end
private
def get_session(env, sid)
sid ||= generate_sid
begin
session = @pool.get(sid) || {}
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
session = {}
end
@mutex = Mutex.new
super
[sid, session]
end
private
def get_session(env, sid)
sid ||= generate_sid
begin
session = @pool.get(sid) || {}
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
session = {}
end
[sid, session]
end
def set_session(env, sid, session_data)
options = env['rack.session.options']
expiry = options[:expire_after] || 0
@pool.set(sid, session_data, expiry)
return true
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
return false
end
end
def set_session(env, sid, session_data)
options = env['rack.session.options']
expiry = options[:expire_after] || 0
@pool.set(sid, session_data, expiry)
return true
rescue MemCache::MemCacheError, Errno::ECONNREFUSED
return false
end
end
end
rescue LoadError
# MemCache wasn't available so neither can the store be
end

View File

@@ -15,12 +15,12 @@
show = "document.getElementById('#{name.gsub /\s/, '-'}').style.display='block';"
hide = (names - [name]).collect {|hide_name| "document.getElementById('#{hide_name.gsub /\s/, '-'}').style.display='none';"}
%>
<a href="#" onclick="<%= hide %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
<a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
<% end %>
<% traces.each do |name, trace| %>
<div id="<%= name.gsub /\s/, '-' %>" style="display: <%= name == "Application Trace" ? 'block' : 'none' %>;">
<pre><code><%= trace.join "\n" %></code></pre>
<pre><code><%=h trace.join "\n" %></code></pre>
</div>
<% end %>
</div>

View File

@@ -1,308 +1,13 @@
module ActionDispatch
class TestRequest < Request
# Improve version of Multipart thats in rack/master
module Multipart #:nodoc:
class UploadedFile
# The filename, *not* including the path, of the "uploaded" file
attr_reader :original_filename
# The content type of the "uploaded" file
attr_accessor :content_type
def initialize(path, content_type = "text/plain", binary = false)
raise "#{path} file does not exist" unless ::File.exist?(path)
@content_type = content_type
@original_filename = ::File.basename(path)
@tempfile = Tempfile.new(@original_filename)
@tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
@tempfile.binmode if binary
FileUtils.copy_file(path, @tempfile.path)
end
def path
@tempfile.path
end
alias_method :local_path, :path
def method_missing(method_name, *args, &block) #:nodoc:
@tempfile.__send__(method_name, *args, &block)
end
end
EOL = "\r\n"
MULTIPART_BOUNDARY = "AaB03x"
def self.parse_multipart(env)
unless env['CONTENT_TYPE'] =~
%r|\Amultipart/.*boundary=\"?([^\";,]+)\"?|n
nil
else
boundary = "--#{$1}"
params = {}
buf = ""
content_length = env['CONTENT_LENGTH'].to_i
input = env['rack.input']
input.rewind
boundary_size = Utils.bytesize(boundary) + EOL.size
bufsize = 16384
content_length -= boundary_size
read_buffer = ''
status = input.read(boundary_size, read_buffer)
raise EOFError, "bad content body" unless status == boundary + EOL
rx = /(?:#{EOL})?#{Regexp.quote boundary}(#{EOL}|--)/n
loop {
head = nil
body = ''
filename = content_type = name = nil
until head && buf =~ rx
if !head && i = buf.index(EOL+EOL)
head = buf.slice!(0, i+2) # First \r\n
buf.slice!(0, 2) # Second \r\n
filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1]
content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
if content_type || filename
body = Tempfile.new("RackMultipart")
body.binmode if body.respond_to?(:binmode)
end
next
end
# Save the read body part.
if head && (boundary_size+4 < buf.size)
body << buf.slice!(0, buf.size - (boundary_size+4))
end
c = input.read(bufsize < content_length ? bufsize : content_length, read_buffer)
raise EOFError, "bad content body" if c.nil? || c.empty?
buf << c
content_length -= c.size
end
# Save the rest.
if i = buf.index(rx)
body << buf.slice!(0, i)
buf.slice!(0, boundary_size+2)
content_length = -1 if $1 == "--"
end
if filename == ""
# filename is blank which means no file has been selected
data = nil
elsif filename
body.rewind
# Take the basename of the upload's original filename.
# This handles the full Windows paths given by Internet Explorer
# (and perhaps other broken user agents) without affecting
# those which give the lone filename.
filename =~ /^(?:.*[:\\\/])?(.*)/m
filename = $1
data = {:filename => filename, :type => content_type,
:name => name, :tempfile => body, :head => head}
elsif !filename && content_type
body.rewind
# Generic multipart cases, not coming from a form
data = {:type => content_type,
:name => name, :tempfile => body, :head => head}
else
data = body
end
Utils.normalize_params(params, name, data) unless data.nil?
break if buf.empty? || content_length == -1
}
input.rewind
params
end
end
def self.build_multipart(params, first = true)
if first
unless params.is_a?(Hash)
raise ArgumentError, "value must be a Hash"
end
multipart = false
query = lambda { |value|
case value
when Array
value.each(&query)
when Hash
value.values.each(&query)
when UploadedFile
multipart = true
end
}
params.values.each(&query)
return nil unless multipart
end
flattened_params = Hash.new
params.each do |key, value|
k = first ? key.to_s : "[#{key}]"
case value
when Array
value.map { |v|
build_multipart(v, false).each { |subkey, subvalue|
flattened_params["#{k}[]#{subkey}"] = subvalue
}
}
when Hash
build_multipart(value, false).each { |subkey, subvalue|
flattened_params[k + subkey] = subvalue
}
else
flattened_params[k] = value
end
end
if first
flattened_params.map { |name, file|
if file.respond_to?(:original_filename)
::File.open(file.path, "rb") do |f|
f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
<<-EOF
--#{MULTIPART_BOUNDARY}\r
Content-Disposition: form-data; name="#{name}"; filename="#{Rack::Utils.escape(file.original_filename)}"\r
Content-Type: #{file.content_type}\r
Content-Length: #{::File.stat(file.path).size}\r
\r
#{f.read}\r
EOF
end
else
<<-EOF
--#{MULTIPART_BOUNDARY}\r
Content-Disposition: form-data; name="#{name}"\r
\r
#{file}\r
EOF
end
}.join + "--#{MULTIPART_BOUNDARY}--\r"
else
flattened_params
end
end
end
DEFAULT_ENV = {
"rack.version" => [1,0],
"rack.input" => StringIO.new,
"rack.errors" => StringIO.new,
"rack.multithread" => true,
"rack.multiprocess" => true,
"rack.run_once" => false,
}
# Improve version of env_for thats in rack/master
def self.env_for(uri="", opts={}) #:nodoc:
uri = URI(uri)
uri.path = "/#{uri.path}" unless uri.path[0] == ?/
env = DEFAULT_ENV.dup
env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET"
env["SERVER_NAME"] = uri.host || "example.org"
env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80"
env["QUERY_STRING"] = uri.query.to_s
env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path
env["rack.url_scheme"] = uri.scheme || "http"
env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off"
env["SCRIPT_NAME"] = opts[:script_name] || ""
if opts[:fatal]
env["rack.errors"] = FatalWarner.new
else
env["rack.errors"] = StringIO.new
end
if params = opts[:params]
if env["REQUEST_METHOD"] == "GET"
params = Rack::Utils.parse_nested_query(params) if params.is_a?(String)
params.update(Rack::Utils.parse_nested_query(env["QUERY_STRING"]))
env["QUERY_STRING"] = build_nested_query(params)
elsif !opts.has_key?(:input)
opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
if params.is_a?(Hash)
if data = Multipart.build_multipart(params)
opts[:input] = data
opts["CONTENT_LENGTH"] ||= data.length.to_s
opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Multipart::MULTIPART_BOUNDARY}"
else
opts[:input] = build_nested_query(params)
end
else
opts[:input] = params
end
end
end
empty_str = ""
empty_str.force_encoding("ASCII-8BIT") if empty_str.respond_to? :force_encoding
opts[:input] ||= empty_str
if String === opts[:input]
rack_input = StringIO.new(opts[:input])
else
rack_input = opts[:input]
end
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
env['rack.input'] = rack_input
env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s
opts.each { |field, value|
env[field] = value if String === field
}
env
end
def self.build_nested_query(value, prefix = nil)
case value
when Array
value.map { |v|
build_nested_query(v, "#{prefix}[]")
}.join("&")
when Hash
value.map { |k, v|
build_nested_query(v, prefix ? "#{prefix}[#{Rack::Utils.escape(k)}]" : Rack::Utils.escape(k))
}.join("&")
when String
raise ArgumentError, "value must be a Hash" if prefix.nil?
"#{prefix}=#{Rack::Utils.escape(value)}"
else
prefix
end
end
DEFAULT_ENV = Rack::MockRequest.env_for('/')
def self.new(env = {})
super
end
def initialize(env = {})
super(self.class.env_for('/').merge(env))
super(DEFAULT_ENV.merge(env))
self.host = 'test.host'
self.remote_addr = '0.0.0.0'

View File

@@ -21,11 +21,6 @@
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift activesupport_path if File.directory?(activesupport_path)
require 'active_support'
require 'active_support/core_ext/class/attribute_accessors'
require File.join(File.dirname(__FILE__), "action_pack")
module ActionView
@@ -36,14 +31,12 @@ module ActionView
autoload :Base, 'action_view/base'
autoload :Context, 'action_view/context'
autoload :Helpers, 'action_view/helpers'
autoload :InlineTemplate, 'action_view/template/inline'
autoload :MissingTemplate, 'action_view/base'
autoload :Partials, 'action_view/render/partials'
autoload :Resolver, 'action_view/template/resolver'
autoload :PathResolver, 'action_view/template/resolver'
autoload :PathSet, 'action_view/paths'
autoload :Rendering, 'action_view/render/rendering'
autoload :Renderable, 'action_view/template/renderable'
autoload :RenderablePartial, 'action_view/template/partial'
autoload :Template, 'action_view/template/template'
autoload :TemplateError, 'action_view/template/error'
autoload :TemplateHandler, 'action_view/template/handler'
@@ -58,3 +51,8 @@ class ERB
end
I18n.load_path << "#{File.dirname(__FILE__)}/action_view/locale/en.yml"
activesupport_path = "#{File.dirname(__FILE__)}/../../activesupport/lib"
$:.unshift activesupport_path if File.directory?(activesupport_path)
require 'active_support'
require 'active_support/core_ext/class/attribute_accessors'

View File

@@ -1,3 +1,4 @@
require 'thread'
require 'cgi'
require 'action_view/helpers/url_helper'
require 'action_view/helpers/tag_helper'
@@ -286,7 +287,9 @@ module ActionView
end
javascript_src_tag(joined_javascript_name, options)
else
ensure_javascript_sources!(expand_javascript_sources(sources, recursive)).collect { |source| javascript_src_tag(source, options) }.join("\n")
sources = expand_javascript_sources(sources, recursive)
ensure_javascript_sources!(sources) if cache
sources.collect { |source| javascript_src_tag(source, options) }.join("\n")
end
end
@@ -435,7 +438,9 @@ module ActionView
end
stylesheet_tag(joined_stylesheet_name, options)
else
ensure_stylesheet_sources!(expand_stylesheet_sources(sources, recursive)).collect { |source| stylesheet_tag(source, options) }.join("\n")
sources = expand_stylesheet_sources(sources, recursive)
ensure_stylesheet_sources!(sources) if cache
sources.collect { |source| stylesheet_tag(source, options) }.join("\n")
end
end

View File

@@ -449,6 +449,15 @@ module ActionView
# <% end %>
# <% end %>
#
# Or a collection to be used:
#
# <% form_for @person, :url => { :action => "update" } do |person_form| %>
# ...
# <% person_form.fields_for :projects, @active_projects do |project_fields| %>
# Name: <%= project_fields.text_field :name %>
# <% end %>
# <% end %>
#
# When projects is already an association on Person you can use
# +accepts_nested_attributes_for+ to define the writer method for you:
#
@@ -1037,18 +1046,21 @@ module ActionView
def fields_for_with_nested_attributes(association_name, args, block)
name = "#{object_name}[#{association_name}_attributes]"
association = @object.send(association_name)
explicit_object = args.first.to_model if args.first.respond_to?(:to_model)
association = args.first.to_model if args.first.respond_to?(:to_model)
if association.respond_to?(:new_record?)
association = [association] if @object.send(association_name).is_a?(Array)
elsif !association.is_a?(Array)
association = @object.send(association_name)
end
if association.is_a?(Array)
children = explicit_object ? [explicit_object] : association
explicit_child_index = args.last[:child_index] if args.last.is_a?(Hash)
children.map do |child|
association.map do |child|
fields_for_nested_model("#{name}[#{explicit_child_index || nested_child_index(name)}]", child, args, block)
end.join
else
fields_for_nested_model(name, explicit_object || association, args, block)
elsif association
fields_for_nested_model(name, association, args, block)
end
end

View File

@@ -106,7 +106,7 @@ module ActionView
# escape_once("&lt;&lt; Accept & Checkout")
# # => "&lt;&lt; Accept &amp; Checkout"
def escape_once(html)
html.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
ActiveSupport::Multibyte.clean(html.to_s).gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
end
private

View File

@@ -1,4 +1,5 @@
require 'action_view/helpers/javascript_helper'
require 'active_support/core_ext/array/access'
require 'active_support/core_ext/hash/keys'
module ActionView

View File

@@ -6,7 +6,7 @@ module ActionView
self.default_format = Mime::XML
def compile(template)
require 'builder'
require 'active_support/vendor/builder'
"xml = ::Builder::XmlMarkup.new(:indent => 2);" +
"self.output_buffer = xml.target!;" +
template.source +

View File

@@ -1,19 +0,0 @@
module ActionView #:nodoc:
class InlineTemplate #:nodoc:
include Renderable
attr_reader :source, :extension, :method_segment
def initialize(source, type = nil)
@source = source
@extension = type
@method_segment = "inline_#{@source.hash.abs}"
end
private
# Always recompile inline templates
def recompile?
true
end
end
end

View File

@@ -1,18 +0,0 @@
module ActionView
# NOTE: The template that this mixin is being included into is frozen
# so you cannot set or modify any instance variables
module RenderablePartial #:nodoc:
extend ActiveSupport::Memoizable
def variable_name
name.sub(/\A_/, '').to_sym
end
memoize :variable_name
def counter_name
"#{variable_name}_counter".to_sym
end
memoize :counter_name
end
end

View File

@@ -1,93 +0,0 @@
# encoding: utf-8
module ActionView
# NOTE: The template that this mixin is being included into is frozen
# so you cannot set or modify any instance variables
module Renderable #:nodoc:
extend ActiveSupport::Memoizable
def render(view, locals)
compile(locals)
view.send(method_name(locals), locals) {|*args| yield(*args) }
end
def load!
names = CompiledTemplates.instance_methods.grep(/#{method_name_without_locals}/)
names.each do |name|
CompiledTemplates.class_eval do
remove_method(name)
end
end
super
end
private
def filename
'compiled-template'
end
def handler
Template.handler_class_for_extension(extension)
end
memoize :handler
def compiled_source
handler.call(self)
end
memoize :compiled_source
def method_name_without_locals
['_run', extension, method_segment].compact.join('_')
end
memoize :method_name_without_locals
def method_name(local_assigns)
if local_assigns && local_assigns.any?
method_name = method_name_without_locals.dup
method_name << "_locals_#{local_assigns.keys.map { |k| k.to_s }.sort.join('_')}"
else
method_name = method_name_without_locals
end
method_name.to_sym
end
# Compile and evaluate the template's code (if necessary)
def compile(local_assigns)
render_symbol = method_name(local_assigns)
if !CompiledTemplates.method_defined?(render_symbol) || recompile?
compile!(render_symbol, local_assigns)
end
end
private
def compile!(render_symbol, local_assigns)
locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
source = <<-end_src
def #{render_symbol}(local_assigns)
old_output_buffer = output_buffer;#{locals_code};#{compiled_source}
ensure
self.output_buffer = old_output_buffer
end
end_src
begin
ActionView::CompiledTemplates.module_eval(source, filename.to_s, 0)
rescue Exception => e # errors from template code
if logger = defined?(ActionController) && Base.logger
logger.debug "ERROR: compiling #{render_symbol} RAISED #{e}"
logger.debug "Function body: #{source}"
logger.debug "Backtrace: #{e.backtrace.join("\n")}"
end
raise ActionView::TemplateError.new(self, {}, e)
end
end
def recompile?
false
end
end
end

View File

@@ -1,9 +1,28 @@
require "pathname"
require "active_support/core_ext/class"
require "action_view/template/template"
module ActionView
# Abstract superclass
class Resolver
class_inheritable_accessor(:registered_details)
self.registered_details = {}
def self.register_detail(name, options = {})
registered_details[name] = lambda do |val|
val ||= yield
val |= [nil] unless options[:allow_nil] == false
val
end
end
register_detail(:locale) { [I18n.locale] }
register_detail(:formats) { Mime::SET.symbols }
register_detail(:handlers, :allow_nil => false) do
TemplateHandlers.extensions
end
def initialize(options = {})
@cache = options[:cache]
@cached = {}
@@ -11,15 +30,18 @@ module ActionView
# Normalizes the arguments and passes it on to find_template
def find(*args)
find_all_by_parts(*args).first
find_all(*args).first
end
def find_all_by_parts(name, details = {}, prefix = nil, partial = nil)
details[:locales] = [I18n.locale]
name = name.to_s.gsub(handler_matcher, '').split("/")
find_templates(name.pop, details, [prefix, *name].compact.join("/"), partial)
def find_all(name, details = {}, prefix = nil, partial = nil)
details = normalize_details(details)
name, prefix = normalize_name(name, prefix)
cached([name, details, prefix, partial]) do
find_templates(name, details, prefix, partial)
end
end
private
# This is what child classes implement. No defaults are needed
@@ -28,29 +50,26 @@ module ActionView
def find_templates(name, details, prefix, partial)
raise NotImplementedError
end
def valid_handlers
@valid_handlers ||= TemplateHandlers.extensions
def normalize_details(details)
details = details.dup
# TODO: Refactor this concern out of the resolver
details.delete(:formats) if details[:formats] == [:"*/*"]
registered_details.each do |k, v|
details[k] = v.call(details[k])
end
details
end
def handler_matcher
@handler_matcher ||= begin
e = valid_handlers.join('|')
/\.(?:#{e})$/
end
end
# Support legacy foo.erb names even though we now ignore .erb
# as well as incorrectly putting part of the path in the template
# name instead of the prefix.
def normalize_name(name, prefix)
handlers = TemplateHandlers.extensions.join('|')
name = name.to_s.gsub(/\.(?:#{handlers})$/, '')
def handler_glob
@handler_glob ||= begin
e = TemplateHandlers.extensions.map{|h| ".#{h}"}.join(",")
"{#{e}}"
end
end
def formats_glob
@formats_glob ||= begin
'{' + Mime::SET.symbols.map { |l| ".#{l}," }.join + '}'
end
parts = name.split('/')
return parts.pop, [prefix, *parts].compact.join("/")
end
def cached(key)
@@ -60,80 +79,49 @@ module ActionView
end
end
class FileSystemResolver < Resolver
class PathResolver < Resolver
def self.cached_glob
@@cached_glob ||= {}
end
def initialize(path, options = {})
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
super(options)
@path = Pathname.new(path).expand_path
end
# TODO: This is the currently needed API. Make this suck less
# ==== <suck>
attr_reader :path
EXTENSION_ORDER = [:locale, :formats, :handlers]
def to_s
path.to_s
@path.to_s
end
alias to_path to_s
def find_templates(name, details, prefix, partial)
path = build_path(name, details, prefix, partial)
query(path, EXTENSION_ORDER.map { |ext| details[ext] })
end
def to_str
path.to_s
end
def ==(path)
to_str == path.to_str
end
def eql?(path)
to_str == path.to_str
end
# ==== </suck>
def find_templates(name, details, prefix, partial, root = "#{@path}/")
if glob = details_to_glob(name, details, prefix, partial, root)
cached(glob) do
Dir[glob].map do |path|
next if File.directory?(path)
source = File.read(path)
identifier = Pathname.new(path).expand_path.to_s
Template.new(source, identifier, *path_to_details(path))
end.compact
end
end
end
private
# :api: plugin
def details_to_glob(name, details, prefix, partial, root)
self.class.cached_glob[[name, prefix, partial, details, root]] ||= begin
path = ""
path << "#{prefix}/" unless prefix.empty?
path << (partial ? "_#{name}" : name)
extensions = ""
[:locales, :formats].each do |k|
extensions << if exts = details[k]
'{' + exts.map {|e| ".#{e},"}.join + '}'
else
k == :formats ? formats_glob : ''
end
end
"#{root}#{path}#{extensions}#{handler_glob}"
end
def build_path(name, details, prefix, partial)
path = ""
path << "#{prefix}/" unless prefix.empty?
path << (partial ? "_#{name}" : name)
path
end
# TODO: fix me
# :api: plugin
def query(path, exts)
query = "#{@path}/#{path}"
exts.each do |ext|
query << '{' << ext.map {|e| e && ".#{e}" }.join(',') << '}'
end
Dir[query].map do |path|
next if File.directory?(path)
source = File.read(path)
identifier = Pathname.new(path).expand_path.to_s
Template.new(source, identifier, *path_to_details(path))
end.compact
end
# # TODO: fix me
# # :api: plugin
def path_to_details(path)
# [:erb, :format => :html, :locale => :en, :partial => true/false]
if m = path.match(%r'/(_)?[\w-]+(\.[\w-]+)*\.(\w+)$')
if m = path.match(%r'(?:^|/)(_)?[\w-]+(\.[\w-]+)*\.(\w+)$')
partial = m[1] == '_'
details = (m[2]||"").split('.').reject { |e| e.empty? }
handler = Template.handler_class_for_extension(m[3])
@@ -146,13 +134,32 @@ module ActionView
end
end
class FileSystemResolverWithFallback < FileSystemResolver
class FileSystemResolver < PathResolver
def initialize(path, options = {})
raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver)
super(options)
@path = Pathname.new(path).expand_path
end
end
def find_templates(name, details, prefix, partial)
templates = super
return super(name, details, prefix, partial, '') if templates.empty?
templates
# OMG HAX
# TODO: remove hax
class FileSystemResolverWithFallback < Resolver
def initialize(path, options = {})
super(options)
@paths = [FileSystemResolver.new(path, options), FileSystemResolver.new("", options), FileSystemResolver.new("/", options)]
end
def find_templates(*args)
@paths.each do |p|
template = p.find_templates(*args)
return template unless template.empty?
end
[]
end
def to_s
@paths.first.to_s
end
end
end

View File

@@ -27,8 +27,10 @@ module ActionView
end
def render(view, locals, &block)
method_name = compile(locals, view)
view.send(method_name, locals, &block)
ActiveSupport::Orchestra.instrument(:render_template, :identifier => identifier) do
method_name = compile(locals, view)
view.send(method_name, locals, &block)
end.result
rescue Exception => e
if e.is_a?(TemplateError)
e.sub_template_of(self)

View File

@@ -1 +0,0 @@
require 'action_pack'

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module AbstractController
module Testing
@@ -148,10 +148,10 @@ module AbstractController
private
def self.layout(formats)
begin
view_paths.find(name.underscore, {:formats => formats}, "layouts")
find_template(name.underscore, {:formats => formats}, :_prefix => "layouts")
rescue ActionView::MissingTemplate
begin
view_paths.find("application", {:formats => formats}, "layouts")
find_template("application", {:formats => formats}, :_prefix => "layouts")
rescue ActionView::MissingTemplate
end
end

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module AbstractController
module Testing
@@ -235,4 +235,4 @@ module AbstractController
end
end
end
end

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module AbstractController
module Testing

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
require 'active_support/core_ext/class/removal'
module AbstractControllerTests

View File

@@ -1,21 +0,0 @@
$:.unshift(File.dirname(__FILE__) + '/../../lib')
$:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib')
$:.unshift(File.dirname(__FILE__) + '/../lib')
require 'rubygems'
require 'test/unit'
require 'active_support'
require 'active_support/test_case'
require 'abstract_controller'
require 'action_view'
require 'action_view/base'
require 'action_dispatch'
require 'fixture_template'
begin
require 'ruby-debug'
Debugger.settings[:autoeval] = true
Debugger.start
rescue LoadError
# Debugging disabled. `gem install ruby-debug` to enable.
end

View File

@@ -1,29 +1,36 @@
$:.unshift(File.dirname(__FILE__) + '/../lib')
$:.unshift(File.dirname(__FILE__) + '/../../activesupport/lib')
$:.unshift(File.dirname(__FILE__) + '/../../activemodel/lib')
$:.unshift(File.dirname(__FILE__) + '/lib')
$:.unshift(File.dirname(__FILE__) + '/lib')
$:.unshift(File.dirname(__FILE__) + '/fixtures/helpers')
$:.unshift(File.dirname(__FILE__) + '/fixtures/alternate_helpers')
ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp')
bundler = File.join(File.dirname(__FILE__), '..', 'vendor', 'gems', 'environment')
require bundler if File.exist?("#{bundler}.rb")
ENV['new_base'] = "true"
$stderr.puts "Running old tests on new_base"
begin
%w( rack rack/test sqlite3 ).each { |lib| require lib }
rescue LoadError => e
abort e.message
end
ENV['TMPDIR'] = File.join(File.dirname(__FILE__), 'tmp')
require 'test/unit'
require 'active_support'
require 'active_support/test_case'
require 'abstract_controller'
require 'action_controller'
require 'action_view'
require 'action_view/base'
require 'action_dispatch'
require 'active_model'
require 'fixture_template'
require 'action_controller/testing/process'
require 'action_view/test_case'
require 'action_controller/testing/integration'
require 'action_view/test_case'
require 'active_support/dependencies'
require 'active_model'
$tags[:new_base] = true
begin
require 'ruby-debug'
@@ -33,6 +40,8 @@ rescue LoadError
# Debugging disabled. `gem install ruby-debug` to enable.
end
require 'pp' # require 'pp' early to prevent hidden_methods from not picking up the pretty-print methods until too late
ActiveSupport::Dependencies.hook!
# Show backtraces for deprecated behavior for quicker cleanup.
@@ -55,6 +64,61 @@ module ActionView
end
end
# Temporary base class
class Rack::TestCase < ActionController::IntegrationTest
setup do
ActionController::Base.session_options[:key] = "abc"
ActionController::Base.session_options[:secret] = ("*" * 30)
end
def app
@app ||= ActionController::Dispatcher.new
end
def self.testing(klass = nil)
if klass
@testing = "/#{klass.name.underscore}".sub!(/_controller$/, '')
else
@testing
end
end
def get(thing, *args)
if thing.is_a?(Symbol)
super("#{self.class.testing}/#{thing}", *args)
else
super
end
end
def assert_body(body)
assert_equal body, Array.wrap(response.body).join
end
def assert_status(code)
assert_equal code, response.status
end
def assert_response(body, status = 200, headers = {})
assert_body body
assert_status status
headers.each do |header, value|
assert_header header, value
end
end
def assert_content_type(type)
assert_equal type, response.headers["Content-Type"]
end
def assert_header(name, value)
assert_equal value, response.headers[name]
end
end
class ::ApplicationController < ActionController::Base
end
module ActionController
Base.session = {
:key => '_testing_session',
@@ -131,3 +195,11 @@ module ActionController
end
end
end
class SimpleRouteCase < Rack::TestCase
setup do
ActionController::Routing::Routes.draw do |map|
map.connect ':controller/:action/:id'
end
end
end

View File

@@ -16,7 +16,7 @@ if defined?(ActiveRecord) && defined?(Fixtures)
else
$stderr.print 'Attempting to load Active Record... '
begin
PATH_TO_AR = "#{File.dirname(__FILE__)}/../../../activerecord/lib"
PATH_TO_AR = "#{File.dirname(__FILE__)}/../../activerecord/lib"
raise LoadError, "#{PATH_TO_AR} doesn't exist" unless File.directory?(PATH_TO_AR)
$LOAD_PATH.unshift PATH_TO_AR
require 'active_record'
@@ -72,13 +72,13 @@ class ActiveRecordTestConnector
# Load actionpack sqlite tables
def load_schema
File.read(File.dirname(__FILE__) + "/../fixtures/db_definitions/sqlite.sql").split(';').each do |sql|
File.read(File.dirname(__FILE__) + "/fixtures/db_definitions/sqlite.sql").split(';').each do |sql|
ActiveRecord::Base.connection.execute(sql) unless sql.blank?
end
end
def require_fixture_models
Dir.glob(File.dirname(__FILE__) + "/../fixtures/*.rb").each {|f| require f}
Dir.glob(File.dirname(__FILE__) + "/fixtures/*.rb").each {|f| require f}
end
end
end

View File

@@ -176,6 +176,7 @@ class ActiveRecordStoreTest < ActionController::IntegrationTest
c.connect "/:action"
end
end
reset_app!
yield
end
end

View File

@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'action_controller/vendor/html-scanner'
require 'controller/fake_controllers'
# a controller class to facilitate the tests
class ActionPackAssertionsController < ActionController::Base

View File

@@ -1,5 +1,6 @@
require 'abstract_unit'
require 'logger'
require 'controller/fake_controllers'
class Address
def Address.count(conditions = nil, join = nil)
@@ -15,13 +16,8 @@ class Address
end
end
class AddressesTestController < ActionController::Base
def self.controller_name; "addresses"; end
def self.controller_path; "addresses"; end
end
class AddressesTest < ActionController::TestCase
tests AddressesTestController
tests AddressesController
def setup
super

View File

@@ -441,8 +441,8 @@ class ActionCacheTest < ActionController::TestCase
def test_correct_content_type_is_returned_for_cache_hit
# run it twice to cache it the first time
get :index, :id => 'content-type.xml'
get :index, :id => 'content-type.xml'
get :index, :id => 'content-type', :format => 'xml'
get :index, :id => 'content-type', :format => 'xml'
assert_equal 'application/xml', @response.content_type
end
@@ -625,15 +625,20 @@ class FragmentCachingTest < ActionController::TestCase
def test_fragment_for_logging
fragment_computed = false
@controller.class.expects(:benchmark).with('Cached fragment exists?: views/expensive')
@controller.class.expects(:benchmark).with('Cached fragment miss: views/expensive')
@controller.class.expects(:benchmark).with('Cached fragment hit: views/expensive').never
listener = []
ActiveSupport::Orchestra.register listener
buffer = 'generated till now -> '
@controller.fragment_for(buffer, 'expensive') { fragment_computed = true }
assert_equal 2, listener.size
assert_equal :fragment_exist?, listener[0].name
assert_equal :write_fragment, listener[1].name
assert fragment_computed
assert_equal 'generated till now -> ', buffer
ensure
ActiveSupport::Orchestra.unregister listener
end
end

View File

@@ -1,6 +1,6 @@
require 'abstract_unit'
class ContentTypeController < ActionController::Base
class OldContentTypeController < ActionController::Base
# :ported:
def render_content_type_from_body
response.content_type = Mime::RSS
@@ -56,7 +56,7 @@ class ContentTypeController < ActionController::Base
end
class ContentTypeTest < ActionController::TestCase
tests ContentTypeController
tests OldContentTypeController
def setup
super
@@ -73,11 +73,11 @@ class ContentTypeTest < ActionController::TestCase
end
def test_render_changed_charset_default
ContentTypeController.default_charset = "utf-16"
OldContentTypeController.default_charset = "utf-16"
get :render_defaults
assert_equal "utf-16", @response.charset
assert_equal Mime::HTML, @response.content_type
ContentTypeController.default_charset = "utf-8"
OldContentTypeController.default_charset = "utf-8"
end
# :ported:
@@ -109,12 +109,12 @@ class ContentTypeTest < ActionController::TestCase
end
def test_nil_default_for_rhtml
ContentTypeController.default_charset = nil
OldContentTypeController.default_charset = nil
get :render_default_for_rhtml
assert_equal Mime::HTML, @response.content_type
assert_nil @response.charset, @response.headers.inspect
ensure
ContentTypeController.default_charset = "utf-8"
OldContentTypeController.default_charset = "utf-8"
end
def test_default_for_rhtml
@@ -143,8 +143,7 @@ class ContentTypeTest < ActionController::TestCase
end
class AcceptBasedContentTypeTest < ActionController::TestCase
tests ContentTypeController
tests OldContentTypeController
def setup
super

View File

@@ -3,13 +3,16 @@ require 'abstract_unit'
class DispatcherTest < Test::Unit::TestCase
Dispatcher = ActionController::Dispatcher
class Foo
cattr_accessor :a, :b
end
def setup
ENV['REQUEST_METHOD'] = 'GET'
# Clear callbacks as they are redefined by Dispatcher#define_dispatcher_callbacks
ActionDispatch::Callbacks.instance_variable_set("@prepare_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
ActionDispatch::Callbacks.instance_variable_set("@before_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
ActionDispatch::Callbacks.instance_variable_set("@after_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
ActionDispatch::Callbacks.reset_callbacks(:prepare)
ActionDispatch::Callbacks.reset_callbacks(:call)
@old_router, Dispatcher.router = Dispatcher.router, mock()
Dispatcher.router.stubs(:call).returns([200, {}, 'response'])
@@ -68,13 +71,12 @@ class DispatcherTest < Test::Unit::TestCase
end
def test_to_prepare_with_identifier_replaces
a = b = nil
Dispatcher.to_prepare(:unique_id) { |*args| a = b = 1 }
Dispatcher.to_prepare(:unique_id) { |*args| a = 2 }
Dispatcher.to_prepare(:unique_id) { |*args| Foo.a, Foo.b = 1, 1 }
Dispatcher.to_prepare(:unique_id) { |*args| Foo.a = 2 }
dispatch
assert_equal 2, a
assert_equal nil, b
assert_equal 2, Foo.a
assert_equal nil, Foo.b
end
private

View File

@@ -35,6 +35,7 @@ class FilterParamTest < ActionController::TestCase
test_hashes = [[{},{},[]],
[{'foo'=>nil},{'foo'=>nil},[]],
[{'foo'=>'bar'},{'foo'=>'bar'},[]],
[{'foo'=>1},{'foo'=>1},[]],
[{'foo'=>'bar'},{'foo'=>'bar'},%w'food'],
[{'foo'=>'bar'},{'foo'=>'[FILTERED]'},%w'foo'],
[{'foo'=>'bar', 'bar'=>'foo'},{'foo'=>'[FILTERED]', 'bar'=>'foo'},%w'foo baz'],

View File

@@ -371,12 +371,13 @@ class IntegrationProcessTest < ActionController::IntegrationTest
c.connect "/:action"
end
end
reset!
yield
end
end
end
class MetalTest < ActionController::IntegrationTest
class MetalIntegrationTest < ActionController::IntegrationTest
class Poller
def self.call(env)
if env["PATH_INFO"] =~ /^\/success/

View File

@@ -2,23 +2,27 @@ require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
class TestController < ActionController::Base
protect_from_forgery
class RenderJSTest < ActionController::TestCase
class TestController < ActionController::Base
protect_from_forgery
def render_vanilla_js_hello
render :js => "alert('hello')"
end
def greeting
# let's just rely on the template
end
def show_partial
render :partial => 'partial'
end
end
def self.controller_path
'test'
end
def render_vanilla_js_hello
render :js => "alert('hello')"
end
def greeting
# let's just rely on the template
end
def show_partial
render :partial => 'partial'
end
end
class RenderTest < ActionController::TestCase
tests TestController
def test_render_vanilla_js
@@ -26,14 +30,14 @@ class RenderTest < ActionController::TestCase
assert_equal "alert('hello')", @response.body
assert_equal "text/javascript", @response.content_type
end
def test_render_with_default_from_accept_header
xhr :get, :greeting
assert_equal "$(\"body\").visualEffect(\"highlight\");", @response.body
end
def test_should_render_js_partial
xhr :get, :show_partial, :format => 'js'
assert_equal 'partial js', @response.body
end
end
end

View File

@@ -2,35 +2,39 @@ require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
class TestController < ActionController::Base
protect_from_forgery
def render_json_nil
render :json => nil
class RenderJsonTest < ActionController::TestCase
class TestController < ActionController::Base
protect_from_forgery
def self.controller_path
'test'
end
def render_json_nil
render :json => nil
end
def render_json_hello_world
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end
def render_json_hello_world_with_callback
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert'
end
def render_json_with_custom_content_type
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript'
end
def render_symbol_json
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end
def render_json_with_render_to_string
render :json => {:hello => render_to_string(:partial => 'partial')}
end
end
def render_json_hello_world
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end
def render_json_hello_world_with_callback
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :callback => 'alert'
end
def render_json_with_custom_content_type
render :json => ActiveSupport::JSON.encode(:hello => 'world'), :content_type => 'text/javascript'
end
def render_symbol_json
render :json => ActiveSupport::JSON.encode(:hello => 'world')
end
def render_json_with_render_to_string
render :json => {:hello => render_to_string(:partial => 'partial')}
end
end
class RenderTest < ActionController::TestCase
tests TestController
def setup
@@ -40,8 +44,8 @@ class RenderTest < ActionController::TestCase
@controller.logger = Logger.new(nil)
@request.host = "www.nextangle.com"
end
end
def test_render_json_nil
get :render_json_nil
assert_equal 'null', @response.body
@@ -76,5 +80,5 @@ class RenderTest < ActionController::TestCase
get :render_json_with_render_to_string
assert_equal '{"hello":"partial html"}', @response.body
assert_equal 'application/json', @response.content_type
end
end
end
end

View File

@@ -2,139 +2,144 @@ require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
class TestController < ActionController::Base
protect_from_forgery
layout :determine_layout
class RenderOtherTest < ActionController::TestCase
class TestController < ActionController::Base
protect_from_forgery
module RenderTestHelper
def rjs_helper_method_from_module
page.visual_effect :highlight
def self.controller_path
'test'
end
end
helper RenderTestHelper
helper do
def rjs_helper_method(value)
page.visual_effect :highlight, value
end
end
layout :determine_layout
def enum_rjs_test
render :update do |page|
page.select('.product').each do |value|
page.rjs_helper_method_from_module
page.rjs_helper_method(value)
page.sortable(value, :url => { :action => "order" })
page.draggable(value)
module RenderTestHelper
def rjs_helper_method_from_module
page.visual_effect :highlight
end
end
end
def render_explicit_html_template
end
def render_custom_code_rjs
render :update, :status => 404 do |page|
page.replace :foo, :partial => 'partial'
end
end
def render_implicit_html_template
end
def render_js_with_explicit_template
@project_id = 4
render :template => 'test/delete_with_js'
end
def render_js_with_explicit_action_template
@project_id = 4
render :action => 'delete_with_js'
end
def delete_with_js
@project_id = 4
end
def update_page
render :update do |page|
page.replace_html 'balance', '$37,000,000.00'
page.visual_effect :highlight, 'balance'
helper RenderTestHelper
helper do
def rjs_helper_method(value)
page.visual_effect :highlight, value
end
end
end
def update_page_with_instance_variables
@money = '$37,000,000.00'
@div_id = 'balance'
render :update do |page|
page.replace_html @div_id, @money
page.visual_effect :highlight, @div_id
def enum_rjs_test
render :update do |page|
page.select('.product').each do |value|
page.rjs_helper_method_from_module
page.rjs_helper_method(value)
page.sortable(value, :url => { :action => "order" })
page.draggable(value)
end
end
end
end
def update_page_with_view_method
render :update do |page|
page.replace_html 'person', pluralize(2, 'person')
def render_explicit_html_template
end
end
def partial_as_rjs
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
def respond_to_partial_as_rjs
respond_to do |format|
format.js do
def render_custom_code_rjs
render :update, :status => 404 do |page|
page.replace :foo, :partial => 'partial'
end
end
def render_implicit_html_template
end
def render_js_with_explicit_template
@project_id = 4
render :template => 'test/delete_with_js'
end
def render_js_with_explicit_action_template
@project_id = 4
render :action => 'delete_with_js'
end
def delete_with_js
@project_id = 4
end
def update_page
render :update do |page|
page.replace_html 'balance', '$37,000,000.00'
page.visual_effect :highlight, 'balance'
end
end
def update_page_with_instance_variables
@money = '$37,000,000.00'
@div_id = 'balance'
render :update do |page|
page.replace_html @div_id, @money
page.visual_effect :highlight, @div_id
end
end
def update_page_with_view_method
render :update do |page|
page.replace_html 'person', pluralize(2, 'person')
end
end
def partial_as_rjs
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
def respond_to_partial_as_rjs
respond_to do |format|
format.js do
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
end
end
def render_alternate_default
# For this test, the method "default_render" is overridden:
@alternate_default_render = lambda do
render :update do |page|
page.replace :foo, :partial => 'partial'
end
end
end
end
def render_alternate_default
# For this test, the method "default_render" is overridden:
@alternate_default_render = lambda do
render :update do |page|
page.replace :foo, :partial => 'partial'
private
def default_render
if @alternate_default_render
@alternate_default_render.call
else
super
end
end
def determine_layout
case action_name
when "hello_world", "layout_test", "rendering_without_layout",
"rendering_nothing_on_layout", "render_text_hello_world",
"render_text_hello_world_with_layout",
"hello_world_with_layout_false",
"partial_only", "partial_only_with_layout",
"accessing_params_in_template",
"accessing_params_in_template_with_layout",
"render_with_explicit_template",
"render_with_explicit_string_template",
"update_page", "update_page_with_instance_variables"
"layouts/standard"
when "action_talk_to_layout", "layout_overriding_layout"
"layouts/talk_from_action"
when "render_implicit_html_template_from_xhr_request"
(request.xhr? ? 'layouts/xhr' : 'layouts/standard')
end
end
end
end
private
def default_render
if @alternate_default_render
@alternate_default_render.call
else
super
end
end
def determine_layout
case action_name
when "hello_world", "layout_test", "rendering_without_layout",
"rendering_nothing_on_layout", "render_text_hello_world",
"render_text_hello_world_with_layout",
"hello_world_with_layout_false",
"partial_only", "partial_only_with_layout",
"accessing_params_in_template",
"accessing_params_in_template_with_layout",
"render_with_explicit_template",
"render_with_explicit_string_template",
"update_page", "update_page_with_instance_variables"
"layouts/standard"
when "action_talk_to_layout", "layout_overriding_layout"
"layouts/talk_from_action"
when "render_implicit_html_template_from_xhr_request"
(request.xhr? ? 'layouts/xhr' : 'layouts/standard')
end
end
end
class RenderTest < ActionController::TestCase
tests TestController
def setup
@@ -144,8 +149,8 @@ class RenderTest < ActionController::TestCase
@controller.logger = Logger.new(nil)
@request.host = "www.nextangle.com"
end
end
def test_enum_rjs_test
ActiveSupport::SecureRandom.stubs(:base64).returns("asdf")
get :enum_rjs_test
@@ -153,13 +158,13 @@ class RenderTest < ActionController::TestCase
$$(".product").each(function(value, index) {
new Effect.Highlight(element,{});
new Effect.Highlight(value,{});
Sortable.create(value, {onUpdate:function(){new Ajax.Request('/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value) + '&authenticity_token=' + encodeURIComponent('asdf')})}});
Sortable.create(value, {onUpdate:function(){new Ajax.Request('/render_other_test/test/order', {asynchronous:true, evalScripts:true, parameters:Sortable.serialize(value) + '&authenticity_token=' + encodeURIComponent('asdf')})}});
new Draggable(value, {});
});
}.gsub(/^ /, '').strip
assert_equal body, @response.body
end
def test_explicitly_rendering_an_html_template_with_implicit_html_template_renders_should_be_possible_from_an_rjs_template
[:js, "js"].each do |format|
assert_nothing_raised do
@@ -167,14 +172,14 @@ class RenderTest < ActionController::TestCase
assert_equal %(document.write("Hello world\\n");), @response.body
end
end
end
end
def test_render_custom_code_rjs
get :render_custom_code_rjs
assert_response 404
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_render_in_an_rjs_template_should_pick_html_templates_when_available
[:js, "js"].each do |format|
assert_nothing_raised do
@@ -183,7 +188,7 @@ class RenderTest < ActionController::TestCase
end
end
end
def test_render_rjs_template_explicitly
get :render_js_with_explicit_template
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
@@ -193,12 +198,12 @@ class RenderTest < ActionController::TestCase
get :render_js_with_explicit_action_template
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_render_rjs_with_default
get :delete_with_js
assert_equal %!Element.remove("person");\nnew Effect.Highlight(\"project-4\",{});!, @response.body
end
def test_update_page
get :update_page
assert_template nil
@@ -219,8 +224,8 @@ class RenderTest < ActionController::TestCase
assert_template nil
assert_equal 'text/javascript; charset=utf-8', @response.headers["Content-Type"]
assert_match /2 people/, @response.body
end
end
def test_should_render_html_formatted_partial_with_rjs
xhr :get, :partial_as_rjs
assert_equal %(Element.replace("foo", "partial html");), @response.body
@@ -230,9 +235,9 @@ class RenderTest < ActionController::TestCase
xhr :get, :respond_to_partial_as_rjs
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
def test_should_render_with_alternate_default_render
xhr :get, :render_alternate_default
assert_equal %(Element.replace("foo", "partial html");), @response.body
end
end
end
end

View File

@@ -2,37 +2,41 @@ require 'abstract_unit'
require 'controller/fake_models'
require 'pathname'
class TestController < ActionController::Base
protect_from_forgery
class RenderXmlTest < ActionController::TestCase
class TestController < ActionController::Base
protect_from_forgery
def render_with_location
render :xml => "<hello/>", :location => "http://example.com", :status => 201
def self.controller_path
'test'
end
def render_with_location
render :xml => "<hello/>", :location => "http://example.com", :status => 201
end
def render_with_object_location
customer = Customer.new("Some guy", 1)
render :xml => "<customer/>", :location => customer, :status => :created
end
def render_with_to_xml
to_xmlable = Class.new do
def to_xml
"<i-am-xml/>"
end
end.new
render :xml => to_xmlable
end
def formatted_xml_erb
end
def render_xml_with_custom_content_type
render :xml => "<blah/>", :content_type => "application/atomsvc+xml"
end
end
def render_with_object_location
customer = Customer.new("Some guy", 1)
render :xml => "<customer/>", :location => customer, :status => :created
end
def render_with_to_xml
to_xmlable = Class.new do
def to_xml
"<i-am-xml/>"
end
end.new
render :xml => to_xmlable
end
def formatted_xml_erb
end
def render_xml_with_custom_content_type
render :xml => "<blah/>", :content_type => "application/atomsvc+xml"
end
end
class RenderTest < ActionController::TestCase
tests TestController
def setup
@@ -42,8 +46,8 @@ class RenderTest < ActionController::TestCase
@controller.logger = Logger.new(nil)
@request.host = "www.nextangle.com"
end
end
def test_rendering_with_location_should_set_header
get :render_with_location
assert_equal "http://example.com", @response.headers["Location"]
@@ -53,7 +57,7 @@ class RenderTest < ActionController::TestCase
get :render_with_to_xml
assert_equal "<i-am-xml/>", @response.body
end
def test_rendering_with_object_location_should_set_header_with_url_for
with_routing do |set|
set.draw do |map|
@@ -65,19 +69,19 @@ class RenderTest < ActionController::TestCase
assert_equal "http://www.nextangle.com/customers/1", @response.headers["Location"]
end
end
def test_should_render_formatted_xml_erb_template
get :formatted_xml_erb, :format => :xml
assert_equal '<test>passed formatted xml erb</test>', @response.body
end
def test_should_render_xml_but_keep_custom_content_type
get :render_xml_with_custom_content_type
assert_equal "application/atomsvc+xml", @response.content_type
end
def test_should_use_implicit_content_type
get :implicit_content_type, :format => 'atom'
assert_equal Mime::ATOM, @response.content_type
end
end
end

View File

@@ -227,12 +227,6 @@ class ControllerInheritanceRescueControllerTest < ActionController::TestCase
end
end
class ApplicationController < ActionController::Base
rescue_from ActionController::RoutingError do
render :text => 'no way'
end
end
class RescueControllerTest < ActionController::TestCase
def test_rescue_handler
get :not_authorized
@@ -332,23 +326,20 @@ class RescueTest < ActionController::IntegrationTest
end
test 'rescue routing exceptions' do
assert_equal 1, ApplicationController.rescue_handlers.length
begin
with_test_routing do
get '/no_way'
assert_equal 'no way', response.body
end
ensure
ActionController::Base.rescue_handlers.clear
app = ActionDispatch::Rescue.new(ActionController::Routing::Routes) do
rescue_from ActionController::RoutingError, lambda { |env| [200, {"Content-Type" => "text/html"}, "Gotcha!"] }
end
@integration_session = open_session(app)
get '/b00m'
assert_equal "Gotcha!", response.body
end
test 'unrescued exception' do
with_test_routing do
get '/b00m'
assert_match(/Action Controller: Exception caught/, response.body)
end
app = ActionDispatch::Rescue.new(ActionController::Routing::Routes)
@integration_session = open_session(app)
assert_raise(ActionController::RoutingError) { get '/b00m' }
end
private
@@ -359,6 +350,7 @@ class RescueTest < ActionController::IntegrationTest
map.connect 'invalid', :controller => "rescue_test/test", :action => 'invalid'
map.connect 'b00m', :controller => "rescue_test/test", :action => 'b00m'
end
reset!
yield
end
end

View File

@@ -135,7 +135,7 @@ class ResourcesTest < ActionController::TestCase
def test_with_custom_conditions
with_restful_routing :messages, :conditions => { :subdomain => 'app' } do
assert_equal 'app', ActionController::Routing::Routes.named_routes.routes[:messages].conditions[:subdomain]
assert ActionController::Routing::Routes.recognize_path("/messages", :method => :get, :subdomain => 'app')
end
end
@@ -1130,7 +1130,8 @@ class ResourcesTest < ActionController::TestCase
map.resource :product
end
assert_equal :get, set.named_routes.routes[:product].conditions[:method]
assert_routing '/product', :controller => 'products', :action => 'show'
assert set.recognize_path("/product", :method => :get)
end
end

View File

@@ -232,14 +232,18 @@ class LegacyRouteSetTests < Test::Unit::TestCase
end
def test_basic_named_route
rs.add_named_route :home, '', :controller => 'content', :action => 'list'
rs.draw do |map|
map.home '', :controller => 'content', :action => 'list'
end
x = setup_for_named_route
assert_equal("http://test.host/",
x.send(:home_url))
end
def test_basic_named_route_with_relative_url_root
rs.add_named_route :home, '', :controller => 'content', :action => 'list'
rs.draw do |map|
map.home '', :controller => 'content', :action => 'list'
end
x = setup_for_named_route
ActionController::Base.relative_url_root = "/foo"
assert_equal("http://test.host/foo/",
@@ -249,14 +253,18 @@ class LegacyRouteSetTests < Test::Unit::TestCase
end
def test_named_route_with_option
rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page'
rs.draw do |map|
map.page 'page/:title', :controller => 'content', :action => 'show_page'
end
x = setup_for_named_route
assert_equal("http://test.host/page/new%20stuff",
x.send(:page_url, :title => 'new stuff'))
end
def test_named_route_with_default
rs.add_named_route :page, 'page/:title', :controller => 'content', :action => 'show_page', :title => 'AboutPage'
rs.draw do |map|
map.page 'page/:title', :controller => 'content', :action => 'show_page', :title => 'AboutPage'
end
x = setup_for_named_route
assert_equal("http://test.host/page/AboutRails",
x.send(:page_url, :title => "AboutRails"))
@@ -264,36 +272,46 @@ class LegacyRouteSetTests < Test::Unit::TestCase
end
def test_named_route_with_name_prefix
rs.add_named_route :page, 'page', :controller => 'content', :action => 'show_page', :name_prefix => 'my_'
rs.draw do |map|
map.page 'page', :controller => 'content', :action => 'show_page', :name_prefix => 'my_'
end
x = setup_for_named_route
assert_equal("http://test.host/page",
x.send(:my_page_url))
end
def test_named_route_with_path_prefix
rs.add_named_route :page, 'page', :controller => 'content', :action => 'show_page', :path_prefix => 'my'
rs.draw do |map|
map.page 'page', :controller => 'content', :action => 'show_page', :path_prefix => 'my'
end
x = setup_for_named_route
assert_equal("http://test.host/my/page",
x.send(:page_url))
end
def test_named_route_with_blank_path_prefix
rs.add_named_route :page, 'page', :controller => 'content', :action => 'show_page', :path_prefix => ''
rs.draw do |map|
map.page 'page', :controller => 'content', :action => 'show_page', :path_prefix => ''
end
x = setup_for_named_route
assert_equal("http://test.host/page",
x.send(:page_url))
end
def test_named_route_with_nested_controller
rs.add_named_route :users, 'admin/user', :controller => 'admin/user', :action => 'index'
rs.draw do |map|
map.users 'admin/user', :controller => 'admin/user', :action => 'index'
end
x = setup_for_named_route
assert_equal("http://test.host/admin/user",
x.send(:users_url))
end
def test_optimised_named_route_call_never_uses_url_for
rs.add_named_route :users, 'admin/user', :controller => '/admin/user', :action => 'index'
rs.add_named_route :user, 'admin/user/:id', :controller=>'/admin/user', :action=>'show'
rs.draw do |map|
map.users 'admin/user', :controller => '/admin/user', :action => 'index'
map.user 'admin/user/:id', :controller=>'/admin/user', :action=>'show'
end
x = setup_for_named_route
x.expects(:url_for).never
x.send(:users_url)
@@ -303,7 +321,9 @@ class LegacyRouteSetTests < Test::Unit::TestCase
end
def test_optimised_named_route_with_host
rs.add_named_route :pages, 'pages', :controller => 'content', :action => 'show_page', :host => 'foo.com'
rs.draw do |map|
map.pages 'pages', :controller => 'content', :action => 'show_page', :host => 'foo.com'
end
x = setup_for_named_route
x.expects(:url_for).with(:host => 'foo.com', :only_path => false, :controller => 'content', :action => 'show_page', :use_route => :pages).once
x.send(:pages_url)
@@ -378,7 +398,9 @@ class LegacyRouteSetTests < Test::Unit::TestCase
end
def test_paths_slashes_unescaped_with_ordered_parameters
rs.add_named_route :path, '/file/*path', :controller => 'content'
rs.draw do |map|
map.path '/file/*path', :controller => 'content'
end
# No / to %2F in URI, only for query params.
x = setup_for_named_route
@@ -1781,23 +1803,23 @@ class RouteSetTest < ActiveSupport::TestCase
end
def test_default_route_recognition
expected = {:controller => 'accounts', :action => 'show', :id => '10'}
assert_equal expected, default_route_set.recognize_path('/accounts/show/10')
assert_equal expected, default_route_set.recognize_path('/accounts/show/10/')
expected = {:controller => 'pages', :action => 'show', :id => '10'}
assert_equal expected, default_route_set.recognize_path('/pages/show/10')
assert_equal expected, default_route_set.recognize_path('/pages/show/10/')
expected[:id] = 'jamis'
assert_equal expected, default_route_set.recognize_path('/accounts/show/jamis/')
assert_equal expected, default_route_set.recognize_path('/pages/show/jamis/')
expected.delete :id
assert_equal expected, default_route_set.recognize_path('/accounts/show')
assert_equal expected, default_route_set.recognize_path('/accounts/show/')
assert_equal expected, default_route_set.recognize_path('/pages/show')
assert_equal expected, default_route_set.recognize_path('/pages/show/')
expected[:action] = 'index'
assert_equal expected, default_route_set.recognize_path('/accounts/')
assert_equal expected, default_route_set.recognize_path('/accounts')
assert_equal expected, default_route_set.recognize_path('/pages/')
assert_equal expected, default_route_set.recognize_path('/pages')
assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/') }
assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/accounts/how/goood/it/is/to/be/free') }
assert_raise(ActionController::RoutingError) { default_route_set.recognize_path('/pages/how/goood/it/is/to/be/free') }
end
def test_default_route_should_omit_default_action
@@ -1813,15 +1835,15 @@ class RouteSetTest < ActiveSupport::TestCase
end
def test_default_route_should_uri_escape_pluses
expected = { :controller => 'accounts', :action => 'show', :id => 'hello world' }
assert_equal expected, default_route_set.recognize_path('/accounts/show/hello world')
assert_equal expected, default_route_set.recognize_path('/accounts/show/hello%20world')
assert_equal '/accounts/show/hello%20world', default_route_set.generate(expected, expected)
expected = { :controller => 'pages', :action => 'show', :id => 'hello world' }
assert_equal expected, default_route_set.recognize_path('/pages/show/hello world')
assert_equal expected, default_route_set.recognize_path('/pages/show/hello%20world')
assert_equal '/pages/show/hello%20world', default_route_set.generate(expected, expected)
expected[:id] = 'hello+world'
assert_equal expected, default_route_set.recognize_path('/accounts/show/hello+world')
assert_equal expected, default_route_set.recognize_path('/accounts/show/hello%2Bworld')
assert_equal '/accounts/show/hello+world', default_route_set.generate(expected, expected)
assert_equal expected, default_route_set.recognize_path('/pages/show/hello+world')
assert_equal expected, default_route_set.recognize_path('/pages/show/hello%2Bworld')
assert_equal '/pages/show/hello+world', default_route_set.generate(expected, expected)
end
def test_parameter_shell

View File

@@ -1,4 +1,5 @@
require 'abstract_unit'
require 'controller/fake_controllers'
ActionController::UrlRewriter

View File

@@ -43,7 +43,7 @@ class ViewLoadPathsTest < ActionController::TestCase
end
def expand(array)
array.map {|x| File.expand_path(x)}
array.map {|x| File.expand_path(x.to_s)}
end
def assert_paths(*paths)

View File

@@ -30,7 +30,7 @@ class CookieStoreTest < ActionController::IntegrationTest
end
def get_session_id
render :text => "foo: #{session[:foo].inspect}; id: #{request.session_options[:id]}"
render :text => "id: #{request.session_options[:id]}"
end
def call_reset_session
@@ -119,7 +119,7 @@ class CookieStoreTest < ActionController::IntegrationTest
get '/get_session_id'
assert_response :success
assert_equal "foo: \"bar\"; id: #{session_id}", response.body
assert_equal "id: #{session_id}", response.body
end
end

View File

@@ -70,8 +70,7 @@ class ShowExceptionsTest < ActionController::IntegrationTest
test "localize public rescue message" do
# Change locale
old_locale = I18n.locale
I18n.locale = :da
old_locale, I18n.locale = I18n.locale, :da
begin
@integration_session = open_session(ProductionApp)

View File

@@ -5,7 +5,7 @@ class TestRequestTest < ActiveSupport::TestCase
env = ActionDispatch::TestRequest.new.env
assert_equal "GET", env.delete("REQUEST_METHOD")
assert_equal "off", env.delete("HTTPS")
assert_equal nil, env.delete("HTTPS")
assert_equal "http", env.delete("rack.url_scheme")
assert_equal "example.org", env.delete("SERVER_NAME")
assert_equal "80", env.delete("SERVER_PORT")
@@ -18,7 +18,7 @@ class TestRequestTest < ActiveSupport::TestCase
assert_equal "0.0.0.0", env.delete("REMOTE_ADDR")
assert_equal "Rails Testing", env.delete("HTTP_USER_AGENT")
assert_equal [1, 0], env.delete("rack.version")
assert_equal [0, 1], env.delete("rack.version")
assert_equal "", env.delete("rack.input").string
assert_kind_of StringIO, env.delete("rack.errors")
assert_equal true, env.delete("rack.multithread")

View File

@@ -9,7 +9,15 @@ module Admin
class UserController < ActionController::Base; end
class NewsFeedController < ActionController::Base; end
end
class ElsewhereController < ActionController::Base; end
class AddressesController < ActionController::Base; end
class SessionsController < ActionController::Base; end
class FooController < ActionController::Base; end
class CController < ActionController::Base; end
class HiController < ActionController::Base; end
class BraveController < ActionController::Base; end
class ImageController < ActionController::Base; end
class WeblogController < ActionController::Base; end
# For speed test
class SpeedController < ActionController::Base; end
@@ -24,7 +32,6 @@ class UsersController < SpeedController; end
class SettingsController < SpeedController; end
class ChannelsController < SpeedController; end
class ChannelVideosController < SpeedController; end
class SessionsController < SpeedController; end
class LostPasswordsController < SpeedController; end
class PagesController < SpeedController; end

View File

@@ -1,67 +1,24 @@
module ActionView #:nodoc:
class FixtureResolver < Resolver
class FixtureResolver < PathResolver
def initialize(hash = {}, options = {})
super(options)
@hash = hash
end
def find_templates(name, details, prefix, partial)
if regexp = details_to_regexp(name, details, prefix, partial)
cached(regexp) do
templates = []
@hash.select { |k,v| k =~ regexp }.each do |path, source|
templates << Template.new(source, path, *path_to_details(path))
end
templates.sort_by {|t| -t.details.values.compact.size }
end
end
end
private
def formats_regexp
@formats_regexp ||= begin
formats = Mime::SET.symbols
'(?:' + formats.map { |l| "\\.#{Regexp.escape(l.to_s)}" }.join('|') + ')?'
end
end
def handler_regexp
e = TemplateHandlers.extensions.map{|h| "\\.#{Regexp.escape(h.to_s)}"}.join("|")
"(?:#{e})"
end
def details_to_regexp(name, details, prefix, partial)
path = ""
path << "#{prefix}/" unless prefix.empty?
path << (partial ? "_#{name}" : name)
extensions = ""
[:locales, :formats].each do |k|
extensions << if exts = details[k]
'(?:' + exts.map {|e| "\\.#{Regexp.escape(e.to_s)}"}.join('|') + ')?'
else
k == :formats ? formats_regexp : ''
end
def query(path, exts)
query = Regexp.escape(path)
exts.each do |ext|
query << '(?:' << ext.map {|e| e && Regexp.escape(".#{e}") }.join('|') << ')'
end
%r'^#{Regexp.escape(path)}#{extensions}#{handler_regexp}$'
end
# TODO: fix me
# :api: plugin
def path_to_details(path)
# [:erb, :format => :html, :locale => :en, :partial => true/false]
if m = path.match(%r'(_)?[\w-]+((?:\.[\w-]+)*)\.(\w+)$')
partial = m[1] == '_'
details = (m[2]||"").split('.').reject { |e| e.empty? }
handler = Template.handler_class_for_extension(m[3])
format = Mime[details.last] && details.pop.to_sym
locale = details.last && details.pop.to_sym
return handler, :format => format, :locale => locale, :partial => partial
templates = []
@hash.select { |k,v| k =~ /^#{query}$/ }.each do |path, source|
templates << Template.new(source, path, *path_to_details(path))
end
templates.sort_by {|t| -t.details.values.compact.size }
end
end
end

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
# Tests the controller dispatching happy path
module Dispatching
@@ -65,4 +65,4 @@ module Dispatching
assert_equal 'contained_empty', Submodule::ContainedEmptyController.controller_name
end
end
end
end

View File

@@ -0,0 +1,18 @@
require 'abstract_unit'
module ContentNegotiation
# This has no layout and it works
class BasicController < ActionController::Base
self.view_paths = [ActionView::FixtureResolver.new(
"content_negotiation/basic/hello.html.erb" => "Hello world <%= request.formats %>!"
)]
end
class TestContentNegotiation < SimpleRouteCase
test "A */* Accept header will return HTML" do
get "/content_negotiation/basic/hello", {}, "HTTP_ACCEPT" => "*/*"
assert_body "Hello world */*!"
end
end
end

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module ContentType
class BaseController < ActionController::Base

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module Etags
class BasicController < ActionController::Base
@@ -43,4 +43,4 @@ module Etags
%("#{Digest::MD5.hexdigest(text)}")
end
end
end
end

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module MetalTest
class MetalMiddleware < ActionController::Middleware
@@ -41,4 +41,3 @@ module MetalTest
end
end
end

View File

@@ -0,0 +1,77 @@
require 'abstract_unit'
module MiddlewareTest
class MyMiddleware
def initialize(app)
@app = app
end
def call(env)
result = @app.call(env)
result[1]["Middleware-Test"] = "Success"
result[1]["Middleware-Order"] = "First"
result
end
end
class ExclaimerMiddleware
def initialize(app)
@app = app
end
def call(env)
result = @app.call(env)
result[1]["Middleware-Order"] << "!"
result
end
end
class MyController < ActionController::Metal
use MyMiddleware
middleware.insert_before MyMiddleware, ExclaimerMiddleware
def index
self.response_body = "Hello World"
end
end
class InheritedController < MyController
end
module MiddlewareTests
extend ActiveSupport::Testing::Declarative
test "middleware that is 'use'd is called as part of the Rack application" do
result = @app.call(env_for("/"))
assert_equal "Hello World", result[2]
assert_equal "Success", result[1]["Middleware-Test"]
end
test "the middleware stack is exposed as 'middleware' in the controller" do
result = @app.call(env_for("/"))
assert_equal "First!", result[1]["Middleware-Order"]
end
end
class TestMiddleware < ActiveSupport::TestCase
include MiddlewareTests
def setup
@app = MyController.action(:index)
end
def env_for(url)
Rack::MockRequest.env_for(url)
end
end
class TestInheritedMiddleware < TestMiddleware
def setup
@app = InheritedController.action(:index)
end
test "middleware inherits" do
end
end
end

View File

@@ -1 +0,0 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module RenderAction
# This has no layout and it works
@@ -317,4 +317,4 @@ module RenderActionWithBothLayouts
assert_status 200
end
end
end
end

View File

@@ -1,9 +1,9 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module RenderFile
class BasicController < ActionController::Base
self.view_paths = "."
self.view_paths = File.dirname(__FILE__)
def index
render :file => File.join(File.dirname(__FILE__), *%w[.. fixtures test hello_world])
@@ -107,4 +107,4 @@ module RenderFile
end
end
end
end

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module RenderImplicitAction
class SimpleController < ::ApplicationController
@@ -25,4 +25,4 @@ module RenderImplicitAction
assert_status 200
end
end
end
end

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module ControllerLayouts
class ImplicitController < ::ApplicationController
@@ -98,4 +98,4 @@ module ControllerLayouts
end
end
end
end
end

View File

@@ -1,4 +1,4 @@
require File.join(File.expand_path(File.dirname(__FILE__)), "test_helper")
require 'abstract_unit'
module RenderPartial
@@ -24,4 +24,4 @@ module RenderPartial
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More