aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/abstract_controller
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/abstract_controller')
-rw-r--r--actionpack/lib/abstract_controller/helpers.rb81
-rw-r--r--actionpack/lib/abstract_controller/layouts.rb29
-rw-r--r--actionpack/lib/abstract_controller/localized_cache.rb49
-rw-r--r--actionpack/lib/abstract_controller/logger.rb24
-rw-r--r--actionpack/lib/abstract_controller/rendering_controller.rb19
5 files changed, 170 insertions, 32 deletions
diff --git a/actionpack/lib/abstract_controller/helpers.rb b/actionpack/lib/abstract_controller/helpers.rb
index f3072fad74..d3b492ad09 100644
--- a/actionpack/lib/abstract_controller/helpers.rb
+++ b/actionpack/lib/abstract_controller/helpers.rb
@@ -1,3 +1,5 @@
+require 'active_support/dependencies'
+
module AbstractController
module Helpers
extend ActiveSupport::Concern
@@ -57,23 +59,48 @@ module AbstractController
end
end
- # Make a number of helper modules part of this class' default
- # helpers.
+ # The +helper+ class method can take a series of helper module names, a block, or both.
#
# ==== Parameters
- # *args<Array[Module]>:: Modules to be included
- # block<Block>:: Evalulate the block in the context
- # of the helper module. Any methods defined in the block
- # will be helpers.
+ # *args<Array[Module, Symbol, String, :all]>
+ # block<Block>:: A block defining helper methods
+ #
+ # ==== Examples
+ # When the argument is a module it will be included directly in the template class.
+ # helper FooHelper # => includes FooHelper
+ #
+ # 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
+ # helper 'resources/foo' # => requires 'resources/foo_helper' and includes Resources::FooHelper
+ #
+ # 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"
+ # 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 }
+ #
def helper(*args, &block)
self._helper_serial = AbstractController::Helpers.next_serial + 1
- args.flatten.each do |arg|
- case arg
- when Module
- add_template_helper(arg)
- end
+ _modules_for_helpers(args).each do |mod|
+ add_template_helper(mod)
end
+
_helpers.module_eval(&block) if block_given?
end
@@ -87,6 +114,38 @@ module AbstractController
def add_template_helper(mod)
_helpers.module_eval { include mod }
end
+
+ # Returns a list of modules, normalized from the acceptable kinds of
+ # helpers with the following behavior:
+ #
+ # String or Symbol:: :FooBar or "FooBar" becomes "foo_bar_helper",
+ # and "foo_bar_helper.rb" is loaded using require_dependency.
+ #
+ # Module:: No further processing
+ #
+ # After loading the appropriate files, the corresponding modules
+ # are returned.
+ #
+ # ==== Parameters
+ # args<Array[String, Symbol, Module]>:: A list of helpers
+ #
+ # ==== Returns
+ # Array[Module]:: A normalized list of modules for the list of
+ # helpers provided.
+ def _modules_for_helpers(args)
+ args.flatten.map! do |arg|
+ case arg
+ when String, Symbol
+ file_name = "#{arg.to_s.underscore}_helper"
+ require_dependency(file_name, "Missing helper file helpers/%s.rb")
+ file_name.camelize.constantize
+ when Module
+ arg
+ else
+ raise ArgumentError, "helper must be a String, Symbol, or Module"
+ end
+ end
+ end
end
end
end
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb
index 796ef40584..8293e79b0a 100644
--- a/actionpack/lib/abstract_controller/layouts.rb
+++ b/actionpack/lib/abstract_controller/layouts.rb
@@ -157,6 +157,7 @@ module AbstractController
end
private
+
# This will be overwritten by _write_layout_method
def _layout(details) end
@@ -171,6 +172,34 @@ module AbstractController
name && _find_layout(name, details)
end
+ # Determine the layout for a given name and details, taking into account
+ # the name type.
+ #
+ # ==== Parameters
+ # name<String|TrueClass|FalseClass|Symbol>:: The name of the template
+ # details<Hash{Symbol => Object}>:: A list of details to restrict
+ # the lookup to. By default, layout lookup is limited to the
+ # formats specified for the current request.
+ def _layout_for_option(name, details)
+ case name
+ when String then _layout_for_name(name, details)
+ when true then _default_layout(details, true)
+ when :default then _default_layout(details, false)
+ when false, nil then nil
+ else
+ raise ArgumentError,
+ "String, true, or false, expected for `layout'; you passed #{name.inspect}"
+ end
+ end
+
+ def _determine_template(options)
+ super
+
+ return unless (options.keys & [:text, :inline, :partial]).empty? || options.key?(:layout)
+ layout = options.key?(:layout) ? options[:layout] : :default
+ options[:_layout] = _layout_for_option(layout, options[:_template].details)
+ end
+
# Take in the name and details and find a Template.
#
# ==== Parameters
diff --git a/actionpack/lib/abstract_controller/localized_cache.rb b/actionpack/lib/abstract_controller/localized_cache.rb
new file mode 100644
index 0000000000..ee7b43cb9f
--- /dev/null
+++ b/actionpack/lib/abstract_controller/localized_cache.rb
@@ -0,0 +1,49 @@
+module AbstractController
+ class HashKey
+ @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
+
+ def self.get(klass, formats, locale)
+ @hash_keys[klass][formats][locale] ||= new(klass, formats, locale)
+ end
+
+ attr_accessor :hash
+ def initialize(klass, formats, locale)
+ @formats, @locale = formats, locale
+ @hash = [formats, locale].hash
+ end
+
+ alias_method :eql?, :equal?
+
+ def inspect
+ "#<HashKey -- formats: #{@formats.inspect} locale: #{@locale.inspect}>"
+ end
+ end
+
+ module LocalizedCache
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def clear_template_caches!
+ ActionView::Partials::PartialRenderer::TEMPLATES.clear
+ template_cache.clear
+ super
+ end
+
+ def template_cache
+ @template_cache ||= Hash.new {|h,k| h[k] = {} }
+ end
+ end
+
+ def render(options)
+ Thread.current[:format_locale_key] = HashKey.get(self.class, formats, I18n.locale)
+ super
+ end
+
+ private
+
+ def with_template_cache(name)
+ self.class.template_cache[Thread.current[:format_locale_key]][name] ||= super
+ end
+
+ end
+end
diff --git a/actionpack/lib/abstract_controller/logger.rb b/actionpack/lib/abstract_controller/logger.rb
index f4d017b8e5..27ba5be45f 100644
--- a/actionpack/lib/abstract_controller/logger.rb
+++ b/actionpack/lib/abstract_controller/logger.rb
@@ -1,4 +1,5 @@
require 'active_support/core_ext/logger'
+require 'active_support/benchmarkable'
module AbstractController
module Logger
@@ -6,22 +7,7 @@ module AbstractController
included do
cattr_accessor :logger
- end
-
- module ClassMethods #:nodoc:
- # Logs a message appending the value measured.
- def log_with_time(message, time, log_level=::Logger::DEBUG)
- return unless logger && logger.level >= log_level
- logger.add(log_level, "#{message} (%.1fms)" % time)
- end
-
- # Silences the logger for the duration of the block.
- def silence
- old_logger_level, logger.level = logger.level, ::Logger::ERROR if logge
- yield
- ensure
- logger.level = old_logger_level if logger
- end
+ extend ActiveSupport::Benchmarkable
end
# A class that allows you to defer expensive processing
@@ -47,7 +33,7 @@ module AbstractController
# Override process_action in the AbstractController::Base
# to log details about the method.
def process_action(action)
- event = ActiveSupport::Orchestra.instrument(:process_action,
+ result = ActiveSupport::Notifications.instrument(:process_action,
:controller => self, :action => action) do
super
end
@@ -56,13 +42,13 @@ module AbstractController
log = DelayedLog.new do
"\n\nProcessing #{self.class.name}\##{action_name} " \
"to #{request.formats} (for #{request_origin}) " \
- "(%.1fms) [#{request.method.to_s.upcase}]" % event.duration
+ "[#{request.method.to_s.upcase}]"
end
logger.info(log)
end
- event.result
+ result
end
private
diff --git a/actionpack/lib/abstract_controller/rendering_controller.rb b/actionpack/lib/abstract_controller/rendering_controller.rb
index bbf941aa32..0aae2b18e9 100644
--- a/actionpack/lib/abstract_controller/rendering_controller.rb
+++ b/actionpack/lib/abstract_controller/rendering_controller.rb
@@ -8,9 +8,7 @@ module AbstractController
included do
attr_internal :formats
-
extlib_inheritable_accessor :_view_paths
-
self._view_paths ||= ActionView::PathSet.new
end
@@ -99,6 +97,7 @@ module AbstractController
end
private
+
# Take in a set of options and determine the template to render
#
# ==== Options
@@ -109,6 +108,18 @@ module AbstractController
# to a directory.
# _partial<TrueClass, FalseClass>:: Whether or not the file to look up is a partial
def _determine_template(options)
+ if options.key?(:text)
+ options[:_template] = ActionView::TextTemplate.new(options[:text], format_for_text)
+ 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]
+ end
+
name = (options[:_template_name] || action_name).to_s
options[:_template] ||= with_template_cache(name) do
@@ -128,6 +139,10 @@ module AbstractController
yield
end
+ def format_for_text
+ Mime[:text]
+ end
+
module ClassMethods
def clear_template_caches!
end