aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib')
-rw-r--r--actionpack/lib/action_controller/metal/url_for.rb8
-rw-r--r--actionpack/lib/action_controller/test_case.rb12
-rw-r--r--actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb1
-rwxr-xr-xactionpack/lib/action_dispatch/http/request.rb26
-rw-r--r--actionpack/lib/action_dispatch/middleware/flash.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/session/abstract_store.rb8
-rw-r--r--actionpack/lib/action_dispatch/middleware/show_exceptions.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/stack.rb18
-rw-r--r--actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb2
-rw-r--r--actionpack/lib/action_dispatch/routing/mapper.rb15
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb32
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/selector.rb2
-rw-r--r--actionpack/lib/action_view/base.rb3
-rw-r--r--actionpack/lib/action_view/helpers/tag_helper.rb2
-rw-r--r--actionpack/lib/action_view/helpers/text_helper.rb38
-rw-r--r--actionpack/lib/action_view/lookup_context.rb74
-rw-r--r--actionpack/lib/action_view/render/layouts.rb15
-rw-r--r--actionpack/lib/action_view/template/handlers.rb2
18 files changed, 160 insertions, 102 deletions
diff --git a/actionpack/lib/action_controller/metal/url_for.rb b/actionpack/lib/action_controller/metal/url_for.rb
index 10c7ca9021..c465035ca1 100644
--- a/actionpack/lib/action_controller/metal/url_for.rb
+++ b/actionpack/lib/action_controller/metal/url_for.rb
@@ -16,5 +16,13 @@ module ActionController
raise "In order to use #url_for, you must include the helpers of a particular " \
"router. For instance, `include Rails.application.routes.url_helpers"
end
+
+ module ClassMethods
+ def action_methods
+ @action_methods ||= begin
+ super - _router.named_routes.helper_names
+ end
+ end
+ end
end
end \ No newline at end of file
diff --git a/actionpack/lib/action_controller/test_case.rb b/actionpack/lib/action_controller/test_case.rb
index 34499fa784..21281b606e 100644
--- a/actionpack/lib/action_controller/test_case.rb
+++ b/actionpack/lib/action_controller/test_case.rb
@@ -139,14 +139,16 @@ module ActionController
end
end
- params = self.request_parameters.dup
+ # Clear the combined params hash in case it was already referenced.
+ @env.delete("action_dispatch.request.parameters")
+ params = self.request_parameters.dup
%w(controller action only_path).each do |k|
params.delete(k)
params.delete(k.to_sym)
end
-
data = params.to_query
+
@env['CONTENT_LENGTH'] = data.length.to_s
@env['rack.input'] = StringIO.new(data)
end
@@ -155,6 +157,8 @@ module ActionController
@formats = nil
@env.delete_if { |k, v| k =~ /^(action_dispatch|rack)\.request/ }
@env.delete_if { |k, v| k =~ /^action_dispatch\.rescue/ }
+ @method = @request_method = nil
+ @fullpath = @ip = @remote_ip = nil
@env['action_dispatch.request.query_parameters'] = {}
end
end
@@ -167,9 +171,7 @@ module ActionController
@block = nil
@length = 0
@body = []
- @charset = nil
- @content_type = nil
-
+ @charset = @content_type = nil
@request = @template = nil
end
end
diff --git a/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb b/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb
index 602411ed37..064ff3724d 100644
--- a/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb
+++ b/actionpack/lib/action_controller/vendor/html-scanner/html/tokenizer.rb
@@ -23,6 +23,7 @@ module HTML #:nodoc:
# Create a new Tokenizer for the given text.
def initialize(text)
+ text.encode! if text.encoding_aware?
@scanner = StringScanner.new(text)
@position = 0
@line = 0
diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb
index 8560a6fc9c..98f4f5ae18 100755
--- a/actionpack/lib/action_dispatch/http/request.rb
+++ b/actionpack/lib/action_dispatch/http/request.rb
@@ -52,9 +52,11 @@ module ActionDispatch
# the application should use), this \method returns the overridden
# value, not the original.
def request_method
- method = env["REQUEST_METHOD"]
- HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
- method
+ @request_method ||= begin
+ method = env["REQUEST_METHOD"]
+ HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
+ method
+ end
end
# Returns a symbol form of the #request_method
@@ -66,9 +68,11 @@ module ActionDispatch
# even if it was overridden by middleware. See #request_method for
# more information.
def method
- method = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD']
- HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
- method
+ @method ||= begin
+ method = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD']
+ HTTP_METHOD_LOOKUP[method] || raise(ActionController::UnknownHttpMethod, "#{method}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
+ method
+ end
end
# Returns a symbol form of the #method
@@ -113,6 +117,10 @@ module ActionDispatch
Http::Headers.new(@env)
end
+ def fullpath
+ @fullpath ||= super
+ end
+
def forgery_whitelisted?
get? || xhr? || content_mime_type.nil? || !content_mime_type.verify_request?
end
@@ -134,6 +142,10 @@ module ActionDispatch
end
alias :xhr? :xml_http_request?
+ def ip
+ @ip ||= super
+ end
+
# Which IP addresses are "trusted proxies" that can be stripped from
# the right-hand-side of X-Forwarded-For
TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
@@ -145,7 +157,7 @@ module ActionDispatch
# delimited list in the case of multiple chained proxies; the last
# address which is not trusted is the originating IP.
def remote_ip
- (@env["action_dispatch.remote_ip"] || ip).to_s
+ @remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s
end
# Returns the lowercase name of the HTTP server software.
diff --git a/actionpack/lib/action_dispatch/middleware/flash.rb b/actionpack/lib/action_dispatch/middleware/flash.rb
index adde183cdb..18771fe782 100644
--- a/actionpack/lib/action_dispatch/middleware/flash.rb
+++ b/actionpack/lib/action_dispatch/middleware/flash.rb
@@ -176,7 +176,7 @@ module ActionDispatch
@app.call(env)
ensure
- if (session = env['rack.session']) && (flash = session['flash']) && flash.empty?
+ if (session = env['rack.session']) && session.key?('flash') && session['flash'].empty?
session.delete('flash')
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
index 15493cd2eb..3e8d64b0c6 100644
--- a/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
+++ b/actionpack/lib/action_dispatch/middleware/session/abstract_store.rb
@@ -51,11 +51,11 @@ module ActionDispatch
super
end
- private
- def loaded?
- @loaded
- end
+ def loaded?
+ @loaded
+ end
+ private
def load!
stale_session_check! do
id, session = @by.send(:load_session, @env)
diff --git a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
index 2dd2ec9fe9..f9e81a02d3 100644
--- a/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
+++ b/actionpack/lib/action_dispatch/middleware/show_exceptions.rb
@@ -72,7 +72,7 @@ module ActionDispatch
rescue_action_in_public(exception)
end
rescue Exception => failsafe_error
- $stderr.puts "Error during failsafe response: #{failsafe_error}"
+ $stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}"
FAILSAFE_RESPONSE
end
diff --git a/actionpack/lib/action_dispatch/middleware/stack.rb b/actionpack/lib/action_dispatch/middleware/stack.rb
index e3180dba77..4240e7a5d5 100644
--- a/actionpack/lib/action_dispatch/middleware/stack.rb
+++ b/actionpack/lib/action_dispatch/middleware/stack.rb
@@ -5,13 +5,13 @@ module ActionDispatch
class Middleware
attr_reader :args, :block
- def initialize(klass, *args, &block)
- @klass, @args, @block = klass, args, block
+ def initialize(klass_or_name, *args, &block)
+ @ref = ActiveSupport::Dependencies::Reference.new(klass_or_name)
+ @args, @block = args, block
end
def klass
- return @klass if @klass.respond_to?(:new)
- @klass = ActiveSupport::Inflector.constantize(@klass.to_s)
+ @ref.get
end
def ==(middleware)
@@ -21,11 +21,7 @@ module ActionDispatch
when Class
klass == middleware
else
- if lazy_compare?(@klass) && lazy_compare?(middleware)
- normalize(@klass) == normalize(middleware)
- else
- klass.name == normalize(middleware.to_s)
- end
+ normalize(@ref.name) == normalize(middleware)
end
end
@@ -39,10 +35,6 @@ module ActionDispatch
private
- def lazy_compare?(object)
- object.is_a?(String) || object.is_a?(Symbol)
- end
-
def normalize(object)
object.to_s.strip.sub(/^::/, '')
end
diff --git a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
index 09ff052fd0..e963b04524 100644
--- a/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
+++ b/actionpack/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb
@@ -13,7 +13,7 @@
request_dump = clean_params.empty? ? 'None' : clean_params.inspect.gsub(',', ",\n")
def debug_hash(hash)
- hash.sort_by { |k, v| k.to_s }.map { |k, v| "#{k}: #{v.inspect}" }.join("\n")
+ hash.sort_by { |k, v| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
end
%>
diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb
index 8a8d21c434..ae4417b56c 100644
--- a/actionpack/lib/action_dispatch/routing/mapper.rb
+++ b/actionpack/lib/action_dispatch/routing/mapper.rb
@@ -622,12 +622,19 @@ module ActionDispatch
end
def member
- unless @scope[:scope_level] == :resources
- raise ArgumentError, "can't use member outside resources scope"
+ unless [:resources, :resource].include?(@scope[:scope_level])
+ raise ArgumentError, "You can't use member action outside resources and resource scope."
end
- with_scope_level(:member) do
- scope(':id', :name_prefix => parent_resource.member_name, :as => "") do
+ case @scope[:scope_level]
+ when :resources
+ with_scope_level(:member) do
+ scope(':id', :name_prefix => parent_resource.member_name, :as => "") do
+ yield
+ end
+ end
+ when :resource
+ with_scope_level(:member) do
yield
end
end
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 0d071dd7fe..57a73dde75 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -12,6 +12,7 @@ module ActionDispatch
def initialize(options={})
@defaults = options[:defaults]
@glob_param = options.delete(:glob)
+ @controllers = {}
end
def call(env)
@@ -29,19 +30,18 @@ module ActionDispatch
def prepare_params!(params)
merge_default_action!(params)
split_glob_param!(params) if @glob_param
-
- params.each do |key, value|
- if value.is_a?(String)
- value = value.dup.force_encoding(Encoding::BINARY) if value.respond_to?(:force_encoding)
- params[key] = URI.unescape(value)
- end
- end
end
def controller(params, raise_error=true)
- if params && params.has_key?(:controller)
- controller = "#{params[:controller].camelize}Controller"
- ActiveSupport::Inflector.constantize(controller)
+ if params && params.key?(:controller)
+ controller_param = params[:controller]
+ unless controller = @controllers[controller_param]
+ controller_name = "#{controller_param.camelize}Controller"
+ controller = @controllers[controller_param] =
+ ActiveSupport::Dependencies.ref(controller_name)
+ end
+
+ controller.get
end
rescue NameError => e
raise ActionController::RoutingError, e.message, e.backtrace if raise_error
@@ -68,6 +68,10 @@ module ActionDispatch
clear!
end
+ def helper_names
+ self.module.instance_methods.map(&:to_s)
+ end
+
def clear!
@routes = {}
@helpers = []
@@ -176,7 +180,6 @@ module ActionDispatch
url_for(options)
end
- protected :#{selector}
END_EVAL
helpers << selector
end
@@ -466,6 +469,13 @@ module ActionDispatch
req = Rack::Request.new(env)
@set.recognize(req) do |route, matches, params|
+ params.each do |key, value|
+ if value.is_a?(String)
+ value = value.dup.force_encoding(Encoding::BINARY) if value.encoding_aware?
+ params[key] = URI.unescape(value)
+ end
+ end
+
dispatcher = route.app
if dispatcher.is_a?(Dispatcher) && dispatcher.controller(params, false)
dispatcher.prepare_params!(params)
diff --git a/actionpack/lib/action_dispatch/testing/assertions/selector.rb b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
index 9deabf5b3c..0e82b41590 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/selector.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/selector.rb
@@ -267,14 +267,12 @@ module ActionDispatch
if match_with = equals[:text]
matches.delete_if do |match|
text = ""
- text.force_encoding(match_with.encoding) if text.respond_to?(:force_encoding)
stack = match.children.reverse
while node = stack.pop
if node.tag?
stack.concat node.children.reverse
else
content = node.content
- content.force_encoding(match_with.encoding) if content.respond_to?(:force_encoding)
text << content
end
end
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb
index f4af763afe..7dd9dea358 100644
--- a/actionpack/lib/action_view/base.rb
+++ b/actionpack/lib/action_view/base.rb
@@ -184,7 +184,7 @@ module ActionView #:nodoc:
attr_internal :captures, :request, :controller, :template, :config
delegate :find_template, :template_exists?, :formats, :formats=, :locale, :locale=,
- :view_paths, :view_paths=, :with_fallbacks, :update_details, :to => :lookup_context
+ :view_paths, :view_paths=, :with_fallbacks, :update_details, :with_layout_format, :to => :lookup_context
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
:flash, :action_name, :controller_name, :to => :controller
@@ -201,6 +201,7 @@ module ActionView #:nodoc:
end
def self.process_view_paths(value)
+ return value.dup if value.is_a?(PathSet)
ActionView::PathSet.new(Array.wrap(value))
end
diff --git a/actionpack/lib/action_view/helpers/tag_helper.rb b/actionpack/lib/action_view/helpers/tag_helper.rb
index c09d01eeee..66277f79fe 100644
--- a/actionpack/lib/action_view/helpers/tag_helper.rb
+++ b/actionpack/lib/action_view/helpers/tag_helper.rb
@@ -110,7 +110,7 @@ module ActionView
def content_tag_string(name, content, options, escape = true)
tag_options = tag_options(options, escape) if options
- "<#{name}#{tag_options}>#{ERB::Util.h(content)}</#{name}>".html_safe
+ "<#{name}#{tag_options}>#{escape ? ERB::Util.h(content) : content}</#{name}>".html_safe
end
def tag_options(options, escape = true)
diff --git a/actionpack/lib/action_view/helpers/text_helper.rb b/actionpack/lib/action_view/helpers/text_helper.rb
index bfad9f8d31..4c76e9642f 100644
--- a/actionpack/lib/action_view/helpers/text_helper.rb
+++ b/actionpack/lib/action_view/helpers/text_helper.rb
@@ -74,6 +74,7 @@ module ActionView
options.reverse_merge!(:length => 30)
+ text = sanitize(text) unless text.html_safe? || options[:safe]
text.truncate(options.delete(:length), options) if text
end
@@ -105,6 +106,7 @@ module ActionView
end
options.reverse_merge!(:highlighter => '<strong class="highlight">\1</strong>')
+ text = sanitize(text) unless text.html_safe? || options[:safe]
if text.blank? || phrases.blank?
text
else
@@ -244,13 +246,14 @@ module ActionView
#
def textilize(text, *options)
options ||= [:hard_breaks]
+ text = sanitize(text) unless text.html_safe? || options.delete(:safe)
if text.blank?
""
else
textilized = RedCloth.new(text, options)
textilized.to_html
- end
+ end.html_safe
end
# Returns the text with all the Textile codes turned into HTML tags,
@@ -271,8 +274,8 @@ module ActionView
#
# textilize_without_paragraph("Visit the Rails website "here":http://www.rubyonrails.org/.)
# # => "Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>."
- def textilize_without_paragraph(text)
- textiled = textilize(text)
+ def textilize_without_paragraph(text, *options)
+ textiled = textilize(text, options)
if textiled[0..2] == "<p>" then textiled = textiled[3..-1] end
if textiled[-4..-1] == "</p>" then textiled = textiled[0..-5] end
return textiled
@@ -295,8 +298,9 @@ module ActionView
#
# markdown('![The ROR logo](http://rubyonrails.com/images/rails.png "Ruby on Rails")')
# # => '<p><img src="http://rubyonrails.com/images/rails.png" alt="The ROR logo" title="Ruby on Rails" /></p>'
- def markdown(text)
- text.blank? ? "" : BlueCloth.new(text).to_html
+ def markdown(text, options = {})
+ text = sanitize(text) unless options[:safe]
+ (text.blank? ? "" : BlueCloth.new(text).to_html).html_safe
end
# Returns +text+ transformed into HTML using simple formatting rules.
@@ -320,14 +324,15 @@ module ActionView
#
# simple_format("Look ma! A class!", :class => 'description')
# # => "<p class='description'>Look ma! A class!</p>"
- def simple_format(text, html_options={})
+ def simple_format(text, html_options={}, options={})
+ text = '' if text.nil?
start_tag = tag('p', html_options, true)
- text = h(text)
+ text = sanitize(text) unless text.html_safe? || options[:safe]
text.gsub!(/\r\n?/, "\n") # \r\n and \r -> \n
text.gsub!(/\n\n+/, "</p>\n\n#{start_tag}") # 2+ newline -> paragraph
text.gsub!(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
text.insert 0, start_tag
- text.safe_concat("</p>")
+ text.html_safe.safe_concat("</p>")
end
# Turns all URLs and e-mail addresses into clickable links. The <tt>:link</tt> option
@@ -368,7 +373,7 @@ module ActionView
# # => "Welcome to my new blog at <a href=\"http://www.myblog.com/\" target=\"_blank\">http://www.myblog.com</a>.
# Please e-mail me at <a href=\"mailto:me@email.com\">me@email.com</a>."
def auto_link(text, *args, &block)#link = :all, html = {}, &block)
- return '' if text.blank?
+ return ''.html_safe if text.blank?
options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter
unless args.empty?
@@ -378,9 +383,9 @@ module ActionView
options.reverse_merge!(:link => :all, :html => {})
case options[:link].to_sym
- when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], &block), options[:html], &block)
+ when :all then auto_link_email_addresses(auto_link_urls(text, options[:html], options, &block), options[:html], &block)
when :email_addresses then auto_link_email_addresses(text, options[:html], &block)
- when :urls then auto_link_urls(text, options[:html], &block)
+ when :urls then auto_link_urls(text, options[:html], options, &block)
end
end
@@ -544,7 +549,7 @@ module ActionView
# Turns all urls into clickable links. If a block is given, each url
# is yielded and the result is used as the link text.
- def auto_link_urls(text, html_options = {})
+ def auto_link_urls(text, html_options = {}, options = {})
link_attributes = html_options.stringify_keys
text.gsub(AUTO_LINK_RE) do
scheme, href = $1, $&
@@ -566,21 +571,22 @@ module ActionView
link_text = block_given?? yield(href) : href
href = 'http://' + href unless scheme
- content_tag(:a, link_text, link_attributes.merge('href' => href)) + punctuation.reverse.join('')
+ content_tag(:a, link_text, link_attributes.merge('href' => href), !(options[:safe] || text.html_safe?)) + punctuation.reverse.join('')
end
- end
+ end.html_safe
end
# Turns all email addresses into clickable links. If a block is given,
# each email is yielded and the result is used as the link text.
- def auto_link_email_addresses(text, html_options = {})
+ def auto_link_email_addresses(text, html_options = {}, options = {})
text.gsub(AUTO_EMAIL_RE) do
text = $&
if auto_linked?($`, $')
- text
+ text.html_safe
else
display_text = (block_given?) ? yield(text) : text
+ display_text = sanitize(display_text) unless options[:safe]
mail_to text, display_text, html_options
end
end
diff --git a/actionpack/lib/action_view/lookup_context.rb b/actionpack/lib/action_view/lookup_context.rb
index 7021342b4a..823226cb9c 100644
--- a/actionpack/lib/action_view/lookup_context.rb
+++ b/actionpack/lib/action_view/lookup_context.rb
@@ -13,8 +13,13 @@ module ActionView
mattr_accessor :registered_details
self.registered_details = []
+ mattr_accessor :registered_detail_setters
+ self.registered_detail_setters = []
+
def self.register_detail(name, options = {}, &block)
self.registered_details << name
+ self.registered_detail_setters << [name, "#{name}="]
+
Accessors.send :define_method, :"_#{name}_defaults", &block
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
def #{name}
@@ -23,12 +28,7 @@ module ActionView
def #{name}=(value)
value = Array.wrap(value.presence || _#{name}_defaults)
-
- if value != @details[:#{name}]
- @details_key = nil
- @details = @details.dup if @details.frozen?
- @details[:#{name}] = value.freeze
- end
+ _set_detail(:#{name}, value) if value != @details[:#{name}]
end
METHOD
end
@@ -59,8 +59,11 @@ module ActionView
def initialize(view_paths, details = {})
@details, @details_key = { :handlers => default_handlers }, nil
@frozen_formats, @skip_default_locale = false, false
+
self.view_paths = view_paths
- self.update_details(details, true)
+ self.registered_detail_setters.each do |key, setter|
+ send(setter, details[key])
+ end
end
module ViewPaths
@@ -116,11 +119,11 @@ module ActionView
end
def default_handlers #:nodoc:
- @default_handlers ||= Template::Handlers.extensions
+ @@default_handlers ||= Template::Handlers.extensions
end
def handlers_regexp #:nodoc:
- @handlers_regexp ||= /\.(?:#{default_handlers.join('|')})$/
+ @@handlers_regexp ||= /\.(?:#{default_handlers.join('|')})$/
end
end
@@ -141,10 +144,13 @@ module ActionView
end
# Overload formats= to reject [:"*/*"] values.
- def formats=(value)
- value = nil if value == [:"*/*"]
- value << :html if value == [:js]
- super(value)
+ def formats=(values)
+ if values && values.size == 1
+ value = values.first
+ values = nil if value == :"*/*"
+ values << :html if value == :js
+ end
+ super(values)
end
# Do not use the default locale on template lookup.
@@ -170,24 +176,48 @@ module ActionView
super(@skip_default_locale ? I18n.locale : _locale_defaults)
end
+ # A method which only uses the first format in the formats array for layout lookup.
+ # This method plays straight with instance variables for performance reasons.
+ def with_layout_format
+ if formats.size == 1
+ yield
+ else
+ old_formats = formats
+ _set_detail(:formats, formats[0,1])
+
+ begin
+ yield
+ ensure
+ _set_detail(:formats, old_formats)
+ end
+ end
+ end
+
# Update the details keys by merging the given hash into the current
# details hash. If a block is given, the details are modified just during
# the execution of the block and reverted to the previous value after.
- def update_details(new_details, force=false)
+ def update_details(new_details)
old_details = @details.dup
- registered_details.each do |key|
- send(:"#{key}=", new_details[key]) if force || new_details.key?(key)
+ registered_detail_setters.each do |key, setter|
+ send(setter, new_details[key]) if new_details.key?(key)
end
- if block_given?
- begin
- yield
- ensure
- @details = old_details
- end
+ begin
+ yield
+ ensure
+ @details_key = nil
+ @details = old_details
end
end
+
+ protected
+
+ def _set_detail(key, value)
+ @details_key = nil
+ @details = @details.dup if @details.frozen?
+ @details[key] = value.freeze
+ end
end
include Accessors
diff --git a/actionpack/lib/action_view/render/layouts.rb b/actionpack/lib/action_view/render/layouts.rb
index 31b09d9f0a..a9dfc0cced 100644
--- a/actionpack/lib/action_view/render/layouts.rb
+++ b/actionpack/lib/action_view/render/layouts.rb
@@ -57,15 +57,11 @@ module ActionView
# This is the method which actually finds the layout using details in the lookup
# context object. If no layout is found, it checkes if at least a layout with
# the given name exists across all details before raising the error.
- #
- # If self.formats contains several formats, just the first one is considered in
- # the layout lookup.
def find_layout(layout)
begin
- if formats.size == 1
- _find_layout(layout)
- else
- update_details(:formats => self.formats.first){ _find_layout(layout) }
+ with_layout_format do
+ layout =~ /^\// ?
+ with_fallbacks { find_template(layout) } : find_template(layout)
end
rescue ActionView::MissingTemplate => e
update_details(:formats => nil) do
@@ -74,11 +70,6 @@ module ActionView
end
end
- def _find_layout(layout) #:nodoc:
- layout =~ /^\// ?
- with_fallbacks { find_template(layout) } : find_template(layout)
- end
-
# Contains the logic that actually renders the layout.
def _render_layout(layout, locals, &block) #:nodoc:
layout.render(self, locals){ |*name| _layout_for(*name, &block) }
diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb
index 35488c0391..6228d7ac39 100644
--- a/actionpack/lib/action_view/template/handlers.rb
+++ b/actionpack/lib/action_view/template/handlers.rb
@@ -19,7 +19,7 @@ module ActionView #:nodoc:
@@default_template_handlers = nil
def self.extensions
- @@template_handlers.keys
+ @@template_extensions ||= @@template_handlers.keys
end
# Register a class that knows how to handle template files with the given