diff options
Diffstat (limited to 'actionpack')
62 files changed, 761 insertions, 503 deletions
diff --git a/actionpack/CHANGELOG b/actionpack/CHANGELOG index e3ad19558e..e758983d7a 100644 --- a/actionpack/CHANGELOG +++ b/actionpack/CHANGELOG @@ -1,5 +1,8 @@ *Edge* +* Ruby 1.9: ERB template encoding using a magic comment at the top of the file. [Jeremy Kemper] + <%# encoding: utf-8 %> + * Change integration test helpers to accept Rack environment instead of just HTTP Headers [Pratik Naik] Before : get '/path', {}, 'Accept' => 'text/javascript' diff --git a/actionpack/Rakefile b/actionpack/Rakefile index 9ce897aae8..5f5614e58f 100644 --- a/actionpack/Rakefile +++ b/actionpack/Rakefile @@ -59,24 +59,21 @@ 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" - # layout - # Dir.glob( "test/{dispatch,template}/**/*_test.rb" ).sort + + t.verbose = true # ==== Not ported # * filters - # * integration - # * test - # * view_paths - t.test_files = %w( + + 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 layout logging mime_responds + 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 url_rewriter verification webservice + resources routing selector send_file test url_rewriter + verification view_paths webservice ).map { |name| "test/controller/#{name}_test.rb" } - t.verbose = true end # Genereate the RDoc documentation diff --git a/actionpack/examples/minimal.rb b/actionpack/examples/minimal.rb index e2d112648c..9eb92cd8e7 100644 --- a/actionpack/examples/minimal.rb +++ b/actionpack/examples/minimal.rb @@ -24,10 +24,12 @@ class Runner out.puts '---' end - def self.run(app, n) + def self.run(app, n, label = nil) + puts '=' * label.size, label, '=' * label.size if label env = { 'n' => n, 'rack.input' => StringIO.new(''), 'rack.errors' => $stdout } t = Benchmark.realtime { new(app).call(env) } - puts "%d ms / %d req = %d usec/req" % [10**3 * t, n, 10**6 * t / n] + puts "%d ms / %d req = %.1f usec/req" % [10**3 * t, n, 10**6 * t / n] + puts end end @@ -38,16 +40,19 @@ class BasePostController < ActionController::Base def index render :text => '' end - - Runner.run(action(:index), N) end +OK = [200, {}, []] +MetalPostController = lambda { OK } + if ActionController.const_defined?(:Http) class HttpPostController < ActionController::Http def index self.response_body = '' end - - Runner.run(action(:index), N) end end + +Runner.run(MetalPostController, N, 'metal') +Runner.run(HttpPostController.action(:index), N, 'http') if defined? HttpPostController +Runner.run(BasePostController.action(:index), N, 'base') diff --git a/actionpack/lib/action_controller/abstract.rb b/actionpack/lib/action_controller/abstract.rb index d6b7a44f5f..f46b91627f 100644 --- a/actionpack/lib/action_controller/abstract.rb +++ b/actionpack/lib/action_controller/abstract.rb @@ -11,4 +11,4 @@ module AbstractController autoload :Renderer, "action_controller/abstract/renderer" # === Exceptions autoload :ActionNotFound, "action_controller/abstract/exceptions" -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/base.rb b/actionpack/lib/action_controller/abstract/base.rb index 0e4803388a..87083a4d79 100644 --- a/actionpack/lib/action_controller/abstract/base.rb +++ b/actionpack/lib/action_controller/abstract/base.rb @@ -2,28 +2,27 @@ require 'active_support/core_ext/module/attr_internal' module AbstractController class Error < StandardError; end - + class DoubleRenderError < Error DEFAULT_MESSAGE = "Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like \"redirect_to(...) and return\"." def initialize(message = nil) super(message || DEFAULT_MESSAGE) end - end - + end + class Base - attr_internal :response_body attr_internal :response_obj attr_internal :action_name class << self - attr_reader :abstract - + attr_reader :abstract + def abstract! @abstract = true end - + alias_method :abstract?, :abstract def inherited(klass) @@ -34,13 +33,13 @@ module AbstractController def subclasses @subclasses ||= [] end - + def internal_methods controller = self controller = controller.superclass until controller.abstract? controller.public_instance_methods(true) end - + def process(action) new.process(action.to_s) end @@ -48,7 +47,7 @@ module AbstractController def hidden_actions [] end - + def action_methods @action_methods ||= # All public instance methods of this class, including ancestors @@ -61,13 +60,13 @@ module AbstractController hidden_actions end end - + abstract! - + def initialize self.response_obj = {} end - + def process(action) @_action_name = action_name = action.to_s @@ -78,26 +77,27 @@ module AbstractController process_action(action_name) self end - + private - def action_methods self.class.action_methods end - + def action_method?(action) action_methods.include?(action) end - + # It is possible for respond_to?(action_name) to be false and # respond_to?(:action_missing) to be false if respond_to_action? # is overridden in a subclass. For instance, ActionController::Base # overrides it to include the case where a template matching the # action_name is found. def process_action(method_name) - send(method_name) + send_action(method_name) end + alias send_action send + def _handle_action_missing action_missing(@_action_name) end @@ -112,4 +112,4 @@ module AbstractController end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/benchmarker.rb b/actionpack/lib/action_controller/abstract/benchmarker.rb index 9f5889c704..07294cede3 100644 --- a/actionpack/lib/action_controller/abstract/benchmarker.rb +++ b/actionpack/lib/action_controller/abstract/benchmarker.rb @@ -1,9 +1,9 @@ module AbstractController module Benchmarker - extend ActiveSupport::DependencyModule - - depends_on Logger - + extend ActiveSupport::Concern + + include Logger + module ClassMethods def benchmark(title, log_level = ::Logger::DEBUG, use_silence = true) if logger && logger.level >= log_level @@ -25,4 +25,4 @@ module AbstractController end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/callbacks.rb b/actionpack/lib/action_controller/abstract/callbacks.rb index e4f9dd3112..affe053bac 100644 --- a/actionpack/lib/action_controller/abstract/callbacks.rb +++ b/actionpack/lib/action_controller/abstract/callbacks.rb @@ -1,8 +1,8 @@ module AbstractController module Callbacks - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern - depends_on ActiveSupport::NewCallbacks + include ActiveSupport::NewCallbacks included do define_callbacks :process_action, "response_body" @@ -13,7 +13,7 @@ module AbstractController super end end - + module ClassMethods def _normalize_callback_options(options) if only = options[:only] @@ -21,11 +21,17 @@ module AbstractController options[:per_key] = {:if => only} end if except = options[:except] - except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ") + except = Array(except).map {|e| "action_name == '#{e}'"}.join(" || ") options[:per_key] = {:unless => except} end end - + + def skip_filter(*names, &blk) + skip_before_filter(*names, &blk) + skip_after_filter(*names, &blk) + skip_around_filter(*names, &blk) + end + [:before, :after, :around].each do |filter| class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def #{filter}_filter(*names, &blk) @@ -37,6 +43,15 @@ module AbstractController end end + def prepend_#{filter}_filter(*names, &blk) + options = names.last.is_a?(Hash) ? names.pop : {} + _normalize_callback_options(options) + names.push(blk) if block_given? + names.each do |name| + process_action_callback(:#{filter}, name, options.merge(:prepend => true)) + end + end + def skip_#{filter}_filter(*names, &blk) options = names.last.is_a?(Hash) ? names.pop : {} _normalize_callback_options(options) @@ -51,4 +66,4 @@ module AbstractController end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/exceptions.rb b/actionpack/lib/action_controller/abstract/exceptions.rb index ec4680629b..2f6c55f068 100644 --- a/actionpack/lib/action_controller/abstract/exceptions.rb +++ b/actionpack/lib/action_controller/abstract/exceptions.rb @@ -1,3 +1,3 @@ module AbstractController - class ActionNotFound < StandardError ; end -end
\ No newline at end of file + class ActionNotFound < StandardError; end +end diff --git a/actionpack/lib/action_controller/abstract/helpers.rb b/actionpack/lib/action_controller/abstract/helpers.rb index 41decfd0c7..0a2776de9c 100644 --- a/actionpack/lib/action_controller/abstract/helpers.rb +++ b/actionpack/lib/action_controller/abstract/helpers.rb @@ -1,8 +1,8 @@ module AbstractController module Helpers - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern - depends_on Renderer + include Renderer included do extlib_inheritable_accessor :master_helper_module @@ -16,12 +16,12 @@ module AbstractController av end end - + module ClassMethods def inherited(klass) klass.master_helper_module = Module.new klass.master_helper_module.__send__ :include, master_helper_module - + super end @@ -57,7 +57,7 @@ module AbstractController ruby_eval end end - + def helper(*args, &block) args.flatten.each do |arg| case arg @@ -68,6 +68,5 @@ module AbstractController master_helper_module.module_eval(&block) if block_given? end end - end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/layouts.rb b/actionpack/lib/action_controller/abstract/layouts.rb index 3d6810bda9..273063f74b 100644 --- a/actionpack/lib/action_controller/abstract/layouts.rb +++ b/actionpack/lib/action_controller/abstract/layouts.rb @@ -1,8 +1,8 @@ module AbstractController module Layouts - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern - depends_on Renderer + include Renderer included do extlib_inheritable_accessor :_layout_conditions @@ -17,18 +17,18 @@ module AbstractController conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} } self._layout_conditions = conditions - + @_layout = layout || false # Converts nil to false _write_layout_method end - + def _implied_layout_name name.underscore end - + # Takes the specified layout and creates a _layout method to be called # by _default_layout - # + # # If the specified layout is a: # String:: return the string # Symbol:: call the method specified by the symbol @@ -57,11 +57,12 @@ module AbstractController end end end - + private - - def _layout(details) end # This will be overwritten - + # This will be overwritten + def _layout(details) + end + # :api: plugin # ==== # Override this to mutate the inbound layout name @@ -69,7 +70,7 @@ module AbstractController unless [String, FalseClass, NilClass].include?(name.class) raise ArgumentError, "String, false, or nil expected; you passed #{name.inspect}" end - + name && view_paths.find_by_parts(name, details, _layout_prefix(name)) end @@ -77,7 +78,7 @@ module AbstractController def _layout_prefix(name) "layouts" end - + def _default_layout(require_layout = false, details = {:formats => formats}) if require_layout && _action_has_layout? && !_layout(details) raise ArgumentError, @@ -87,7 +88,7 @@ module AbstractController begin _layout_for_name(_layout(details), details) if _action_has_layout? rescue NameError => e - raise NoMethodError, + raise NoMethodError, "You specified #{@_layout.inspect} as the layout, but no such method was found" end end @@ -103,4 +104,4 @@ module AbstractController end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/abstract/logger.rb b/actionpack/lib/action_controller/abstract/logger.rb index 980ede0bed..d6fa843485 100644 --- a/actionpack/lib/action_controller/abstract/logger.rb +++ b/actionpack/lib/action_controller/abstract/logger.rb @@ -3,13 +3,13 @@ require 'active_support/core_ext/logger' module AbstractController module Logger - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern class DelayedLog def initialize(&blk) @blk = blk end - + def to_s @blk.call end @@ -19,10 +19,10 @@ module AbstractController included do cattr_accessor :logger end - + def process(action) ret = super - + if logger log = DelayedLog.new do "\n\nProcessing #{self.class.name}\##{action_name} " \ @@ -32,14 +32,14 @@ module AbstractController logger.info(log) end - + ret end - + 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 end end diff --git a/actionpack/lib/action_controller/abstract/renderer.rb b/actionpack/lib/action_controller/abstract/renderer.rb index d7c68549e1..dd58c7cb64 100644 --- a/actionpack/lib/action_controller/abstract/renderer.rb +++ b/actionpack/lib/action_controller/abstract/renderer.rb @@ -2,9 +2,9 @@ require "action_controller/abstract/logger" module AbstractController module Renderer - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern - depends_on AbstractController::Logger + include AbstractController::Logger included do attr_internal :formats @@ -15,22 +15,22 @@ module AbstractController end def _action_view - @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) + @_action_view ||= ActionView::Base.new(self.class.view_paths, {}, self) end - + def render(*args) if response_body raise AbstractController::DoubleRenderError, "OMG" end - + self.response_body = render_to_body(*args) end - + # Raw rendering of a template to a Rack-compatible body. # ==== # @option _prefix<String> The template's path prefix # @option _layout<String> The relative path to the layout template to use - # + # # :api: plugin def render_to_body(options = {}) # TODO: Refactor so we can just use the normal template logic for this @@ -46,7 +46,7 @@ module AbstractController # ==== # @option _prefix<String> The template's path prefix # @option _layout<String> The relative path to the layout template to use - # + # # :api: plugin def render_to_string(options = {}) AbstractController::Renderer.body_to_s(render_to_body(options)) @@ -55,8 +55,10 @@ module AbstractController def _render_template(options) _action_view._render_template_from_controller(options[:_template], options[:_layout], options, options[:_partial]) end - - def view_paths() _view_paths end + + def view_paths() + _view_paths + end # Return a string representation of a Rack-compatible response body. def self.body_to_s(body) @@ -71,7 +73,6 @@ module AbstractController end private - def _determine_template(options) name = (options[:_template_name] || action_name).to_s @@ -81,15 +82,18 @@ module AbstractController end module ClassMethods - def append_view_path(path) self.view_paths << path end - + + def prepend_view_path(path) + self.view_paths.unshift(path) + end + def view_paths self._view_paths end - + def view_paths=(paths) self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths) diff --git a/actionpack/lib/action_controller/base/chained/filters.rb b/actionpack/lib/action_controller/base/chained/filters.rb index e121c0129d..f528dd0686 100644 --- a/actionpack/lib/action_controller/base/chained/filters.rb +++ b/actionpack/lib/action_controller/base/chained/filters.rb @@ -1,11 +1,6 @@ module ActionController #:nodoc: module Filters #:nodoc: - def self.included(base) - base.class_eval do - extend ClassMethods - include ActionController::Filters::InstanceMethods - end - end + extend ActiveSupport::Concern class FilterChain < ActiveSupport::Callbacks::CallbackChain #:nodoc: def append_filter_to_chain(filters, filter_type, &block) diff --git a/actionpack/lib/action_controller/base/chained/flash.rb b/actionpack/lib/action_controller/base/chained/flash.rb index 6bd482d85a..42c6e430ca 100644 --- a/actionpack/lib/action_controller/base/chained/flash.rb +++ b/actionpack/lib/action_controller/base/chained/flash.rb @@ -26,11 +26,11 @@ module ActionController #:nodoc: # # See docs on the FlashHash class for more details about the flash. module Flash - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base - depends_on Session if defined?(ActionController::Http) - + include Session if defined?(ActionController::Http) + included do # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) @@ -129,65 +129,68 @@ module ActionController #:nodoc: (@used.keys - keys).each{ |k| @used.delete(k) } end + def store(session, key = "flash") + return if self.empty? + session[key] = self + end + private # Used internally by the <tt>keep</tt> and <tt>discard</tt> methods # use() # marks the entire flash as used # use('msg') # marks the "msg" entry as used # use(nil, false) # marks the entire flash as unused (keeps it around for one more action) # use('msg', false) # marks the "msg" entry as unused (keeps it around for one more action) - def use(k=nil, v=true) - unless k.nil? - @used[k] = v - else - keys.each{ |key| use(key, v) } - end + # Returns the single value for the key you asked to be marked (un)used or the FlashHash itself + # if no key is passed. + def use(key = nil, used = true) + Array(key || keys).each { |k| @used[k] = used } + return key ? self[key] : self end end module InstanceMethodsForBase #:nodoc: protected + def perform_action_with_flash + perform_action_without_flash + if defined? @_flash + @_flash.store(session) + remove_instance_variable(:@_flash) + end + end - def perform_action_with_flash - perform_action_without_flash - remove_instance_variable(:@_flash) if defined?(@_flash) - end - - def reset_session_with_flash - reset_session_without_flash - remove_instance_variable(:@_flash) if defined?(@_flash) - end + def reset_session_with_flash + reset_session_without_flash + remove_instance_variable(:@_flash) if defined?(@_flash) + end end module InstanceMethodsForNewBase #:nodoc: protected + def process_action(method_name) + super + if defined? @_flash + @_flash.store(session) + remove_instance_variable(:@_flash) + end + end - def reset_session - super - remove_flash_instance_variable - end - - def process_action(method_name) - super - remove_flash_instance_variable - end - - def remove_flash_instance_variable - remove_instance_variable(:@_flash) if defined?(@_flash) - end + def reset_session + super + remove_instance_variable(:@_flash) if defined?(@_flash) + end end protected + # Access the contents of the flash. Use <tt>flash["notice"]</tt> to + # read a notice you put there or <tt>flash["notice"] = "hello"</tt> + # to put a new one. + def flash #:doc: + if !defined?(@_flash) + @_flash = session["flash"] || FlashHash.new + @_flash.sweep + end - # Access the contents of the flash. Use <tt>flash["notice"]</tt> to - # read a notice you put there or <tt>flash["notice"] = "hello"</tt> - # to put a new one. - def flash #:doc: - unless defined?(@_flash) - @_flash = session["flash"] ||= FlashHash.new - @_flash.sweep + @_flash end - - @_flash - end end end diff --git a/actionpack/lib/action_controller/base/cookies.rb b/actionpack/lib/action_controller/base/cookies.rb index ca380e98d0..d4806623c3 100644 --- a/actionpack/lib/action_controller/base/cookies.rb +++ b/actionpack/lib/action_controller/base/cookies.rb @@ -51,7 +51,7 @@ module ActionController #:nodoc: protected # Returns the cookie container, which operates as described above. def cookies - CookieJar.new(self) + @cookies ||= CookieJar.new(self) end end diff --git a/actionpack/lib/action_controller/base/filter_parameter_logging.rb b/actionpack/lib/action_controller/base/filter_parameter_logging.rb index f5a678ca03..8370ba6fc0 100644 --- a/actionpack/lib/action_controller/base/filter_parameter_logging.rb +++ b/actionpack/lib/action_controller/base/filter_parameter_logging.rb @@ -1,16 +1,14 @@ module ActionController module FilterParameterLogging - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) - depends_on AbstractController::Logger + include AbstractController::Logger end included do - if defined?(ActionController::Http) - include InstanceMethodsForNewBase - end + include InstanceMethodsForNewBase end module ClassMethods diff --git a/actionpack/lib/action_controller/base/helpers.rb b/actionpack/lib/action_controller/base/helpers.rb index 96fa7896a9..f74158bc13 100644 --- a/actionpack/lib/action_controller/base/helpers.rb +++ b/actionpack/lib/action_controller/base/helpers.rb @@ -3,7 +3,7 @@ require 'active_support/dependencies' # FIXME: helper { ... } is broken on Ruby 1.9 module ActionController #:nodoc: module Helpers #:nodoc: - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do # Initialize the base module to aggregate its helpers. diff --git a/actionpack/lib/action_controller/base/request_forgery_protection.rb b/actionpack/lib/action_controller/base/request_forgery_protection.rb index 0a0e20e1f1..a470c8eec1 100644 --- a/actionpack/lib/action_controller/base/request_forgery_protection.rb +++ b/actionpack/lib/action_controller/base/request_forgery_protection.rb @@ -3,11 +3,11 @@ module ActionController #:nodoc: end module RequestForgeryProtection - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) - depends_on AbstractController::Helpers, Session + include AbstractController::Helpers, Session end included do diff --git a/actionpack/lib/action_controller/base/streaming.rb b/actionpack/lib/action_controller/base/streaming.rb index 5872ba99a2..73d4bde6c1 100644 --- a/actionpack/lib/action_controller/base/streaming.rb +++ b/actionpack/lib/action_controller/base/streaming.rb @@ -2,11 +2,11 @@ module ActionController #:nodoc: # Methods for sending arbitrary data and for streaming files to the browser, # instead of rendering. module Streaming - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) - depends_on ActionController::Renderer + include ActionController::Renderer end DEFAULT_SEND_FILE_OPTIONS = { diff --git a/actionpack/lib/action_controller/base/verification.rb b/actionpack/lib/action_controller/base/verification.rb index 3fa5a105b1..d87b348ed4 100644 --- a/actionpack/lib/action_controller/base/verification.rb +++ b/actionpack/lib/action_controller/base/verification.rb @@ -1,10 +1,10 @@ module ActionController #:nodoc: module Verification #:nodoc: - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern # TODO : Remove the defined? check when new base is the main base if defined?(ActionController::Http) - depends_on AbstractController::Callbacks, Session, Flash, Renderer + include AbstractController::Callbacks, Session, Flash, Renderer end # This module provides a class-level method for specifying that certain diff --git a/actionpack/lib/action_controller/caching.rb b/actionpack/lib/action_controller/caching.rb index 2f2eec10f6..38cf1da6a8 100644 --- a/actionpack/lib/action_controller/caching.rb +++ b/actionpack/lib/action_controller/caching.rb @@ -24,7 +24,7 @@ module ActionController #:nodoc: # ActionController::Base.cache_store = :mem_cache_store, "localhost" # ActionController::Base.cache_store = MyOwnStore.new("parameter") module Caching - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern autoload :Actions, 'action_controller/caching/actions' autoload :Fragments, 'action_controller/caching/fragments' diff --git a/actionpack/lib/action_controller/caching/actions.rb b/actionpack/lib/action_controller/caching/actions.rb index 3646ff1af9..54148b55d8 100644 --- a/actionpack/lib/action_controller/caching/actions.rb +++ b/actionpack/lib/action_controller/caching/actions.rb @@ -93,7 +93,7 @@ module ActionController #:nodoc: # TODO: Remove once New Base is merged if defined?(ActionController::Http) - def around_process_action(controller) + def filter(controller) should_continue = before(controller) yield if should_continue after(controller) diff --git a/actionpack/lib/action_controller/new_base.rb b/actionpack/lib/action_controller/new_base.rb index 276be50614..df256985ac 100644 --- a/actionpack/lib/action_controller/new_base.rb +++ b/actionpack/lib/action_controller/new_base.rb @@ -4,6 +4,7 @@ module ActionController autoload :HideActions, "action_controller/new_base/hide_actions" autoload :Http, "action_controller/new_base/http" autoload :Layouts, "action_controller/new_base/layouts" + autoload :RackConvenience, "action_controller/new_base/rack_convenience" autoload :Rails2Compatibility, "action_controller/new_base/compatibility" autoload :Redirector, "action_controller/new_base/redirector" autoload :Renderer, "action_controller/new_base/renderer" @@ -40,5 +41,7 @@ module ActionController require 'action_controller/routing' end +autoload :HTML, 'action_controller/vendor/html-scanner' + require 'action_dispatch' require 'action_view' diff --git a/actionpack/lib/action_controller/new_base/base.rb b/actionpack/lib/action_controller/new_base/base.rb index ffe608ade4..d7b65d37fa 100644 --- a/actionpack/lib/action_controller/new_base/base.rb +++ b/actionpack/lib/action_controller/new_base/base.rb @@ -1,7 +1,7 @@ module ActionController class Base < Http abstract! - + include AbstractController::Benchmarker include AbstractController::Callbacks include AbstractController::Logger @@ -14,6 +14,7 @@ module ActionController include ActionController::Renderers::All include ActionController::Layouts include ActionController::ConditionalGet + include ActionController::RackConvenience # Legacy modules include SessionManagement @@ -38,9 +39,9 @@ module ActionController # TODO: Extract into its own module # This should be moved together with other normalizing behavior module ImplicitRender - def process_action(method_name) + def send_action(method_name) ret = super - default_render if response_body.nil? + default_render unless performed? ret end @@ -65,31 +66,31 @@ module ActionController ::ActionController::Base.subclasses << klass.to_s super end - + def self.subclasses @subclasses ||= [] end - + def self.app_loaded! @subclasses.each do |subclass| subclass.constantize._write_layout_method end end - + def _normalize_options(action = nil, options = {}, &blk) if action.is_a?(Hash) - options, action = action, nil + options, action = action, nil elsif action.is_a?(String) || action.is_a?(Symbol) key = case action = action.to_s when %r{^/} then :file when %r{/} then :template else :action - end + end options.merge! key => action elsif action options.merge! :partial => action end - + if options.key?(:action) && options[:action].to_s.index("/") options[:template] = options.delete(:action) end @@ -139,7 +140,7 @@ module ActionController # # When using <tt>redirect_to :back</tt>, if there is no referrer, # RedirectBackError will be raised. You may specify some fallback - # behavior for this case by rescuing RedirectBackError. + # behavior for this case by rescuing RedirectBackError. def redirect_to(options = {}, response_status = {}) #:doc: raise ActionControllerError.new("Cannot redirect to nil!") if options.nil? @@ -165,7 +166,7 @@ module ActionController else url_for(options) end - + super(url, status) end end diff --git a/actionpack/lib/action_controller/new_base/compatibility.rb b/actionpack/lib/action_controller/new_base/compatibility.rb index 4245ba982b..f278c2da14 100644 --- a/actionpack/lib/action_controller/new_base/compatibility.rb +++ b/actionpack/lib/action_controller/new_base/compatibility.rb @@ -1,6 +1,6 @@ module ActionController module Rails2Compatibility - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern class ::ActionController::ActionControllerError < StandardError #:nodoc: end @@ -9,43 +9,43 @@ module ActionController included do ::ActionController::UnknownAction = ::AbstractController::ActionNotFound ::ActionController::DoubleRenderError = ::AbstractController::DoubleRenderError - + cattr_accessor :session_options self.session_options = {} - + cattr_accessor :allow_concurrency self.allow_concurrency = false - + cattr_accessor :param_parsers self.param_parsers = { Mime::MULTIPART_FORM => :multipart_form, Mime::URL_ENCODED_FORM => :url_encoded_form, Mime::XML => :xml_simple, Mime::JSON => :json } - + cattr_accessor :relative_url_root self.relative_url_root = ENV['RAILS_RELATIVE_URL_ROOT'] - + cattr_accessor :default_charset self.default_charset = "utf-8" - + # cattr_reader :protected_instance_variables cattr_accessor :protected_instance_variables self.protected_instance_variables = %w(@assigns @performed_redirect @performed_render @variables_added @request_origin @url @parent_controller @action_name @before_filter_chain_aborted @action_cache_path @_headers @_params @_flash @_response) - + # Indicates whether or not optimise the generated named # route helper methods cattr_accessor :optimise_named_routes self.optimise_named_routes = true - + cattr_accessor :resources_path_names self.resources_path_names = { :new => 'new', :edit => 'edit' } - + # Controls the resource action separator cattr_accessor :resource_action_separator self.resource_action_separator = "/" - + cattr_accessor :use_accept_header self.use_accept_header = true @@ -61,19 +61,29 @@ module ActionController # and images to a dedicated asset server away from the main web server. Example: # ActionController::Base.asset_host = "http://assets.example.com" cattr_accessor :asset_host + + cattr_accessor :ip_spoofing_check + self.ip_spoofing_check = true end - + # For old tests def initialize_template_class(*) end def assign_shortcuts(*) end # TODO: Remove this after we flip def template - _action_view + @template ||= _action_view + end + + def process_action(*) + template + super end module ClassMethods - def consider_all_requests_local() end + def consider_all_requests_local + end + def rescue_action(env) raise env["action_dispatch.rescue.exception"] end @@ -84,16 +94,11 @@ module ActionController end end - def initialize(*) - super - @template = _action_view - end - def render_to_body(options) if options.is_a?(Hash) && options.key?(:template) options[:template].sub!(/^\//, '') end - + options[:text] = nil if options[:nothing] == true body = super @@ -107,8 +112,8 @@ module ActionController def method_for_action(action_name) super || (respond_to?(:method_missing) && "_handle_method_missing") - end - + end + def _layout_prefix(name) super unless name =~ /\blayouts/ end @@ -116,5 +121,18 @@ module ActionController def performed? response_body end + + # ==== Request only view path switching ==== + def append_view_path(path) + view_paths.push(*path) + end + + def prepend_view_path(path) + view_paths.unshift(*path) + end + + def view_paths + _action_view.view_paths + end end end diff --git a/actionpack/lib/action_controller/new_base/conditional_get.rb b/actionpack/lib/action_controller/new_base/conditional_get.rb index 116ce34494..d287ec4994 100644 --- a/actionpack/lib/action_controller/new_base/conditional_get.rb +++ b/actionpack/lib/action_controller/new_base/conditional_get.rb @@ -1,12 +1,15 @@ module ActionController module ConditionalGet - + extend ActiveSupport::Concern + + include RackConvenience + # Sets the etag, last_modified, or both on the response and renders a # "304 Not Modified" response if the request is already fresh. # # Parameters: # * <tt>:etag</tt> - # * <tt>:last_modified</tt> + # * <tt>:last_modified</tt> # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches). # # Example: @@ -18,14 +21,14 @@ module ActionController # # This will render the show template if the request isn't sending a matching etag or # If-Modified-Since header and just a "304 Not Modified" response if there's a match. - # + # def fresh_when(options) options.assert_valid_keys(:etag, :last_modified, :public) response.etag = options[:etag] if options[:etag] response.last_modified = options[:last_modified] if options[:last_modified] - - if options[:public] + + if options[:public] cache_control = response.headers["Cache-Control"].split(",").map {|k| k.strip } cache_control.delete("private") cache_control.delete("no-cache") @@ -36,8 +39,8 @@ module ActionController if request.fresh?(response) head :not_modified end - end - + end + # Return a response that has no content (merely headers). The options # argument is interpreted to be a hash of header names and values. # This allows you to easily return a response that consists only of @@ -64,8 +67,8 @@ module ActionController end render :nothing => true, :status => status - end - + end + # Sets the etag and/or last_modified on the response and checks it against # the client request. If the request doesn't match the options provided, the # request is considered stale and should be generated from scratch. Otherwise, @@ -73,7 +76,7 @@ module ActionController # # Parameters: # * <tt>:etag</tt> - # * <tt>:last_modified</tt> + # * <tt>:last_modified</tt> # * <tt>:public</tt> By default the Cache-Control header is private, set this to true if you want your application to be cachable by other devices (proxy caches). # # Example: @@ -92,7 +95,7 @@ module ActionController fresh_when(options) !request.fresh?(response) end - + # Sets a HTTP 1.1 Cache-Control header. Defaults to issuing a "private" instruction, so that # intermediate caches shouldn't cache the response. # @@ -114,10 +117,10 @@ module ActionController else cache_control << "private" end - + # This allows for additional headers to be passed through like 'max-stale' => 5.hours cache_control += options.symbolize_keys.reject{|k,v| k == :public || k == :private }.map{ |k,v| v == true ? k.to_s : "#{k.to_s}=#{v.to_s}"} - + response.headers["Cache-Control"] = cache_control.join(', ') end @@ -126,6 +129,5 @@ module ActionController def expires_now #:doc: response.headers["Cache-Control"] = "no-cache" end - end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/helpers.rb b/actionpack/lib/action_controller/new_base/helpers.rb index e00c3c338b..e8000be87b 100644 --- a/actionpack/lib/action_controller/new_base/helpers.rb +++ b/actionpack/lib/action_controller/new_base/helpers.rb @@ -4,9 +4,9 @@ require 'active_support/dependencies' module ActionController module Helpers - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern - depends_on AbstractController::Helpers + include AbstractController::Helpers included do # Set the default directory for helpers @@ -24,10 +24,10 @@ module ActionController # # * <tt>*args</tt>: One or more modules, strings or symbols, or the special symbol <tt>:all</tt>. # * <tt>&block</tt>: A block defining helper methods. - # + # # ==== Examples - # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file - # and include the module in the template class. The second form illustrates how to include custom helpers + # When the argument is a string or symbol, the method will provide the "_helper" suffix, require the file + # and include the module in the template class. The second form illustrates how to include custom helpers # when working with namespaced controllers, or other cases where the file containing the helper definition is not # in one of Rails' standard load paths: # helper :foo # => requires 'foo_helper' and includes FooHelper @@ -40,17 +40,17 @@ module ActionController # <tt>ActionController::Base.helpers_dir</tt> (defaults to <tt>app/helpers/**/*.rb</tt> under RAILS_ROOT). # helper :all # - # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available + # Additionally, the +helper+ class method can receive and evaluate a block, making the methods defined available # to the template. # # One line # helper { def hello() "Hello, world!" end } # # Multi-line # helper do - # def foo(bar) - # "#{bar} is the very best" + # def foo(bar) + # "#{bar} is the very best" # end # end - # + # # Finally, all the above styles can be mixed together, and the +helper+ method can be invoked with a mix of # +symbols+, +strings+, +modules+ and blocks. # helper(:three, BlindHelper) { def mice() 'mice' end } @@ -106,25 +106,24 @@ module ActionController end private - - def default_helper_module! - unless name.blank? - module_name = name.sub(/Controller$|$/, 'Helper') - module_path = module_name.split('::').map { |m| m.underscore }.join('/') - require_dependency module_path - helper module_name.constantize + def default_helper_module! + unless name.blank? + module_name = name.sub(/Controller$|$/, 'Helper') + module_path = module_name.split('::').map { |m| m.underscore }.join('/') + require_dependency module_path + helper module_name.constantize + end + rescue MissingSourceFile => e + raise unless e.is_missing? module_path + rescue NameError => e + raise unless e.missing_name? module_name end - rescue MissingSourceFile => e - raise unless e.is_missing? module_path - rescue NameError => e - raise unless e.missing_name? module_name - end - # Extract helper names from files in app/helpers/**/*.rb - def all_application_helpers - extract = /^#{Regexp.quote(helpers_dir)}\/?(.*)_helper.rb$/ - Dir["#{helpers_dir}/**/*_helper.rb"].map { |file| file.sub extract, '\1' } - end - end # ClassMethods + # Extract helper names from files in app/helpers/**/*.rb + def all_application_helpers + extract = /^#{Regexp.quote(helpers_dir)}\/?(.*)_helper.rb$/ + Dir["#{helpers_dir}/**/*_helper.rb"].map { |file| file.sub extract, '\1' } + end + end end end diff --git a/actionpack/lib/action_controller/new_base/hide_actions.rb b/actionpack/lib/action_controller/new_base/hide_actions.rb index a29b09a893..b45e520bee 100644 --- a/actionpack/lib/action_controller/new_base/hide_actions.rb +++ b/actionpack/lib/action_controller/new_base/hide_actions.rb @@ -1,33 +1,39 @@ module ActionController module HideActions - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do extlib_inheritable_accessor :hidden_actions self.hidden_actions ||= Set.new end - def action_methods() self.class.action_names end - def action_names() action_methods end - - private - - def action_method?(action_name) - !hidden_actions.include?(action_name) && super + def action_methods + self.class.action_names end - - module ClassMethods - def hide_action(*args) - args.each do |arg| - self.hidden_actions << arg.to_s - end - end - - def action_methods - @action_names ||= Set.new(super.reject {|name| self.hidden_actions.include?(name.to_s)}) - end - def self.action_names() action_methods end + def action_names + action_methods end + + private + def action_method?(action_name) + !hidden_actions.include?(action_name) && super + end + + module ClassMethods + def hide_action(*args) + args.each do |arg| + self.hidden_actions << arg.to_s + end + end + + def action_methods + @action_names ||= Set.new(super.reject {|name| self.hidden_actions.include?(name.to_s)}) + end + + def self.action_names + action_methods + end + end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/http.rb b/actionpack/lib/action_controller/new_base/http.rb index 2525e221a6..c96aaaa865 100644 --- a/actionpack/lib/action_controller/new_base/http.rb +++ b/actionpack/lib/action_controller/new_base/http.rb @@ -4,9 +4,9 @@ require 'active_support/core_ext/module/delegation' module ActionController class Http < AbstractController::Base abstract! - + # :api: public - attr_internal :request, :response, :params + attr_internal :params, :env # :api: public def self.controller_name @@ -14,54 +14,78 @@ module ActionController end # :api: public - def controller_name() self.class.controller_name end + def controller_name + self.class.controller_name + end - # :api: public + # :api: public def self.controller_path @controller_path ||= self.name.sub(/Controller$/, '').underscore end - - # :api: public - def controller_path() self.class.controller_path end - - # :api: private - def self.action_names() action_methods end - + + # :api: public + def controller_path + self.class.controller_path + end + + # :api: private + def self.action_names + action_methods + end + # :api: private - def action_names() action_methods end - + def action_names + action_methods + end + # :api: plugin def self.call(env) controller = new controller.call(env).to_rack end - - delegate :headers, :to => "@_response" - def params - @_params ||= @_request.parameters + # The details below can be overridden to support a specific + # Request and Response object. The default ActionController::Base + # implementation includes RackConvenience, which makes a request + # and response object available. You might wish to control the + # environment and response manually for performance reasons. + + attr_internal :status, :headers, :content_type + + def initialize(*) + @_headers = {} + super + end + + # Basic implements for content_type=, location=, and headers are + # provided to reduce the dependency on the RackConvenience module + # in Renderer and Redirector. + + def content_type=(type) + headers["Content-Type"] = type.to_s end - + + def location=(url) + headers["Location"] = url + end + # :api: private def call(name, env) - @_request = ActionDispatch::Request.new(env) - @_response = ActionDispatch::Response.new - @_response.request = request + @_env = env process(name) to_rack end - + + # :api: private + def to_rack + [status, headers, response_body] + end + def self.action(name) @actions ||= {} @actions[name.to_s] ||= proc do |env| new.call(name, env) end end - - # :api: private - def to_rack - @_response.prepare! - @_response.to_a - end end end diff --git a/actionpack/lib/action_controller/new_base/layouts.rb b/actionpack/lib/action_controller/new_base/layouts.rb index 35068db770..0ff71587d6 100644 --- a/actionpack/lib/action_controller/new_base/layouts.rb +++ b/actionpack/lib/action_controller/new_base/layouts.rb @@ -1,36 +1,34 @@ module ActionController module Layouts - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern + + include ActionController::Renderer + include AbstractController::Layouts - depends_on ActionController::Renderer - depends_on AbstractController::Layouts - module ClassMethods def _implied_layout_name controller_path end end - - private - def _determine_template(options) - super - if (!options.key?(:text) && !options.key?(:inline) && !options.key?(:partial)) || options.key?(:layout) - options[:_layout] = _layout_for_option(options.key?(:layout) ? options[:layout] : :none, options[:_template].details) + private + def _determine_template(options) + super + if (!options.key?(:text) && !options.key?(:inline) && !options.key?(:partial)) || options.key?(:layout) + options[:_layout] = _layout_for_option(options.key?(:layout) ? options[:layout] : :none, options[:_template].details) + end end - end - - def _layout_for_option(name, details) - case name - when String then _layout_for_name(name, details) - when true then _default_layout(true, details) - when :none then _default_layout(false, details) - when false, nil then nil - else - raise ArgumentError, - "String, true, or false, expected for `layout'; you passed #{name.inspect}" + + def _layout_for_option(name, details) + case name + when String then _layout_for_name(name, details) + when true then _default_layout(true, details) + when :none then _default_layout(false, details) + when false, nil then nil + else + raise ArgumentError, + "String, true, or false, expected for `layout'; you passed #{name.inspect}" + end end - end - end end diff --git a/actionpack/lib/action_controller/new_base/rack_convenience.rb b/actionpack/lib/action_controller/new_base/rack_convenience.rb new file mode 100644 index 0000000000..5dfa7d12f3 --- /dev/null +++ b/actionpack/lib/action_controller/new_base/rack_convenience.rb @@ -0,0 +1,33 @@ +module ActionController + module RackConvenience + extend ActiveSupport::Concern + + included do + delegate :headers, :status=, :location=, + :status, :location, :content_type, :to => "@_response" + attr_internal :request, :response + end + + def call(name, env) + @_request = ActionDispatch::Request.new(env) + @_response = ActionDispatch::Response.new + @_response.request = request + super + end + + def params + @_params ||= @_request.parameters + end + + # :api: private + def to_rack + @_response.prepare! + @_response.to_a + end + + def response_body=(body) + response.body = body if response + super + end + end +end diff --git a/actionpack/lib/action_controller/new_base/redirector.rb b/actionpack/lib/action_controller/new_base/redirector.rb index ff7b74341c..20060b001f 100644 --- a/actionpack/lib/action_controller/new_base/redirector.rb +++ b/actionpack/lib/action_controller/new_base/redirector.rb @@ -6,14 +6,14 @@ module ActionController super(message || DEFAULT_MESSAGE) end end - + module Redirector def redirect_to(url, status) #:doc: raise AbstractController::DoubleRenderError if response_body logger.info("Redirected to #{url}") if logger && logger.info? - response.status = status - response.location = url.gsub(/[\r\n]/, '') + self.status = status + self.location = url.gsub(/[\r\n]/, '') self.response_body = "<html><body>You are being <a href=\"#{CGI.escapeHTML(url)}\">redirected</a>.</body></html>" end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/new_base/render_options.rb b/actionpack/lib/action_controller/new_base/render_options.rb index 581a92cb7b..fc9a02626f 100644 --- a/actionpack/lib/action_controller/new_base/render_options.rb +++ b/actionpack/lib/action_controller/new_base/render_options.rb @@ -1,12 +1,12 @@ module ActionController module RenderOptions - extend ActiveSupport::DependencyModule - + extend ActiveSupport::Concern + included do extlib_inheritable_accessor :_renderers self._renderers = [] end - + module ClassMethods def _write_render_options renderers = _renderers.map do |r| @@ -17,33 +17,31 @@ module ActionController end RUBY_EVAL end - + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 def _handle_render_options(options) #{renderers.join} end RUBY_EVAL end - + def _add_render_option(name) _renderers << name _write_render_options end end - + def render_to_body(options) _handle_render_options(options) || super end end - - module RenderOption - extend ActiveSupport::DependencyModule - included do - extend ActiveSupport::DependencyModule - depends_on ::ActionController::RenderOptions + module RenderOption #:nodoc: + def self.extended(base) + base.extend ActiveSupport::Concern + base.send :include, ::ActionController::RenderOptions - def self.register_renderer(name) + def base.register_renderer(name) included { _add_render_option(name) } end end @@ -51,57 +49,55 @@ module ActionController module Renderers module Json - include RenderOption + extend RenderOption register_renderer :json - + def _render_json(json, options) json = ActiveSupport::JSON.encode(json) unless json.respond_to?(:to_str) json = "#{options[:callback]}(#{json})" unless options[:callback].blank? - response.content_type ||= Mime::JSON + self.content_type ||= Mime::JSON self.response_body = json - end + end end module Js - include RenderOption + extend RenderOption register_renderer :js def _render_js(js, options) - response.content_type ||= Mime::JS + self.content_type ||= Mime::JS self.response_body = js end end module Xml - include RenderOption + extend RenderOption register_renderer :xml def _render_xml(xml, options) - response.content_type ||= Mime::XML + self.content_type ||= Mime::XML self.response_body = xml.respond_to?(:to_xml) ? xml.to_xml : xml end end - module Rjs - include RenderOption + module RJS + extend RenderOption register_renderer :update def _render_update(proc, options) generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(_action_view, &proc) - response.content_type = Mime::JS + self.content_type = Mime::JS self.response_body = generator.to_s end end module All - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern - included do - include ::ActionController::Renderers::Json - include ::ActionController::Renderers::Js - include ::ActionController::Renderers::Xml - include ::ActionController::Renderers::Rjs - end + include ActionController::Renderers::Json + include ActionController::Renderers::Js + include ActionController::Renderers::Xml + include ActionController::Renderers::RJS end end end diff --git a/actionpack/lib/action_controller/new_base/renderer.rb b/actionpack/lib/action_controller/new_base/renderer.rb index 987751a601..2fab501302 100644 --- a/actionpack/lib/action_controller/new_base/renderer.rb +++ b/actionpack/lib/action_controller/new_base/renderer.rb @@ -1,23 +1,18 @@ module ActionController module Renderer - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern + + include AbstractController::Renderer - depends_on AbstractController::Renderer - def process_action(*) self.formats = request.formats.map {|x| x.to_sym} super end - - def response_body=(body) - response.body = body if response - super - end def render(options) super options[:_template] ||= _action_view._partial - response.content_type ||= begin + self.content_type ||= begin mime = options[:_template].mime_type formats.include?(mime && mime.to_sym) || formats.include?(:all) ? mime : Mime::Type.lookup_by_extension(formats.first) end @@ -26,7 +21,7 @@ module ActionController def render_to_body(options) _process_options(options) - + if options.key?(:partial) _render_partial(options[:partial], options) end @@ -34,51 +29,50 @@ module ActionController super end - private + private + def _prefix + controller_path + end - def _prefix - controller_path - end + def _determine_template(options) + if options.key?(:text) + options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first) + elsif options.key?(:inline) + handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb") + template = ActionView::Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) + options[:_template] = template + elsif options.key?(:template) + options[:_template_name] = options[:template] + elsif options.key?(:file) + options[:_template_name] = options[:file] + elsif !options.key?(:partial) + options[:_template_name] = (options[:action] || action_name).to_s + options[:_prefix] = _prefix + end - def _determine_template(options) - if options.key?(:text) - options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first) - elsif options.key?(:inline) - handler = ActionView::Template.handler_class_for_extension(options[:type] || "erb") - template = ActionView::Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) - options[:_template] = template - elsif options.key?(:template) - options[:_template_name] = options[:template] - elsif options.key?(:file) - options[:_template_name] = options[:file] - elsif !options.key?(:partial) - options[:_template_name] = (options[:action] || action_name).to_s - options[:_prefix] = _prefix + super end - - super - end - def _render_partial(partial, options) - case partial - when true - options[:_prefix] = _prefix - when String - options[:_prefix] = _prefix unless partial.index('/') - options[:_template_name] = partial - else - options[:_partial_object] = true - return + def _render_partial(partial, options) + case partial + when true + options[:_prefix] = _prefix + when String + options[:_prefix] = _prefix unless partial.index('/') + options[:_template_name] = partial + else + options[:_partial_object] = true + return + end + + options[:_partial] = options[:object] || true + end + + def _process_options(options) + status, content_type, location = options.values_at(:status, :content_type, :location) + self.status = status if status + self.content_type = content_type if content_type + self.headers["Location"] = url_for(location) if location end - - options[:_partial] = options[:object] || true - end - - def _process_options(options) - status, content_type, location = options.values_at(:status, :content_type, :location) - response.status = status if status - response.content_type = content_type if content_type - response.headers["Location"] = url_for(location) if location - end end end diff --git a/actionpack/lib/action_controller/new_base/rescuable.rb b/actionpack/lib/action_controller/new_base/rescuable.rb index 29ffe19d5f..029e643d93 100644 --- a/actionpack/lib/action_controller/new_base/rescuable.rb +++ b/actionpack/lib/action_controller/new_base/rescuable.rb @@ -15,7 +15,7 @@ module ActionController #:nodoc: # behavior is achieved by overriding the <tt>rescue_action_in_public</tt> # and <tt>rescue_action_locally</tt> methods. module Rescue - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do include ActiveSupport::Rescuable @@ -32,22 +32,21 @@ module ActionController #:nodoc: attr_internal :rescued_exception - private - - def method_for_action(action_name) - return action_name if self.rescued_exception = request.env.delete("action_dispatch.rescue.exception") - super - end + 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 _rescue_action + rescue_with_handler(rescued_exception) || raise(rescued_exception) + end - def process_action(*) - super - rescue Exception => exception - self.rescued_exception = exception - _rescue_action - end + def process_action(*) + super + rescue Exception => exception + self.rescued_exception = exception + _rescue_action + end end end diff --git a/actionpack/lib/action_controller/new_base/session.rb b/actionpack/lib/action_controller/new_base/session.rb index a8715555fb..bcedd6e1c7 100644 --- a/actionpack/lib/action_controller/new_base/session.rb +++ b/actionpack/lib/action_controller/new_base/session.rb @@ -1,5 +1,9 @@ module ActionController module Session + extend ActiveSupport::Concern + + include RackConvenience + def session @_request.session end diff --git a/actionpack/lib/action_controller/new_base/testing.rb b/actionpack/lib/action_controller/new_base/testing.rb index 78051a6252..a4a1116d9e 100644 --- a/actionpack/lib/action_controller/new_base/testing.rb +++ b/actionpack/lib/action_controller/new_base/testing.rb @@ -1,6 +1,8 @@ module ActionController module Testing - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern + + include RackConvenience # OMG MEGA HAX def process_with_new_base_test(request, response) @@ -13,7 +15,7 @@ module ActionController set_test_assigns ret end - + def set_test_assigns @assigns = {} (instance_variable_names - self.class.protected_instance_variables).each do |var| @@ -33,6 +35,5 @@ module ActionController _process_action_callbacks.find_all{|x| x.kind == :before}.map{|x| x.name} end end - end end diff --git a/actionpack/lib/action_controller/new_base/url_for.rb b/actionpack/lib/action_controller/new_base/url_for.rb index 94de9fab50..7119c14cd3 100644 --- a/actionpack/lib/action_controller/new_base/url_for.rb +++ b/actionpack/lib/action_controller/new_base/url_for.rb @@ -1,5 +1,9 @@ module ActionController module UrlFor + extend ActiveSupport::Concern + + include RackConvenience + def process_action(*) initialize_current_url super @@ -21,7 +25,7 @@ module ActionController # by this method. def default_url_options(options = nil) end - + def rewrite_options(options) #:nodoc: if defaults = default_url_options(options) defaults.merge(options) @@ -29,7 +33,7 @@ module ActionController options end end - + def url_for(options = {}) options ||= {} case options @@ -42,4 +46,4 @@ module ActionController end end end -end
\ No newline at end of file +end diff --git a/actionpack/lib/action_controller/routing/resources.rb b/actionpack/lib/action_controller/routing/resources.rb index 86abb7b2f4..05c782d226 100644 --- a/actionpack/lib/action_controller/routing/resources.rb +++ b/actionpack/lib/action_controller/routing/resources.rb @@ -1,3 +1,6 @@ +require 'active_support/core_ext/hash/slice' +require 'active_support/core_ext/object/try' + module ActionController # == Overview # diff --git a/actionpack/lib/action_controller/routing/segments.rb b/actionpack/lib/action_controller/routing/segments.rb index 4f936d51d2..2603855476 100644 --- a/actionpack/lib/action_controller/routing/segments.rb +++ b/actionpack/lib/action_controller/routing/segments.rb @@ -1,7 +1,7 @@ module ActionController module Routing class Segment #:nodoc: - RESERVED_PCHAR = ':@&=+$,;' + RESERVED_PCHAR = ':@&=+$,;%' SAFE_PCHAR = "#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}" if RUBY_VERSION >= '1.9' UNSAFE_PCHAR = Regexp.new("[^#{SAFE_PCHAR}]", false).freeze diff --git a/actionpack/lib/action_controller/testing/integration.rb b/actionpack/lib/action_controller/testing/integration.rb index cc157816e2..af4ccb7837 100644 --- a/actionpack/lib/action_controller/testing/integration.rb +++ b/actionpack/lib/action_controller/testing/integration.rb @@ -301,7 +301,7 @@ module ActionController # A module used to extend ActionController::Base, so that integration tests # can capture the controller used to satisfy a request. module ControllerCapture #:nodoc: - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do alias_method_chain :initialize, :capture diff --git a/actionpack/lib/action_controller/testing/process2.rb b/actionpack/lib/action_controller/testing/process2.rb index 677dd41781..1c6fd2d80a 100644 --- a/actionpack/lib/action_controller/testing/process2.rb +++ b/actionpack/lib/action_controller/testing/process2.rb @@ -51,9 +51,10 @@ module ActionController @request.session = ActionController::TestSession.new(session) unless session.nil? @request.session["flash"] = ActionController::Flash::FlashHash.new.update(flash) if flash - build_request_uri(action, parameters) + @controller.request = @request @controller.params.merge!(parameters) + build_request_uri(action, parameters) # Base.class_eval { include ProcessWithTest } unless Base < ProcessWithTest @controller.process_with_new_base_test(@request, @response) @response diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb index a992f7d912..51e0868995 100644 --- a/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +++ b/actionpack/lib/action_controller/vendor/html-scanner/html/sanitizer.rb @@ -1,3 +1,6 @@ +require 'set' +require 'active_support/core_ext/class/inheritable_attributes' + module HTML class Sanitizer def sanitize(text, options = {}) diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb index 4d598669c7..bfff307669 100644 --- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb +++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb @@ -10,7 +10,8 @@ module ActionDispatch @@rescue_responses = Hash.new(:internal_server_error) @@rescue_responses.update({ 'ActionController::RoutingError' => :not_found, - 'ActionController::UnknownAction' => :not_found, + # TODO: Clean this up after the switch + ActionController::UnknownAction.name => :not_found, 'ActiveRecord::RecordNotFound' => :not_found, 'ActiveRecord::StaleObjectError' => :conflict, 'ActiveRecord::RecordInvalid' => :unprocessable_entity, @@ -23,14 +24,17 @@ module ActionDispatch cattr_accessor :rescue_templates @@rescue_templates = Hash.new('diagnostics') @@rescue_templates.update({ - 'ActionView::MissingTemplate' => 'missing_template', - 'ActionController::RoutingError' => 'routing_error', - 'ActionController::UnknownAction' => 'unknown_action', - 'ActionView::TemplateError' => 'template_error' + 'ActionView::MissingTemplate' => 'missing_template', + 'ActionController::RoutingError' => 'routing_error', + ActionController::UnknownAction.name => 'unknown_action', + 'ActionView::TemplateError' => 'template_error' }) FAILSAFE_RESPONSE = [500, {'Content-Type' => 'text/html'}, - ['<html><body><h1>500 Internal Server Error</h1></body></html>']] + ["<html><body><h1>500 Internal Server Error</h1>" << + "If you are the administrator of this website, then please read this web " << + "application's log file and/or the web server's log file to find out what " << + "went wrong.</body></html>"]] def initialize(app, consider_all_requests_local = false) @app = app diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb index 89d1a49403..e6d6b5a3ef 100644 --- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb +++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/hash/diff' + module ActionDispatch module Assertions # Suite of assertions to test routes generated by Rails and the handling of requests made to them. diff --git a/actionpack/lib/action_view/helpers/capture_helper.rb b/actionpack/lib/action_view/helpers/capture_helper.rb index 9e39536653..b4197479a0 100644 --- a/actionpack/lib/action_view/helpers/capture_helper.rb +++ b/actionpack/lib/action_view/helpers/capture_helper.rb @@ -124,7 +124,11 @@ module ActionView # Use an alternate output buffer for the duration of the block. # Defaults to a new empty string. - def with_output_buffer(buf = '') #:nodoc: + def with_output_buffer(buf = nil) #:nodoc: + unless buf + buf = '' + buf.force_encoding(output_buffer.encoding) if buf.respond_to?(:force_encoding) + end self.output_buffer, old_buffer = buf, output_buffer yield output_buffer @@ -134,9 +138,12 @@ module ActionView # Add the output buffer to the response body and start a new one. def flush_output_buffer #:nodoc: - if output_buffer && output_buffer != '' + if output_buffer && !output_buffer.empty? response.body_parts << output_buffer - self.output_buffer = '' + new = '' + new.force_encoding(output_buffer.encoding) if new.respond_to?(:force_encoding) + self.output_buffer = new + nil end end end diff --git a/actionpack/lib/action_view/helpers/form_tag_helper.rb b/actionpack/lib/action_view/helpers/form_tag_helper.rb index daf38fe3da..c96b1fc8d2 100644 --- a/actionpack/lib/action_view/helpers/form_tag_helper.rb +++ b/actionpack/lib/action_view/helpers/form_tag_helper.rb @@ -353,7 +353,8 @@ module ActionView disable_with << ";#{options.delete('onclick')}" if options['onclick'] options["onclick"] = "if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }" - options["onclick"] << "else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }" + options["onclick"] << "else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';" + options["onclick"] << "hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }" options["onclick"] << "this.setAttribute('originalValue', this.value);this.disabled = true;#{disable_with};" options["onclick"] << "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());" options["onclick"] << "if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index f2429e8cef..eacf117bea 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -171,7 +171,7 @@ module ActionView # <% end %> module Partials extend ActiveSupport::Memoizable - extend ActiveSupport::DependencyModule + extend ActiveSupport::Concern included do attr_accessor :_partial diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index 95f11d6490..21272ef089 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -16,11 +16,9 @@ module ActionView self.default_format = Mime::HTML def compile(template) - src = ::ERB.new("<% __in_erb_template=true %>#{template.source}", nil, erb_trim_mode, '@output_buffer').src - - # Ruby 1.9 prepends an encoding to the source. However this is - # useless because you can only set an encoding on the first line - RUBY_VERSION >= '1.9' ? src.sub(/\A#coding:.*\n/, '') : src + magic = $1 if template.source =~ /\A(<%#.*coding:\s*(\S+)\s*-?%>)/ + erb = "#{magic}<% __in_erb_template=true %>#{template.source}" + ::ERB.new(erb, nil, erb_trim_mode, '@output_buffer').src end end end diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index f61dd591a5..e7ea42c2eb 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -52,16 +52,30 @@ module ActionView locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join + code = @handler.call(self) + if code.sub!(/\A(#.*coding.*)\n/, '') + encoding_comment = $1 + elsif defined?(Encoding) && Encoding.respond_to?(:default_external) + encoding_comment = "#coding:#{Encoding.default_external}" + end + source = <<-end_src def #{method_name}(local_assigns) - old_output_buffer = output_buffer;#{locals_code};#{@handler.call(self)} + old_output_buffer = output_buffer;#{locals_code};#{code} ensure self.output_buffer = old_output_buffer end end_src + if encoding_comment + source = "#{encoding_comment}\n#{source}" + line = -1 + else + line = 0 + end + begin - ActionView::Base::CompiledTemplates.module_eval(source, identifier, 0) + ActionView::Base::CompiledTemplates.module_eval(source, identifier, line) method_name rescue Exception => e # errors from template code if logger = (view && view.logger) @@ -79,4 +93,4 @@ module ActionView "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") end end -end
\ No newline at end of file +end diff --git a/actionpack/test/controller/cookie_test.rb b/actionpack/test/controller/cookie_test.rb index 39d0017dd8..7199da3441 100644 --- a/actionpack/test/controller/cookie_test.rb +++ b/actionpack/test/controller/cookie_test.rb @@ -123,6 +123,12 @@ class CookieTest < ActionController::TestCase assert_cookie_header "user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT" end + def test_cookies_persist_throughout_request + get :authenticate + cookies = @controller.send(:cookies) + assert_equal 'david', cookies['user_name'] + end + private def assert_cookie_header(expected) header = @response.headers["Set-Cookie"] diff --git a/actionpack/test/controller/filters_test.rb b/actionpack/test/controller/filters_test.rb index bdcc24b371..df0a9dbfb0 100644 --- a/actionpack/test/controller/filters_test.rb +++ b/actionpack/test/controller/filters_test.rb @@ -1,10 +1,32 @@ require 'abstract_unit' +require 'active_support/core_ext/symbol' -class << ActionController::Base - %w(append_around_filter prepend_after_filter prepend_around_filter prepend_before_filter skip_after_filter skip_before_filter skip_filter).each do |pending| - define_method(pending) do |*args| - $stderr.puts "#{pending} unimplemented: #{args.inspect}" - end unless method_defined?(pending) +class ActionController::Base + class << self + %w(append_around_filter prepend_after_filter prepend_around_filter prepend_before_filter skip_after_filter skip_before_filter skip_filter).each do |pending| + define_method(pending) do |*args| + $stderr.puts "#{pending} unimplemented: #{args.inspect}" + end unless method_defined?(pending) + end + + if defined?(ActionController::Http) + def before_filters + filters = _process_action_callbacks.select { |c| c.kind == :before } + filters.map! { |c| c.instance_variable_get(:@raw_filter) } + end + end + end + + if defined?(ActionController::Http) + def assigns(key = nil) + assigns = {} + instance_variable_names.each do |ivar| + next if ActionController::Base.protected_instance_variables.include?(ivar) + assigns[ivar[1..-1]] = instance_variable_get(ivar) + end + + key.nil? ? assigns : assigns[key.to_s] + end end end @@ -209,24 +231,29 @@ class FilterTest < ActionController::TestCase end class ConditionalParentOfConditionalSkippingController < ConditionalFilterController - before_filter :conditional_in_parent, :only => [:show, :another_action] - after_filter :conditional_in_parent, :only => [:show, :another_action] + before_filter :conditional_in_parent_before, :only => [:show, :another_action] + after_filter :conditional_in_parent_after, :only => [:show, :another_action] private - def conditional_in_parent + def conditional_in_parent_before @ran_filter ||= [] - @ran_filter << 'conditional_in_parent' + @ran_filter << 'conditional_in_parent_before' + end + + def conditional_in_parent_after + @ran_filter ||= [] + @ran_filter << 'conditional_in_parent_after' end end class ChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController - skip_before_filter :conditional_in_parent, :only => :another_action - skip_after_filter :conditional_in_parent, :only => :another_action + skip_before_filter :conditional_in_parent_before, :only => :another_action + skip_after_filter :conditional_in_parent_after, :only => :another_action end class AnotherChildOfConditionalParentController < ConditionalParentOfConditionalSkippingController - skip_before_filter :conditional_in_parent, :only => :show + skip_before_filter :conditional_in_parent_before, :only => :show end class ProcController < PrependingController @@ -571,11 +598,22 @@ class FilterTest < ActionController::TestCase assert_equal "before and after", assigns["execution_log"] end - def test_prepending_and_appending_around_filter - controller = test_process(MixedFilterController) - assert_equal " before aroundfilter before procfilter before appended aroundfilter " + - " after appended aroundfilter after aroundfilter after procfilter ", - MixedFilterController.execution_log + for_tag(:old_base) do + def test_prepending_and_appending_around_filter + controller = test_process(MixedFilterController) + assert_equal " before aroundfilter before procfilter before appended aroundfilter " + + " after appended aroundfilter after aroundfilter after procfilter ", + MixedFilterController.execution_log + end + end + + for_tag(:new_base) do + def test_prepending_and_appending_around_filter + controller = test_process(MixedFilterController) + assert_equal " before aroundfilter before procfilter before appended aroundfilter " + + " after appended aroundfilter after procfilter after aroundfilter ", + MixedFilterController.execution_log + end end def test_rendering_breaks_filtering_chain @@ -600,7 +638,7 @@ class FilterTest < ActionController::TestCase %w(foo bar baz).each do |action| request = ActionController::TestRequest.new request.query_parameters[:choose] = action - response = DynamicDispatchController.action.call(request.env).last + response = DynamicDispatchController.action(action).call(request.env).last assert_equal action, response.body end end @@ -636,18 +674,18 @@ class FilterTest < ActionController::TestCase def test_conditional_skipping_of_filters_when_parent_filter_is_also_conditional test_process(ChildOfConditionalParentController) - assert_equal %w( conditional_in_parent conditional_in_parent ), assigns['ran_filter'] + assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter'] test_process(ChildOfConditionalParentController, 'another_action') assert_nil assigns['ran_filter'] end def test_condition_skipping_of_filters_when_siblings_also_have_conditions test_process(ChildOfConditionalParentController) - assert_equal %w( conditional_in_parent conditional_in_parent ), assigns['ran_filter'], "1" + assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter'] test_process(AnotherChildOfConditionalParentController) - assert_equal nil, assigns['ran_filter'] + assert_equal %w( conditional_in_parent_after ), assigns['ran_filter'] test_process(ChildOfConditionalParentController) - assert_equal %w( conditional_in_parent conditional_in_parent ), assigns['ran_filter'] + assert_equal %w( conditional_in_parent_before conditional_in_parent_after ), assigns['ran_filter'] end def test_changing_the_requirements @@ -801,7 +839,9 @@ class ControllerWithAllTypesOfFilters < PostsController end class ControllerWithTwoLessFilters < ControllerWithAllTypesOfFilters + $vbf = true skip_filter :around_again + $vbf = false skip_filter :after end @@ -864,9 +904,18 @@ class YieldingAroundFiltersTest < ActionController::TestCase end end - def test_filter_order_with_all_filter_types - test_process(ControllerWithAllTypesOfFilters,'no_raise') - assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) around (after yield) after', assigns['ran_filter'].join(' ') + for_tag(:old_base) do + def test_filter_order_with_all_filter_types + test_process(ControllerWithAllTypesOfFilters,'no_raise') + assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) around (after yield) after', assigns['ran_filter'].join(' ') + end + end + + for_tag(:new_base) do + def test_filter_order_with_all_filter_types + test_process(ControllerWithAllTypesOfFilters,'no_raise') + assert_equal 'before around (before yield) around_again (before yield) around_again (after yield) after around (after yield)', assigns['ran_filter'].join(' ') + end end def test_filter_order_with_skip_filter_method @@ -879,7 +928,6 @@ class YieldingAroundFiltersTest < ActionController::TestCase response = test_process(controller, 'fail_1') assert_equal ' ', response.body assert_equal 1, controller.instance_variable_get(:@try) - assert controller.instance_variable_get(:@before_filter_chain_aborted) end def test_second_filter_in_multiple_before_filter_chain_halts @@ -887,7 +935,6 @@ class YieldingAroundFiltersTest < ActionController::TestCase response = test_process(controller, 'fail_2') assert_equal ' ', response.body assert_equal 2, controller.instance_variable_get(:@try) - assert controller.instance_variable_get(:@before_filter_chain_aborted) end def test_last_filter_in_multiple_before_filter_chain_halts @@ -895,7 +942,6 @@ class YieldingAroundFiltersTest < ActionController::TestCase response = test_process(controller, 'fail_3') assert_equal ' ', response.body assert_equal 3, controller.instance_variable_get(:@try) - assert controller.instance_variable_get(:@before_filter_chain_aborted) end protected diff --git a/actionpack/test/controller/flash_test.rb b/actionpack/test/controller/flash_test.rb index 84e27d7779..c448f36cb3 100644 --- a/actionpack/test/controller/flash_test.rb +++ b/actionpack/test/controller/flash_test.rb @@ -122,7 +122,7 @@ class FlashTest < ActionController::TestCase assert_nil assigns["flash_copy"]["that"], "On second flash" assert_equal "hello again", assigns["flash_copy"]["this"], "On second flash" end - + def test_flash_after_reset_session get :use_flash_after_reset_session assert_equal "hello", assigns["flashy_that"] @@ -130,6 +130,11 @@ class FlashTest < ActionController::TestCase assert_nil assigns["flashy_that_reset"] end + def test_does_not_set_the_session_if_the_flash_is_empty + get :std_action + assert_nil session["flash"] + end + def test_sweep_after_halted_filter_chain get :std_action assert_nil assigns["flash_copy"]["foo"] @@ -140,4 +145,19 @@ class FlashTest < ActionController::TestCase get :std_action assert_nil assigns["flash_copy"]["foo"] end + + def test_keep_and_discard_return_values + flash = ActionController::Flash::FlashHash.new + flash.update(:foo => :foo_indeed, :bar => :bar_indeed) + + assert_equal(:foo_indeed, flash.discard(:foo)) # valid key passed + assert_nil flash.discard(:unknown) # non existant key passed + assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.discard()) # nothing passed + assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.discard(nil)) # nothing passed + + assert_equal(:foo_indeed, flash.keep(:foo)) # valid key passed + assert_nil flash.keep(:unknown) # non existant key passed + assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep()) # nothing passed + assert_equal({:foo => :foo_indeed, :bar => :bar_indeed}, flash.keep(nil)) # nothing passed + end end diff --git a/actionpack/test/controller/routing_test.rb b/actionpack/test/controller/routing_test.rb index 11bffdb42e..6b08a04b10 100644 --- a/actionpack/test/controller/routing_test.rb +++ b/actionpack/test/controller/routing_test.rb @@ -90,6 +90,11 @@ class StaticSegmentTest < Test::Unit::TestCase assert_equal 'Hello World', s.interpolation_chunk end + def test_value_should_not_be_double_unescaped + s = ROUTING::StaticSegment.new('%D0%9A%D0%B0%D1%80%D1%82%D0%B0') # Карта + assert_equal '%D0%9A%D0%B0%D1%80%D1%82%D0%B0', s.interpolation_chunk + end + def test_regexp_chunk_should_escape_specials s = ROUTING::StaticSegment.new('Hello*World') assert_equal 'Hello\*World', s.regexp_chunk @@ -644,9 +649,8 @@ class RoutingTest < Test::Unit::TestCase ActionController::Routing.use_controllers! nil - silence_warnings do - Object.send(:const_set, :RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures') - end + Object.send(:remove_const, :RAILS_ROOT) if defined?(::RAILS_ROOT) + Object.const_set(:RAILS_ROOT, File.dirname(__FILE__) + '/controller_fixtures') ActionController::Routing.controller_paths = [ RAILS_ROOT, RAILS_ROOT + '/app/controllers', RAILS_ROOT + '/vendor/plugins/bad_plugin/lib' @@ -2482,7 +2486,8 @@ end class RouteLoadingTest < Test::Unit::TestCase def setup routes.instance_variable_set '@routes_last_modified', nil - silence_warnings { Object.const_set :RAILS_ROOT, '.' } + Object.remove_const(:RAILS_ROOT) if defined?(::RAILS_ROOT) + Object.const_set :RAILS_ROOT, '.' routes.add_configuration_file(File.join(RAILS_ROOT, 'config', 'routes.rb')) @stat = stub_everything diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb index 0ac10634b2..c732d1c910 100644 --- a/actionpack/test/controller/view_paths_test.rb +++ b/actionpack/test/controller/view_paths_test.rb @@ -22,7 +22,7 @@ class ViewLoadPathsTest < ActionController::TestCase end def setup - TestController.view_paths = nil + # TestController.view_paths = nil @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new @@ -48,7 +48,7 @@ class ViewLoadPathsTest < ActionController::TestCase def assert_paths(*paths) controller = paths.first.is_a?(Class) ? paths.shift : @controller - assert_equal expand(paths), controller.view_paths.map(&:to_s) + assert_equal expand(paths), controller.view_paths.map { |p| p.to_s } end def test_template_load_path_was_set_correctly diff --git a/actionpack/test/dispatch/show_exceptions_test.rb b/actionpack/test/dispatch/show_exceptions_test.rb index 0c0c087340..ce1973853e 100644 --- a/actionpack/test/dispatch/show_exceptions_test.rb +++ b/actionpack/test/dispatch/show_exceptions_test.rb @@ -61,7 +61,7 @@ class ShowExceptionsTest < ActionController::IntegrationTest get "/not_found" assert_response 404 - assert_match /ActionController::UnknownAction/, body + assert_match /#{ActionController::UnknownAction.name}/, body get "/method_not_allowed" assert_response 405 @@ -99,7 +99,7 @@ class ShowExceptionsTest < ActionController::IntegrationTest get "/not_found" assert_response 404 - assert_match /ActionController::UnknownAction/, body + assert_match /#{ActionController::UnknownAction.name}/, body get "/method_not_allowed" assert_response 405 diff --git a/actionpack/test/fixtures/test/utf8.html.erb b/actionpack/test/fixtures/test/utf8.html.erb index 0b4d19aa0e..14fe12debc 100644 --- a/actionpack/test/fixtures/test/utf8.html.erb +++ b/actionpack/test/fixtures/test/utf8.html.erb @@ -1,2 +1,4 @@ Русский текст -日本語のテキスト
\ No newline at end of file +<%= "日".encoding %> +<%= @output_buffer.encoding %> +<%= __ENCODING__ %> diff --git a/actionpack/test/fixtures/test/utf8_magic.html.erb b/actionpack/test/fixtures/test/utf8_magic.html.erb new file mode 100644 index 0000000000..58cd03b439 --- /dev/null +++ b/actionpack/test/fixtures/test/utf8_magic.html.erb @@ -0,0 +1,5 @@ +<%# encoding: utf-8 -%> +Русский текст +<%= "日".encoding %> +<%= @output_buffer.encoding %> +<%= __ENCODING__ %> diff --git a/actionpack/test/template/body_parts_test.rb b/actionpack/test/template/body_parts_test.rb index e17092a452..4e7aa63f96 100644 --- a/actionpack/test/template/body_parts_test.rb +++ b/actionpack/test/template/body_parts_test.rb @@ -4,6 +4,9 @@ class BodyPartsTest < ActionController::TestCase RENDERINGS = [Object.new, Object.new, Object.new] class TestController < ActionController::Base + def performed? + defined?(ActionController::Http) ? true : super + end def index RENDERINGS.each do |rendering| @template.punctuate_body! rendering @@ -16,7 +19,7 @@ class BodyPartsTest < ActionController::TestCase def test_body_parts get :index - pending do + pending(:old_base) do # TestProcess buffers body_parts into body # TODO: Rewrite test w/o going through process assert_equal RENDERINGS, @response.body_parts diff --git a/actionpack/test/template/form_tag_helper_test.rb b/actionpack/test/template/form_tag_helper_test.rb index ea0be4a27a..5ca4d4d6ea 100644 --- a/actionpack/test/template/form_tag_helper_test.rb +++ b/actionpack/test/template/form_tag_helper_test.rb @@ -253,14 +253,14 @@ class FormTagHelperTest < ActionView::TestCase def test_submit_tag assert_dom_equal( - %(<input name='commit' type='submit' value='Save' onclick="if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';alert('hello!');result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" />), + %(<input name='commit' onclick="if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';alert('hello!');result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Save" />), submit_tag("Save", :disable_with => "Saving...", :onclick => "alert('hello!')") ) end def test_submit_tag_with_no_onclick_options assert_dom_equal( - %(<input name='commit' type='submit' value='Save' onclick="if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" />), + %(<input name='commit' onclick="if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Save" />), submit_tag("Save", :disable_with => "Saving...") ) end @@ -274,7 +274,7 @@ class FormTagHelperTest < ActionView::TestCase def test_submit_tag_with_confirmation_and_with_disable_with assert_dom_equal( - %(<input name="commit" type="submit" value="Save" onclick="if (!confirm('Are you sure?')) return false; if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = this.cloneNode(false);hiddenCommit.setAttribute('type', 'hidden');this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" />), + %(<input name="commit" onclick="if (!confirm('Are you sure?')) return false; if (window.hiddenCommit) { window.hiddenCommit.setAttribute('value', this.value); }else { hiddenCommit = document.createElement('input');hiddenCommit.type = 'hidden';hiddenCommit.value = this.value;hiddenCommit.name = this.name;this.form.appendChild(hiddenCommit); }this.setAttribute('originalValue', this.value);this.disabled = true;this.value='Saving...';result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit());if (result == false) { this.value = this.getAttribute('originalValue');this.disabled = false; }return result;" type="submit" value="Save" />), submit_tag("Save", :disable_with => "Saving...", :confirm => "Are you sure?") ) end diff --git a/actionpack/test/template/output_buffer_test.rb b/actionpack/test/template/output_buffer_test.rb index 171cfb63e1..36bbaf9099 100644 --- a/actionpack/test/template/output_buffer_test.rb +++ b/actionpack/test/template/output_buffer_test.rb @@ -9,33 +9,52 @@ class OutputBufferTest < ActionController::TestCase tests TestController - def test_flush_output_buffer - pending - # TODO: This tests needs to be rewritten due - # The @response is not the same response object assigned - # to the @controller.template - - # Start with the default body parts - # --- - # get :index - # assert_equal ['foo'], @response.body_parts - # assert_nil @controller.template.output_buffer - # - # # Nil output buffer is skipped - # @controller.template.flush_output_buffer - # assert_nil @controller.template.output_buffer - # assert_equal ['foo'], @response.body_parts - # - # # Empty output buffer is skipped - # @controller.template.output_buffer = '' - # @controller.template.flush_output_buffer - # assert_equal '', @controller.template.output_buffer - # assert_equal ['foo'], @response.body_parts - # - # # Flushing appends the output buffer to the body parts - # @controller.template.output_buffer = 'bar' - # @controller.template.flush_output_buffer - # assert_equal '', @controller.template.output_buffer - # assert_equal ['foo', 'bar'], @response.body_parts + def setup + get :index + assert_equal ['foo'], body_parts end + + test 'output buffer is nil after rendering' do + assert_nil output_buffer + end + + test 'flushing ignores nil output buffer' do + @controller.template.flush_output_buffer + assert_nil output_buffer + assert_equal ['foo'], body_parts + end + + test 'flushing ignores empty output buffer' do + @controller.template.output_buffer = '' + @controller.template.flush_output_buffer + assert_equal '', output_buffer + assert_equal ['foo'], body_parts + end + + test 'flushing appends the output buffer to the body parts' do + @controller.template.output_buffer = 'bar' + @controller.template.flush_output_buffer + assert_equal '', output_buffer + assert_equal ['foo', 'bar'], body_parts + end + + if '1.9'.respond_to?(:force_encoding) + test 'flushing preserves output buffer encoding' do + original_buffer = ' '.force_encoding(Encoding::EUC_JP) + @controller.template.output_buffer = original_buffer + @controller.template.flush_output_buffer + assert_equal ['foo', original_buffer], body_parts + assert_not_equal original_buffer, output_buffer + assert_equal Encoding::EUC_JP, output_buffer.encoding + end + end + + protected + def output_buffer + @controller.template.output_buffer + end + + def body_parts + @controller.template.response.body_parts + end end diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 71291f009c..20cd4cc1d4 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -247,10 +247,27 @@ module RenderTestCases end if '1.9'.respond_to?(:force_encoding) - def test_render_utf8_template - result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") - assert_equal "Русский текст\n日本語のテキスト", result - assert_equal Encoding::UTF_8, result.encoding + def test_render_utf8_template_with_magic_comment + with_external_encoding Encoding::ASCII_8BIT do + result = @view.render(:file => "test/utf8_magic.html.erb", :layouts => "layouts/yield") + assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result + assert_equal Encoding::UTF_8, result.encoding + end + end + + def test_render_utf8_template_with_default_external_encoding + with_external_encoding Encoding::UTF_8 do + result = @view.render(:file => "test/utf8.html.erb", :layouts => "layouts/yield") + assert_equal "Русский текст\nUTF-8\nUTF-8\nUTF-8\n", result + assert_equal Encoding::UTF_8, result.encoding + end + end + + def with_external_encoding(encoding) + old, Encoding.default_external = Encoding.default_external, encoding + yield + ensure + Encoding.default_external = old end end end |