Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Begin unifying the interface between ActionController and ActionView

  • Loading branch information...
commit eb9af20b7cc0e374277cf330bdd404f9daab28ec 1 parent cc0b5fa
Yehuda Katz wycats authored josh committed
Showing with 759 additions and 556 deletions.
  1. +42 −23 actionmailer/lib/action_mailer/base.rb
  2. +22 −4 actionmailer/test/mail_service_test.rb
  3. +2 −0  actionpack/lib/action_controller.rb
  4. +146 −112 actionpack/lib/action_controller/base.rb
  5. +54 −90 actionpack/lib/action_controller/layout.rb
  6. +3 −6 actionpack/lib/action_controller/mime_responds.rb
  7. +8 −6 actionpack/lib/action_controller/mime_type.rb
  8. +25 −10 actionpack/lib/action_controller/request.rb
  9. +6 −4 actionpack/lib/action_controller/rescue.rb
  10. +2 −3 actionpack/lib/action_controller/templates/rescues/diagnostics.erb
  11. +11 −8 actionpack/lib/action_view.rb
  12. +10 −81 actionpack/lib/action_view/base.rb
  13. +3 −3 actionpack/lib/action_view/helpers/prototype_helper.rb
  14. +13 −3 actionpack/lib/action_view/paths.rb
  15. +108 −43 actionpack/lib/action_view/{ → render}/partials.rb
  16. +119 −0 actionpack/lib/action_view/render/rendering.rb
  17. +0 −47 actionpack/lib/action_view/renderable_partial.rb
  18. 0  actionpack/lib/action_view/{template_error.rb → template/error.rb}
  19. 0  actionpack/lib/action_view/{template_handler.rb → template/handler.rb}
  20. +3 −3 actionpack/lib/action_view/{template_handlers.rb → template/handlers.rb}
  21. 0  actionpack/lib/action_view/{template_handlers → template/handlers}/builder.rb
  22. 0  actionpack/lib/action_view/{template_handlers → template/handlers}/erb.rb
  23. +1 −1  actionpack/lib/action_view/{template_handlers → template/handlers}/rjs.rb
  24. 0  actionpack/lib/action_view/{inline_template.rb → template/inline.rb}
  25. +18 −0 actionpack/lib/action_view/template/partial.rb
  26. +7 −29 actionpack/lib/action_view/{ → template}/renderable.rb
  27. +20 −14 actionpack/lib/action_view/{ → template}/template.rb
  28. +8 −11 actionpack/lib/action_view/test_case.rb
  29. +35 −3 actionpack/test/controller/layout_test.rb
  30. +1 −1  actionpack/test/controller/mime_responds_test.rb
  31. +3 −3 actionpack/test/controller/render_test.rb
  32. +1 −1  actionpack/test/controller/view_paths_test.rb
  33. +1 −0  actionpack/test/fixtures/layout_tests/views/goodbye.rhtml
  34. +1 −1  actionpack/test/template/javascript_helper_test.rb
  35. +1 −1  actionpack/test/template/prototype_helper_test.rb
  36. +1 −1  actionpack/test/template/render_test.rb
  37. +1 −0  activesupport/lib/active_support.rb
  38. +8 −8 activesupport/lib/active_support/buffered_logger.rb
  39. +1 −1  activesupport/lib/active_support/callbacks.rb
  40. +26 −0 activesupport/lib/active_support/concurrent_hash.rb
  41. +2 −2 activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
  42. +5 −5 activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
  43. +11 −11 activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
  44. +2 −2 activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
  45. +3 −3 activesupport/lib/active_support/core_ext/proc.rb
  46. +5 −1 activesupport/lib/active_support/core_ext/string/multibyte.rb
  47. +1 −1  activesupport/lib/active_support/deprecation.rb
  48. +1 −1  activesupport/lib/active_support/memoizable.rb
  49. +9 −0 activesupport/lib/active_support/mini.rb
  50. +5 −5 activesupport/lib/active_support/multibyte/unicode_database.rb
  51. +4 −4 activesupport/lib/active_support/time_with_zone.rb
65 actionmailer/lib/action_mailer/base.rb
View
@@ -371,6 +371,14 @@ def mailer_name=(value)
attr_reader :mail
attr_reader :template_name, :default_template_name, :action_name
+ def controller_path
+ self.class.controller_path
+ end
+
+ def formats
+ @template.formats
+ end
+
class << self
attr_writer :mailer_name
@@ -464,7 +472,7 @@ def create!(method_name, *parameters) #:nodoc:
# have not already been specified manually.
if @parts.empty?
Dir.glob("#{template_path}/#{@template}.*").each do |path|
- template = template_root["#{mailer_name}/#{File.basename(path)}"]
+ template = template_root.find_template("#{mailer_name}/#{File.basename(path)}")
# Skip unless template has a multipart format
next unless template && template.multipart?
@@ -473,7 +481,7 @@ def create!(method_name, *parameters) #:nodoc:
:content_type => template.content_type,
:disposition => "inline",
:charset => charset,
- :body => render_message(template, @body)
+ :body => render_template(template, @body)
)
end
unless @parts.empty?
@@ -487,7 +495,7 @@ def create!(method_name, *parameters) #:nodoc:
# normal template exists (or if there were no implicit parts) we render
# it.
template_exists = @parts.empty?
- template_exists ||= template_root["#{mailer_name}/#{@template}"]
+ template_exists ||= template_root.find_template("#{mailer_name}/#{@template}")
@body = render_message(@template, @body) if template_exists
# Finally, if there are other message parts and a textual body exists,
@@ -512,6 +520,7 @@ def create!(method_name, *parameters) #:nodoc:
# no alternate has been given as the parameter, this will fail.
def deliver!(mail = @mail)
raise "no mail object available for delivery!" unless mail
+
unless logger.nil?
logger.info "Sent mail to #{Array(recipients).join(', ')}"
logger.debug "\n#{mail.encoded}"
@@ -543,27 +552,43 @@ def initialize_defaults(method_name)
@mime_version = @@default_mime_version.dup if @@default_mime_version
end
- def render_message(method_name, body)
- if method_name.respond_to?(:content_type)
- @current_template_content_type = method_name.content_type
+ def render_template(template, body)
+ if template.respond_to?(:content_type)
+ @current_template_content_type = template.content_type
end
+
+ @template = initialize_template_class(body)
+ layout = _pick_layout(layout, true) unless template.exempt_from_layout?
+ @template._render_template_with_layout(template, layout, {})
+ ensure
+ @current_template_content_type = nil
+ end
+
+ def render_message(method_name, body)
render :file => method_name, :body => body
ensure
@current_template_content_type = nil
end
def render(opts)
- body = opts.delete(:body)
- if opts[:file] && (opts[:file] !~ /\// && !opts[:file].respond_to?(:render))
- opts[:file] = "#{mailer_name}/#{opts[:file]}"
- end
-
+ layout, file = opts.delete(:layout), opts[:file]
+
begin
- old_template, @template = @template, initialize_template_class(body)
- layout = respond_to?(:pick_layout, true) ? pick_layout(opts) : false
- @template.render(opts.merge(:layout => layout))
- ensure
- @template = old_template
+ @template = initialize_template_class(opts.delete(:body))
+
+ if file
+ prefix = mailer_name unless file =~ /\//
+ template = view_paths.find_by_parts(file, formats, prefix)
+ end
+
+ layout = _pick_layout(layout,
+ !template || !template.exempt_from_layout?)
+
+ if template
+ @template._render_template_with_layout(template, layout, opts)
+ elsif inline = opts[:inline]
+ @template._render_inline(inline, layout, opts)
+ end
end
end
@@ -575,12 +600,6 @@ def default_template_format
end
end
- def candidate_for_layout?(options)
- !self.view_paths.find_template(default_template_name, default_template_format).exempt_from_layout?
- rescue ActionView::MissingTemplate
- return true
- end
-
def template_root
self.class.template_root
end
@@ -595,7 +614,7 @@ def template_path
def initialize_template_class(assigns)
template = ActionView::Base.new(view_paths, assigns, self)
- template.template_format = default_template_format
+ template.formats = [default_template_format]
template
end
26 actionmailer/test/mail_service_test.rb
View
@@ -566,13 +566,31 @@ def test_performs_delivery_via_sendmail
TestMailer.deliver_signed_up(@recipient)
end
+ class FakeLogger
+ attr_reader :info_contents, :debug_contents
+
+ def initialize
+ @info_contents, @debug_contents = "", ""
+ end
+
+ def info(str)
+ @info_contents << str
+ end
+
+ def debug(str)
+ @debug_contents << str
+ end
+ end
+
def test_delivery_logs_sent_mail
mail = TestMailer.create_signed_up(@recipient)
- logger = mock()
- logger.expects(:info).with("Sent mail to #{@recipient}")
- logger.expects(:debug).with("\n#{mail.encoded}")
- TestMailer.logger = logger
+ # logger = mock()
+ # logger.expects(:info).with("Sent mail to #{@recipient}")
+ # logger.expects(:debug).with("\n#{mail.encoded}")
+ TestMailer.logger = FakeLogger.new
TestMailer.deliver_signed_up(@recipient)
+ assert(TestMailer.logger.info_contents =~ /Sent mail to #{@recipient}/)
+ assert_equal(TestMailer.logger.debug_contents, "\n#{mail.encoded}")
end
def test_unquote_quoted_printable_subject
2  actionpack/lib/action_controller.rb
View
@@ -35,6 +35,8 @@
require 'rack'
require 'action_controller/rack_ext'
+require File.join(File.dirname(__FILE__), "action_pack")
+
module ActionController
# TODO: Review explicit to see if they will automatically be handled by
# the initilizer if they are really needed.
258 actionpack/lib/action_controller/base.rb
View
@@ -514,8 +514,8 @@ def filter_parameter_logging(*filter_words, &block)
def process(request, response, method = :perform_action, *arguments) #:nodoc:
response.request = request
- initialize_template_class(response)
assign_shortcuts(request, response)
+ initialize_template_class(response)
initialize_current_url
assign_names
@@ -863,90 +863,82 @@ def append_view_path(path)
def render(options = nil, extra_options = {}, &block) #:doc:
raise DoubleRenderError, "Can only render or redirect once per action" if performed?
- validate_render_arguments(options, extra_options, block_given?)
-
- if options.nil?
- options = { :template => default_template, :layout => true }
- elsif options == :update
- options = extra_options.merge({ :update => true })
- elsif options.is_a?(String) || options.is_a?(Symbol)
- case options.to_s.index('/')
- when 0
- extra_options[:file] = options
- when nil
- extra_options[:action] = options
- else
- extra_options[:template] = options
- end
+ options = { :layout => true } if options.nil?
+ original, options = options, extra_options unless options.is_a?(Hash)
+
+ layout_name = options.delete(:layout)
- options = extra_options
- end
+ _process_options(options)
+
+ if block_given?
+ @template.send(:_evaluate_assigns_and_ivars)
- layout = pick_layout(options)
- response.layout = layout.path_without_format_and_extension if layout
- logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger && layout
-
- if content_type = options[:content_type]
- response.content_type = content_type.to_s
+ generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
+ response.content_type = Mime::JS
+ return render_for_text(generator.to_s)
end
-
- if location = options[:location]
- response.headers["Location"] = url_for(location)
+
+ if original
+ return render_for_name(original, layout_name, options) unless block_given?
+ end
+
+ if options.key?(:text)
+ return render_for_text(@template._render_text(options[:text],
+ _pick_layout(layout_name), options))
end
- if options.has_key?(:text)
- text = layout ? @template.render(options.merge(:text => options[:text], :layout => layout)) : options[:text]
- render_for_text(text, options[:status])
+ file, template = options.values_at(:file, :template)
+ if file || template
+ file = template.sub(/^\//, '') if template
+ return render_for_file(file, [layout_name, !!template], options)
+ end
+
+ if action_option = options[:action]
+ return render_for_action(action_option, [layout_name, true], options)
+ end
+
+ if inline = options[:inline]
+ render_for_text(@template._render_inline(inline, _pick_layout(layout_name), options))
+
+ elsif xml = options[:xml]
+ response.content_type ||= Mime::XML
+ render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml)
+
+ elsif js = options[:js]
+ response.content_type ||= Mime::JS
+ render_for_text(js)
+
+ elsif json = options[:json]
+ json = json.to_json unless json.is_a?(String)
+ json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
+ response.content_type ||= Mime::JSON
+ render_for_text(json)
+
+ elsif partial = options[:partial]
+ if partial == true
+ parts = [action_name_base, formats, controller_name, true]
+ elsif partial.is_a?(String)
+ parts = partial_parts(partial, options)
+ else
+ return render_for_text(@template._render_partial(options))
+ end
+
+ render_for_parts(parts, layout_name, options)
+
+ elsif options[:nothing]
+ render_for_text(nil)
else
- if file = options[:file]
- render_for_file(file, options[:status], layout, options[:locals] || {})
-
- elsif template = options[:template]
- render_for_file(template, options[:status], layout, options[:locals] || {})
-
- elsif inline = options[:inline]
- render_for_text(@template.render(options.merge(:layout => layout)), options[:status])
-
- elsif action_name = options[:action]
- render_for_file(default_template(action_name.to_s), options[:status], layout)
-
- elsif xml = options[:xml]
- response.content_type ||= Mime::XML
- render_for_text(xml.respond_to?(:to_xml) ? xml.to_xml : xml, options[:status])
-
- elsif js = options[:js]
- response.content_type ||= Mime::JS
- render_for_text(js, options[:status])
-
- elsif json = options[:json]
- json = json.to_json unless json.is_a?(String)
- json = "#{options[:callback]}(#{json})" unless options[:callback].blank?
- response.content_type ||= Mime::JSON
- render_for_text(json, options[:status])
-
- elsif options[:partial]
- options[:partial] = default_template_name if options[:partial] == true
- if layout
- render_for_text(@template.render(:text => @template.render(options), :layout => layout), options[:status])
- else
- render_for_text(@template.render(options), options[:status])
- end
-
- elsif options[:update]
- @template.send(:_evaluate_assigns_and_ivars)
-
- generator = ActionView::Helpers::PrototypeHelper::JavaScriptGenerator.new(@template, &block)
- response.content_type = Mime::JS
- render_for_text(generator.to_s, options[:status])
+ render_for_parts([action_name, formats, controller_path], layout_name, options)
+ end
+ end
- elsif options[:nothing]
- render_for_text(nil, options[:status])
+ def formats
+ @_request.formats.map {|f| f.symbol }.compact
+ end
- else
- render_for_file(default_template, options[:status], layout)
- end
- end
+ def action_name_base(name = action_name)
+ (name.is_a?(String) ? name.sub(/^#{controller_path}\//, '') : name).to_s
end
# Renders according to the same rules as <tt>render</tt>, but returns the result in a string instead
@@ -1174,16 +1166,70 @@ def reset_session #:doc:
end
private
- def render_for_file(template_path, status = nil, layout = nil, locals = {}) #:nodoc:
- path = template_path.respond_to?(:path_without_format_and_extension) ? template_path.path_without_format_and_extension : template_path
- logger.info("Rendering #{path}" + (status ? " (#{status})" : '')) if logger
- render_for_text @template.render(:file => template_path, :locals => locals, :layout => layout), status
+ def _process_options(options)
+ if content_type = options[:content_type]
+ response.content_type = content_type.to_s
+ end
+
+ if location = options[:location]
+ response.headers["Location"] = url_for(location)
+ end
+
+ response.status = interpret_status(options[:status] || DEFAULT_RENDER_STATUS_CODE)
end
- def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
- @performed_render = true
+ def render_for_name(name, layout, options)
+ case name.to_s.index('/')
+ when 0
+ render_for_file(name, layout, options)
+ when nil
+ render_for_action(name, layout, options)
+ else
+ render_for_file(name.sub(/^\//, ''), [layout, true], options)
+ end
+ end
+
+ def render_for_parts(parts, layout, options = {})
+ tmp = view_paths.find_by_parts(*parts)
+ layout = _pick_layout(*layout) unless tmp.exempt_from_layout?
+
+ render_for_text(
+ @template._render_template_with_layout(tmp, layout, options, parts[3]))
+ end
+
+ def partial_parts(name, options)
+ segments = name.split("/")
+ parts = segments.pop.split(".")
+
+ case parts.size
+ when 1
+ parts
+ when 2, 3
+ extension = parts.delete_at(1).to_sym
+ if formats.include?(extension)
+ self.formats.replace [extension]
+ end
+ parts.pop if parts.size == 2
+ end
- response.status = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
+ path = parts.join(".")
+ prefix = segments[0..-1].join("/")
+ prefix = prefix.blank? ? controller_path : prefix
+ parts = [path, formats, prefix]
+ parts.push options[:object] || true
+ end
+
+ def render_for_file(file, layout, options)
+ render_for_parts([file, [request.format.to_sym]], layout, options)
+ end
+
+ def render_for_action(name, layout, options)
+ parts = [action_name_base(name), formats, controller_name]
+ render_for_parts(parts, layout, options)
+ end
+
+ def render_for_text(text = nil, append_response = false) #:nodoc:
+ @performed_render = true
if append_response
response.body ||= ''
@@ -1197,18 +1243,8 @@ def render_for_text(text = nil, status = nil, append_response = false) #:nodoc:
end
end
- def validate_render_arguments(options, extra_options, has_block)
- if options && (has_block && options != :update) && !options.is_a?(String) && !options.is_a?(Hash) && !options.is_a?(Symbol)
- raise RenderError, "You called render with invalid options : #{options.inspect}"
- end
-
- if !extra_options.is_a?(Hash)
- raise RenderError, "You called render with invalid options : #{options.inspect}, #{extra_options.inspect}"
- end
- end
-
def initialize_template_class(response)
- response.template = ActionView::Base.new(self.class.view_paths, {}, self)
+ @template = response.template = ActionView::Base.new(self.class.view_paths, {}, self, formats)
response.template.helpers.send :include, self.class.master_helper_module
response.redirected_to = nil
@performed_render = @performed_redirect = false
@@ -1221,7 +1257,6 @@ def assign_shortcuts(request, response)
@_response.session = request.session
@_session = @_response.session
- @template = @_response.template
@_headers = @_response.headers
end
@@ -1257,23 +1292,21 @@ def default_render #:nodoc:
end
def perform_action
- if action_methods.include?(action_name)
- send(action_name)
- default_render unless performed?
- elsif respond_to? :method_missing
- method_missing action_name
- default_render unless performed?
- else
- begin
- default_render
- rescue ActionView::MissingTemplate => e
- # Was the implicit template missing, or was it another template?
- if e.path == default_template_name
- raise UnknownAction, "No action responded to #{action_name}. Actions: #{action_methods.sort.to_sentence}", caller
- else
- raise e
- end
- end
+ if called = action_methods.include?(action_name)
+ ret = send(action_name)
+ elsif called = respond_to?(:method_missing)
+ ret = method_missing(action_name)
+ end
+
+ return (performed? ? ret : default_render) if called
+
+ begin
+ default_render
+ rescue ActionView::MissingTemplate => e
+ raise e unless e.path == action_name
+ # If the path is the same as the action_name, the action is completely missing
+ raise UnknownAction, "No action responded to #{action_name}. Actions: " +
+ "#{action_methods.sort.to_sentence}", caller
end
end
@@ -1337,6 +1370,7 @@ def strip_out_controller(path)
path.split('/', 2).last
end
+
def template_path_includes_controller?(path)
self.controller_path.split('/')[-1] == path.split('/')[0]
end
144 actionpack/lib/action_controller/layout.rb
View
@@ -2,11 +2,7 @@ module ActionController #:nodoc:
module Layout #:nodoc:
def self.included(base)
base.extend(ClassMethods)
- base.class_eval do
- class << self
- alias_method_chain :inherited, :layout
- end
- end
+ base.class_inheritable_accessor :layout_name, :layout_conditions
end
# Layouts reverse the common pattern of including shared headers and footers in many templates to isolate changes in
@@ -159,122 +155,90 @@ class << self
#
# This will render the help action with the "help" layout instead of the controller-wide "weblog_standard" layout.
module ClassMethods
+ extend ActiveSupport::Memoizable
+
# If a layout is specified, all rendered actions will have their result rendered
# when the layout <tt>yield</tt>s. This layout can itself depend on instance variables assigned during action
# performance and have access to them as any normal template would.
def layout(template_name, conditions = {}, auto = false)
add_layout_conditions(conditions)
- write_inheritable_attribute(:layout, template_name)
- write_inheritable_attribute(:auto_layout, auto)
+ self.layout_name = template_name
end
- def layout_conditions #:nodoc:
- @layout_conditions ||= read_inheritable_attribute(:layout_conditions)
+ def memoized_default_layout(formats) #:nodoc:
+ self.layout_name || begin
+ layout = default_layout_name
+ layout.is_a?(String) ? find_layout(layout, formats) : layout
+ rescue ActionView::MissingTemplate
+ end
end
- def default_layout(format) #:nodoc:
- layout = read_inheritable_attribute(:layout)
- return layout unless read_inheritable_attribute(:auto_layout)
- find_layout(layout, format)
+ def default_layout(*args)
+ (@_memoized_default_layout ||= ::ActiveSupport::ConcurrentHash.new)[args] ||= memoized_default_layout(*args)
+ end
+
+ def memoized_find_layout(layout, formats) #:nodoc:
+ return layout if layout.nil? || layout.respond_to?(:render)
+ prefix = layout.to_s =~ /layouts\// ? nil : "layouts"
+ view_paths.find_by_parts(layout.to_s, formats, prefix)
+ end
+
+ def find_layout(*args)
+ (@_memoized_find_layout ||= ::ActiveSupport::ConcurrentHash.new)[args] ||= memoized_find_layout(*args)
end
def layout_list #:nodoc:
Array(view_paths).sum([]) { |path| Dir["#{path}/layouts/**/*"] }
end
+ memoize :layout_list
- def find_layout(layout, *formats) #:nodoc:
- return layout if layout.respond_to?(:render)
- view_paths.find_template(layout.to_s =~ /layouts\// ? layout : "layouts/#{layout}", *formats)
- rescue ActionView::MissingTemplate
- nil
+ def default_layout_name
+ layout_match = name.underscore.sub(/_controller$/, '')
+ if layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
+ superclass.default_layout_name if superclass.respond_to?(:default_layout_name)
+ else
+ layout_match
+ end
end
+ memoize :default_layout_name
private
- def inherited_with_layout(child)
- inherited_without_layout(child)
- unless child.name.blank?
- layout_match = child.name.underscore.sub(/_controller$/, '').sub(/^controllers\//, '')
- child.layout(layout_match, {}, true) unless child.layout_list.grep(%r{layouts/#{layout_match}(\.[a-z][0-9a-z]*)+$}).empty?
- end
- end
-
def add_layout_conditions(conditions)
- write_inheritable_hash(:layout_conditions, normalize_conditions(conditions))
- end
-
- def normalize_conditions(conditions)
- conditions.inject({}) {|hash, (key, value)| hash.merge(key => [value].flatten.map {|action| action.to_s})}
+ # :except => :foo == :except => [:foo] == :except => "foo" == :except => ["foo"]
+ conditions.each {|k, v| conditions[k] = Array(v).map {|a| a.to_s} }
+ write_inheritable_hash(:layout_conditions, conditions)
end
end
-
- # Returns the name of the active layout. If the layout was specified as a method reference (through a symbol), this method
- # is called and the return value is used. Likewise if the layout was specified as an inline method (through a proc or method
- # object). If the layout was defined without a directory, layouts is assumed. So <tt>layout "weblog/standard"</tt> will return
- # weblog/standard, but <tt>layout "standard"</tt> will return layouts/standard.
- def active_layout(passed_layout = nil)
- layout = passed_layout || self.class.default_layout(default_template_format)
-
- active_layout = case layout
- when Symbol then __send__(layout)
- when Proc then layout.call(self)
- else layout
+
+ def active_layout(name)
+ name = self.class.default_layout(formats) if name == true
+
+ layout_name = case name
+ when Symbol then __send__(name)
+ when Proc then name.call(self)
+ else name
end
- if active_layout
- if layout = self.class.find_layout(active_layout, @template.template_format)
- layout
- else
- raise ActionView::MissingTemplate.new(self.class.view_paths, active_layout)
- end
- end
+ self.class.find_layout(layout_name, formats)
end
- private
- def candidate_for_layout?(options)
- template = options[:template] || default_template(options[:action])
- if options.values_at(:text, :xml, :json, :file, :inline, :partial, :nothing, :update).compact.empty?
- begin
- !self.view_paths.find_template(template, default_template_format).exempt_from_layout?
- rescue ActionView::MissingTemplate
- true
- end
- end
- rescue ActionView::MissingTemplate
- false
- end
-
- def pick_layout(options)
- if options.has_key?(:layout)
- case layout = options.delete(:layout)
- when FalseClass
- nil
- when NilClass, TrueClass
- active_layout if action_has_layout? && candidate_for_layout?(:template => default_template_name)
- else
- active_layout(layout)
- end
- else
- active_layout if action_has_layout? && candidate_for_layout?(options)
- end
- end
+ def _pick_layout(layout_name, implicit = false)
+ return unless layout_name || implicit
+ layout_name = true if layout_name.nil?
+ active_layout(layout_name) if action_has_layout? && layout_name
+ end
+ private
def action_has_layout?
if conditions = self.class.layout_conditions
- case
- when only = conditions[:only]
- only.include?(action_name)
- when except = conditions[:except]
- !except.include?(action_name)
- else
- true
+ if only = conditions[:only]
+ return only.include?(action_name)
+ elsif except = conditions[:except]
+ return !except.include?(action_name)
end
- else
- true
end
+ true
end
- def default_template_format
- response.template.template_format
- end
end
end
9 actionpack/lib/action_controller/mime_responds.rb
View
@@ -109,16 +109,13 @@ def respond_to(*types, &block)
end
class Responder #:nodoc:
+
def initialize(controller)
@controller = controller
@request = controller.request
@response = controller.response
- if ActionController::Base.use_accept_header
- @mime_type_priority = Array(Mime::Type.lookup_by_extension(@request.parameters[:format]) || @request.accepts)
- else
- @mime_type_priority = [@request.format]
- end
+ @mime_type_priority = @request.formats
@order = []
@responses = {}
@@ -130,7 +127,7 @@ def custom(mime_type, &block)
@order << mime_type
@responses[mime_type] ||= Proc.new do
- @response.template.template_format = mime_type.to_sym
+ @response.template.formats = [mime_type.to_sym]
@response.content_type = mime_type.to_s
block_given? ? block.call : @controller.send(:render, :action => @controller.action_name)
end
14 actionpack/lib/action_controller/mime_type.rb
View
@@ -5,6 +5,10 @@ module Mime
EXTENSION_LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
LOOKUP = Hash.new { |h, k| h[k] = Type.new(k) unless k.blank? }
+ def self.[](type)
+ Type.lookup_by_extension(type.to_s)
+ end
+
# Encapsulates the notion of a mime type. Can be used at render time, for example, with:
#
# class PostsController < ActionController::Base
@@ -27,7 +31,7 @@ class Type
# only needs to protect against these types.
@@browser_generated_types = Set.new [:html, :url_encoded_form, :multipart_form, :text]
cattr_reader :browser_generated_types
-
+ attr_reader :symbol
@@unverifiable_types = Set.new [:text, :json, :csv, :xml, :rss, :atom, :yaml]
def self.unverifiable_types
@@ -172,6 +176,8 @@ def ===(list)
def ==(mime_type)
return false if mime_type.blank?
(@synonyms + [ self ]).any? do |synonym|
+ require "ruby-debug"
+ debugger if mime_type.is_a?(Array)
synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
end
end
@@ -187,17 +193,13 @@ def =~(mime_type)
# Returns true if Action Pack should check requests using this Mime Type for possible request forgery. See
# ActionController::RequestForgeryProtection.
def verify_request?
- browser_generated?
+ @@browser_generated_types.include?(to_sym)
end
def html?
@@html_types.include?(to_sym) || @string =~ /html/
end
- def browser_generated?
- @@browser_generated_types.include?(to_sym)
- end
-
private
def method_missing(method, *args)
if method.to_s =~ /(\w+)\?$/
35 actionpack/lib/action_controller/request.rb
View
@@ -101,10 +101,16 @@ def content_type
def accepts
header = @env['HTTP_ACCEPT'].to_s.strip
+ fallback = xhr? ? Mime::JS : Mime::HTML
+
if header.empty?
- [content_type, Mime::ALL].compact
+ [content_type, fallback, Mime::ALL].compact
else
- Mime::Type.parse(header)
+ ret = Mime::Type.parse(header)
+ if ret.last == Mime::ALL
+ ret.insert(-2, fallback)
+ end
+ ret
end
end
memoize :accepts
@@ -144,24 +150,33 @@ def fresh?(response)
end
end
+ ONLY_ALL = [Mime::ALL].freeze
+
# Returns the Mime type for the \format used in the request.
#
# GET /posts/5.xml | request.format => Mime::XML
# GET /posts/5.xhtml | request.format => Mime::HTML
# GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
- def format
+
+ def format(view_path = [])
@format ||=
if parameters[:format]
- Mime::Type.lookup_by_extension(parameters[:format])
- elsif ActionController::Base.use_accept_header
- accepts.first
- elsif xhr?
- Mime::Type.lookup_by_extension("js")
- else
- Mime::Type.lookup_by_extension("html")
+ Mime[parameters[:format]]
+ elsif Base.use_accept_header && !(accepts == ONLY_ALL)
+ accepts.first
+ elsif xhr? then Mime::JS
+ else Mime::HTML
end
end
+ def formats
+ @formats =
+ if Base.use_accept_header
+ ret = Array(Mime[parameters[:format]] || accepts)
+ else
+ [format]
+ end
+ end
# Sets the \format by string extension, which can be used to force custom formats
# that are not controlled by the extension.
10 actionpack/lib/action_controller/rescue.rb
View
@@ -125,11 +125,13 @@ def rescue_action_locally(exception)
@template.instance_variable_set("@exception", exception)
@template.instance_variable_set("@rescues_path", RESCUES_TEMPLATE_PATH)
@template.instance_variable_set("@contents",
- @template.render(:file => template_path_for_local_rescue(exception)))
+ @template._render_template(template_path_for_local_rescue(exception)))
response.content_type = Mime::HTML
- render_for_file(rescues_path("layout"),
- response_code_for_rescue(exception))
+ response.status = interpret_status(response_code_for_rescue(exception))
+
+ content = @template._render_template(rescues_path("layout"))
+ render_for_text(content)
end
def rescue_action_without_handler(exception)
@@ -157,7 +159,7 @@ def perform_action_with_rescue #:nodoc:
end
def rescues_path(template_name)
- RESCUES_TEMPLATE_PATH["rescues/#{template_name}.erb"]
+ RESCUES_TEMPLATE_PATH.find_template("rescues/#{template_name}.erb")
end
def template_path_for_local_rescue(exception)
5 actionpack/lib/action_controller/templates/rescues/diagnostics.erb
View
@@ -6,6 +6,5 @@
</h1>
<pre><%=h @exception.clean_message %></pre>
-<%= render :file => @rescues_path["rescues/_trace.erb"] %>
-
-<%= render :file => @rescues_path["rescues/_request_and_response.erb"] %>
+<%= @template._render_template(@rescues_path.find_template("rescues/_trace.erb")) %>
+<%= @template._render_template(@rescues_path.find_template("rescues/_request_and_response.erb")) %>
19 actionpack/lib/action_view.rb
View
@@ -31,6 +31,8 @@
end
end
+require File.join(File.dirname(__FILE__), "action_pack")
+
module ActionView
def self.load_all!
[Base, InlineTemplate, TemplateError]
@@ -38,15 +40,16 @@ def self.load_all!
autoload :Base, 'action_view/base'
autoload :Helpers, 'action_view/helpers'
- autoload :InlineTemplate, 'action_view/inline_template'
- autoload :Partials, 'action_view/partials'
+ autoload :InlineTemplate, 'action_view/template/inline'
+ autoload :Partials, 'action_view/render/partials'
autoload :PathSet, 'action_view/paths'
- autoload :Renderable, 'action_view/renderable'
- autoload :RenderablePartial, 'action_view/renderable_partial'
- autoload :Template, 'action_view/template'
- autoload :TemplateError, 'action_view/template_error'
- autoload :TemplateHandler, 'action_view/template_handler'
- autoload :TemplateHandlers, 'action_view/template_handlers'
+ autoload :Rendering, 'action_view/render/rendering'
+ autoload :Renderable, 'action_view/template/renderable'
+ autoload :RenderablePartial, 'action_view/template/partial'
+ autoload :Template, 'action_view/template/template'
+ autoload :TemplateError, 'action_view/template/error'
+ autoload :TemplateHandler, 'action_view/template/handler'
+ autoload :TemplateHandlers, 'action_view/template/handlers'
autoload :Helpers, 'action_view/helpers'
end
91 actionpack/lib/action_view/base.rb
View
@@ -160,14 +160,13 @@ def initialize(paths, path, template_format = nil)
#
# See the ActionView::Helpers::PrototypeHelper::GeneratorMethods documentation for more details.
class Base
- include Helpers, Partials, ::ERB::Util
+ include Helpers, Rendering, Partials, ::ERB::Util
+
extend ActiveSupport::Memoizable
- attr_accessor :base_path, :assigns, :template_extension
+ attr_accessor :base_path, :assigns, :template_extension, :formats
attr_accessor :controller
- attr_writer :template_format
-
attr_accessor :output_buffer
class << self
@@ -184,9 +183,13 @@ class << self
attr_internal :request
+ delegate :controller_path, :to => :controller, :allow_nil => true
+
delegate :request_forgery_protection_token, :template, :params, :session, :cookies, :response, :headers,
:flash, :logger, :action_name, :controller_name, :to => :controller
+ delegate :find_by_parts, :to => :view_paths
+
module CompiledTemplates #:nodoc:
# holds compiled template code
end
@@ -209,7 +212,8 @@ def include(*args)
end
end
- def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)#:nodoc:
+ def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc:
+ @formats = formats || [:html]
@assigns = assigns_for_first_render
@assigns_added = nil
@_render_stack = []
@@ -223,55 +227,7 @@ def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil)
def view_paths=(paths)
@view_paths = self.class.process_view_paths(paths)
end
-
- # Returns the result of a render that's dictated by the options hash. The primary options are:
- #
- # * <tt>:partial</tt> - See ActionView::Partials.
- # * <tt>:update</tt> - Calls update_page with the block given.
- # * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
- # * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
- # * <tt>:text</tt> - Renders the text passed in out.
- #
- # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
- # as the locals hash.
- def render(options = {}, local_assigns = {}, &block) #:nodoc:
- local_assigns ||= {}
-
- case options
- when Hash
- options = options.reverse_merge(:locals => {})
- if options[:layout]
- _render_with_layout(options, local_assigns, &block)
- elsif options[:file]
- tempalte = self.view_paths.find_template(options[:file], template_format)
- tempalte.render_template(self, options[:locals])
- elsif options[:partial]
- render_partial(options)
- elsif options[:inline]
- InlineTemplate.new(options[:inline], options[:type]).render(self, options[:locals])
- elsif options[:text]
- options[:text]
- end
- when :update
- update_page(&block)
- else
- render_partial(:partial => options, :locals => local_assigns)
- end
- end
-
- # The format to be used when choosing between multiple templates with
- # the same name but differing formats. See +Request#template_format+
- # for more details.
- def template_format
- if defined? @template_format
- @template_format
- elsif controller && controller.respond_to?(:request)
- @template_format = controller.request.template_format.to_sym
- else
- @template_format = :html
- end
- end
-
+
# Access the current template being rendered.
# Returns a ActionView::Template object.
def template
@@ -301,32 +257,5 @@ def _set_controller_content_type(content_type) #:nodoc:
controller.response.content_type ||= content_type
end
end
-
- def _render_with_layout(options, local_assigns, &block) #:nodoc:
- partial_layout = options.delete(:layout)
-
- if block_given?
- begin
- @_proc_for_layout = block
- concat(render(options.merge(:partial => partial_layout)))
- ensure
- @_proc_for_layout = nil
- end
- else
- begin
- original_content_for_layout = @content_for_layout if defined?(@content_for_layout)
- @content_for_layout = render(options)
-
- if (options[:inline] || options[:file] || options[:text])
- @cached_content_for_layout = @content_for_layout
- render(:file => partial_layout, :locals => local_assigns)
- else
- render(options.merge(:partial => partial_layout))
- end
- ensure
- @content_for_layout = original_content_for_layout
- end
- end
- end
end
end
6 actionpack/lib/action_view/helpers/prototype_helper.rb
View
@@ -987,13 +987,13 @@ def record(line)
end
def render(*options_for_render)
- old_format = @context && @context.template_format
- @context.template_format = :html if @context
+ old_formats = @context && @context.formats
+ @context.formats = [:html] if @context
Hash === options_for_render.first ?
@context.render(*options_for_render) :
options_for_render.first.to_s
ensure
- @context.template_format = old_format if @context
+ @context.formats = old_formats if @context
end
def javascript_object_for(object)
16 actionpack/lib/action_view/paths.rb
View
@@ -32,14 +32,24 @@ def unshift(*objs)
super(*objs.map { |obj| self.class.type_cast(obj) })
end
+ def find_by_parts(path, extension = nil, prefix = nil, partial = false)
+ template_path = path.sub(/^\//, '')
+
+ each do |load_path|
+ if template = load_path.find_by_parts(template_path, extension, prefix, partial)
+ return template
+ end
+ end
+
+ Template.new(path, self)
+ end
+
def find_template(original_template_path, format = nil)
return original_template_path if original_template_path.respond_to?(:render)
template_path = original_template_path.sub(/^\//, '')
each do |load_path|
- if format && (template = load_path["#{template_path}.#{format}"])
- return template
- elsif template = load_path[template_path]
+ if template = load_path.find_by_parts(template_path, format)
return template
end
end
151 actionpack/lib/action_view/partials.rb → actionpack/lib/action_view/render/partials.rb
View
@@ -172,63 +172,128 @@ module ActionView
module Partials
extend ActiveSupport::Memoizable
+ def _render_partial(options = {}) #:nodoc:
+ options[:locals] ||= {}
+
+ case path = partial = options[:partial]
+ when *_array_like_objects
+ return _render_partial_collection(partial, options)
+ else
+ if partial.is_a?(ActionView::Helpers::FormBuilder)
+ path = partial.class.to_s.demodulize.underscore.sub(/_builder$/, '')
+ options[:locals].merge!(path.to_sym => partial)
+ elsif !partial.is_a?(String)
+ options[:object] = object = partial
+ path = ActionController::RecordIdentifier.partial_path(object, controller_path)
+ end
+ _, _, prefix, object = parts = partial_parts(path, options)
+ template = find_by_parts(*parts)
+ _render_partial_object(template, options, (object unless object == true))
+ end
+ end
+
private
- def render_partial(options = {}) #:nodoc:
- local_assigns = options[:locals] || {}
+ def partial_parts(name, options)
+ segments = name.split("/")
+ parts = segments.pop.split(".")
- case partial_path = options[:partial]
- when String, Symbol, NilClass
- if options.has_key?(:collection)
- render_partial_collection(options)
- else
- _pick_partial_template(partial_path).render_partial(self, options[:object], local_assigns)
+ case parts.size
+ when 1
+ parts
+ when 2, 3
+ extension = parts.delete_at(1).to_sym
+ if formats.include?(extension)
+ self.formats.replace [extension]
end
- when ActionView::Helpers::FormBuilder
- builder_partial_path = partial_path.class.to_s.demodulize.underscore.sub(/_builder$/, '')
- local_assigns.merge!(builder_partial_path.to_sym => partial_path)
- render_partial(:partial => builder_partial_path, :object => options[:object], :locals => local_assigns)
- when Array, ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope
- render_partial_collection(options.except(:partial).merge(:collection => partial_path))
+ parts.pop if parts.size == 2
+ end
+
+ path = parts.join(".")
+ prefix = segments[0..-1].join("/")
+ prefix = prefix.blank? ? controller_path : prefix
+ parts = [path, formats, prefix]
+ parts.push options[:object] || true
+ end
+
+ def _render_partial_with_block(layout, block, options)
+ @_proc_for_layout = block
+ concat(_render_partial(options.merge(:partial => layout)))
+ ensure
+ @_proc_for_layout = nil
+ end
+
+ def _render_partial_with_layout(layout, options)
+ if layout
+ prefix = controller && !layout.include?("/") ? controller.controller_path : nil
+ layout = find_by_parts(layout, formats, prefix, true)
+ end
+ content = _render_partial(options)
+ return _render_content_with_layout(content, layout, options[:locals])
+ end
+
+ def _deprecated_ivar_assign(template)
+ if respond_to?(:controller)
+ ivar = :"@#{template.variable_name}"
+ object =
+ if controller.instance_variable_defined?(ivar)
+ ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
+ controller.instance_variable_get(ivar),
+ "#{ivar} will no longer be implicitly assigned to #{template.variable_name}")
+ end
+ end
+ end
+
+ def _array_like_objects
+ array_like = [Array]
+ if defined?(ActiveRecord)
+ array_like.push(ActiveRecord::Associations::AssociationCollection, ActiveRecord::NamedScope::Scope)
+ end
+ array_like
+ end
+
+ def _render_partial_object(template, options, object = nil)
+ if options.key?(:collection)
+ _render_partial_collection(options.delete(:collection), options, template)
else
- object = partial_path
- render_partial(
- :partial => ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path),
- :object => object,
- :locals => local_assigns
- )
+ locals = (options[:locals] ||= {})
+ object ||= locals[:object] || locals[template.variable_name]
+
+ _set_locals(object, locals, template, options)
+ _render_template(template, locals)
end
end
- def render_partial_collection(options = {}) #:nodoc:
- return nil if options[:collection].blank?
+ def _set_locals(object, locals, template, options)
+ object ||= _deprecated_ivar_assign(template)
+ locals[:object] = locals[template.variable_name] = object
+ locals[options[:as]] = object if options[:as]
+ end
- partial = options[:partial]
- spacer = options[:spacer_template] ? render(:partial => options[:spacer_template]) : ''
- local_assigns = options[:locals] ? options[:locals].clone : {}
- as = options[:as]
+ def _render_partial_collection(collection, options = {}, passed_template = nil) #:nodoc:
+ return nil if collection.blank?
+
+ spacer = options[:spacer_template] ? _render_partial(:partial => options[:spacer_template]) : ''
- index = 0
- options[:collection].map do |object|
- _partial_path ||= partial ||
- ActionController::RecordIdentifier.partial_path(object, controller.class.controller_path)
- template = _pick_partial_template(_partial_path)
- local_assigns[template.counter_name] = index
- result = template.render_partial(self, object, local_assigns.dup, as)
+ locals = (options[:locals] ||= {})
+ index, @_partial_path = 0, nil
+ collection.map do |object|
+ template = passed_template || begin
+ _partial_path =
+ ActionController::RecordIdentifier.partial_path(object, controller_path)
+ template = _pick_partial_template(_partial_path)
+ end
+
+ _set_locals(object, locals, template, options)
+ locals[template.counter_name] = index
+
index += 1
- result
+ _render_template(template, locals)
end.join(spacer)
end
def _pick_partial_template(partial_path) #:nodoc:
- if partial_path.include?('/')
- path = File.join(File.dirname(partial_path), "_#{File.basename(partial_path)}")
- elsif controller
- path = "#{controller.class.controller_path}/_#{partial_path}"
- else
- path = "_#{partial_path}"
- end
-
- self.view_paths.find_template(path, self.template_format)
+ prefix = controller_path unless partial_path.include?('/')
+ find_by_parts(partial_path, formats, prefix, true)
end
memoize :_pick_partial_template
end
119 actionpack/lib/action_view/render/rendering.rb
View
@@ -0,0 +1,119 @@
+module ActionView
+ module Rendering
+ # Returns the result of a render that's dictated by the options hash. The primary options are:
+ #
+ # * <tt>:partial</tt> - See ActionView::Partials.
+ # * <tt>:update</tt> - Calls update_page with the block given.
+ # * <tt>:file</tt> - Renders an explicit template file (this used to be the old default), add :locals to pass in those.
+ # * <tt>:inline</tt> - Renders an inline template similar to how it's done in the controller.
+ # * <tt>:text</tt> - Renders the text passed in out.
+ #
+ # If no options hash is passed or :update specified, the default is to render a partial and use the second parameter
+ # as the locals hash.
+ def render(options = {}, local_assigns = {}, &block) #:nodoc:
+ local_assigns ||= {}
+
+ @exempt_from_layout = true
+
+ case options
+ when Hash
+ options[:locals] ||= {}
+ layout = options[:layout]
+
+ return _render_partial_with_layout(layout, options) if options.key?(:partial)
+ return _render_partial_with_block(layout, block, options) if block_given?
+
+ layout = find_by_parts(layout, formats) if layout
+
+ if file = options[:file]
+ template = find_by_parts(file, formats)
+ _render_template_with_layout(template, layout, :locals => options[:locals])
+ elsif inline = options[:inline]
+ _render_inline(inline, layout, options)
+ elsif text = options[:text]
+ _render_text(text, layout, options)
+ end
+ when :update
+ update_page(&block)
+ when String, NilClass
+ _render_partial(:partial => options, :locals => local_assigns)
+ end
+ end
+
+ def _render_content_with_layout(content, layout, locals)
+ return content unless layout
+
+ locals ||= {}
+
+ if controller && layout
+ response.layout = layout.path_without_format_and_extension if controller.respond_to?(:response)
+ logger.info("Rendering template within #{layout.path_without_format_and_extension}") if logger
+ end
+
+ begin
+ original_content_for_layout = @content_for_layout if defined?(@content_for_layout)
+ @content_for_layout = content
+
+ @cached_content_for_layout = @content_for_layout
+ _render_template(layout, locals)
+ ensure
+ @content_for_layout = original_content_for_layout
+ end
+ end
+
+ def _render_template(template, local_assigns = {})
+ template.compile(local_assigns)
+
+ @_render_stack.push(template)
+
+ _evaluate_assigns_and_ivars
+ _set_controller_content_type(template.mime_type) if template.respond_to?(:mime_type)
+
+ result = send(template.method_name(local_assigns), local_assigns) do |*names|
+ if !instance_variable_defined?(:"@content_for_#{names.first}") &&
+ instance_variable_defined?(:@_proc_for_layout) && (proc = @_proc_for_layout)
+ capture(*names, &proc)
+ elsif instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
+ instance_variable_get(ivar)
+ end
+ end
+
+ @_render_stack.pop
+ result
+ rescue Exception => e
+ raise e if !template.filename || template.is_a?(InlineTemplate)
+ if TemplateError === e
+ e.sub_template_of(template)
+ raise e
+ else
+ raise TemplateError.new(template, assigns, e)
+ end
+ end
+
+ def _render_inline(inline, layout, options)
+ content = _render_template(InlineTemplate.new(options[:inline], options[:type]), options[:locals] || {})
+ layout ? _render_content_with_layout(content, layout, options[:locals]) : content
+ end
+
+ def _render_text(text, layout, options)
+ layout ? _render_content_with_layout(text, layout, options[:locals]) : text
+ end
+
+ def _render_template_with_layout(template, layout = nil, options = {}, partial = false)
+ if controller && logger
+ logger.info("Rendering #{template.path_without_extension}" +
+ (options[:status] ? " (#{options[:status]})" : ''))
+ end
+
+ content = if partial
+ object = partial unless partial == true
+ _render_partial_object(template, options, object)
+ else
+ _render_template(template, options[:locals] || {})
+ end
+
+ return content unless layout && !template.exempt_from_layout?
+ _render_content_with_layout(content, layout, options[:locals] || {})
+ end
+ end
+end
47 actionpack/lib/action_view/renderable_partial.rb
View
@@ -1,47 +0,0 @@
-module ActionView
- # NOTE: The template that this mixin is being included into is frozen
- # so you cannot set or modify any instance variables
- module RenderablePartial #:nodoc:
- extend ActiveSupport::Memoizable
-
- def variable_name
- name.sub(/\A_/, '').to_sym
- end
- memoize :variable_name
-
- def counter_name
- "#{variable_name}_counter".to_sym
- end
- memoize :counter_name
-
- def render(view, local_assigns = {})
- if defined? ActionController
- ActionController::Base.benchmark("Rendered #{path_without_format_and_extension}", Logger::DEBUG, false) do
- super
- end
- else
- super
- end
- end
-
- def render_partial(view, object = nil, local_assigns = {}, as = nil)
- object ||= local_assigns[:object] || local_assigns[variable_name]
-
- if object.nil? && view.respond_to?(:controller)
- ivar = :"@#{variable_name}"
- object =
- if view.controller.instance_variable_defined?(ivar)
- ActiveSupport::Deprecation::DeprecatedObjectProxy.new(
- view.controller.instance_variable_get(ivar),
- "#{ivar} will no longer be implicitly assigned to #{variable_name}")
- end
- end
-
- # Ensure correct object is reassigned to other accessors
- local_assigns[:object] = local_assigns[variable_name] = object
- local_assigns[as] = object if as
-
- render_template(view, local_assigns)
- end
- end
-end
0  actionpack/lib/action_view/template_error.rb → actionpack/lib/action_view/template/error.rb
View
File renamed without changes
0  actionpack/lib/action_view/template_handler.rb → actionpack/lib/action_view/template/handler.rb
View
File renamed without changes
6 actionpack/lib/action_view/template_handlers.rb → actionpack/lib/action_view/template/handlers.rb
View
@@ -1,8 +1,8 @@
module ActionView #:nodoc:
module TemplateHandlers #:nodoc:
- autoload :ERB, 'action_view/template_handlers/erb'
- autoload :RJS, 'action_view/template_handlers/rjs'
- autoload :Builder, 'action_view/template_handlers/builder'
+ autoload :ERB, 'action_view/template/handlers/erb'
+ autoload :RJS, 'action_view/template/handlers/rjs'
+ autoload :Builder, 'action_view/template/handlers/builder'
def self.extended(base)
base.register_default_template_handler :erb, TemplateHandlers::ERB
0  ...pack/lib/action_view/template_handlers/builder.rb → ...pack/lib/action_view/template/handlers/builder.rb
View
File renamed without changes
0  actionpack/lib/action_view/template_handlers/erb.rb → actionpack/lib/action_view/template/handlers/erb.rb
View
File renamed without changes
2  actionpack/lib/action_view/template_handlers/rjs.rb → actionpack/lib/action_view/template/handlers/rjs.rb
View
@@ -4,7 +4,7 @@ class RJS < TemplateHandler
include Compilable
def compile(template)
- "@template_format = :html;" +
+ "@formats = [:html];" +
"controller.response.content_type ||= Mime::JS;" +
"update_page do |page|;#{template.source}\nend"
end
0  actionpack/lib/action_view/inline_template.rb → actionpack/lib/action_view/template/inline.rb
View
File renamed without changes
18 actionpack/lib/action_view/template/partial.rb
View
@@ -0,0 +1,18 @@
+module ActionView
+ # NOTE: The template that this mixin is being included into is frozen
+ # so you cannot set or modify any instance variables
+ module RenderablePartial #:nodoc:
+ extend ActiveSupport::Memoizable
+
+ def variable_name
+ name.sub(/\A_/, '').to_sym
+ end
+ memoize :variable_name
+
+ def counter_name
+ "#{variable_name}_counter".to_sym
+ end
+ memoize :counter_name
+
+ end
+end
36 actionpack/lib/action_view/renderable.rb → actionpack/lib/action_view/template/renderable.rb
View
@@ -23,28 +23,6 @@ def method_name_without_locals
end
memoize :method_name_without_locals
- def render(view, local_assigns = {})
- compile(local_assigns)
-
- stack = view.instance_variable_get(:@_render_stack)
- stack.push(self)
-
- view.send(:_evaluate_assigns_and_ivars)
- view.send(:_set_controller_content_type, mime_type) if respond_to?(:mime_type)
-
- result = view.send(method_name(local_assigns), local_assigns) do |*names|
- ivar = :@_proc_for_layout
- if !view.instance_variable_defined?(:"@content_for_#{names.first}") && view.instance_variable_defined?(ivar) && (proc = view.instance_variable_get(ivar))
- view.capture(*names, &proc)
- elsif view.instance_variable_defined?(ivar = :"@content_for_#{names.first || :layout}")
- view.instance_variable_get(ivar)
- end
- end
-
- stack.pop
- result
- end
-
def method_name(local_assigns)
if local_assigns && local_assigns.any?
method_name = method_name_without_locals.dup
@@ -55,16 +33,16 @@ def method_name(local_assigns)
method_name.to_sym
end
- private
- # Compile and evaluate the template's code (if necessary)
- def compile(local_assigns)
- render_symbol = method_name(local_assigns)
+ # Compile and evaluate the template's code (if necessary)
+ def compile(local_assigns)
+ render_symbol = method_name(local_assigns)
- if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
- compile!(render_symbol, local_assigns)
- end
+ if !Base::CompiledTemplates.method_defined?(render_symbol) || recompile?
+ compile!(render_symbol, local_assigns)
end
+ end
+ private
def compile!(render_symbol, local_assigns)
locals_code = local_assigns.keys.map { |key| "#{key} = local_assigns[:#{key}];" }.join
34 actionpack/lib/action_view/template.rb → actionpack/lib/action_view/template/template.rb
View
@@ -38,7 +38,7 @@ def eql?(path)
# should not be confused with format extensions +html+, +js+, +xml+,
# etc. A format must be supplied to match a formated file. +hello/index+
# will never match +hello/index.html.erb+.
- def [](path)
+ def find_template(path)
templates_in_path do |template|
if template.accessible_paths.include?(path)
return template
@@ -47,6 +47,24 @@ def [](path)
nil
end
+ def find_by_parts(name, extensions = nil, prefix = nil, partial = nil)
+ path = prefix ? "#{prefix}/" : ""
+
+ name = name.split("/")
+ name[-1] = "_#{name[-1]}" if partial
+
+ path << name.join("/")
+
+ template = nil
+
+ Array(extensions).each do |extension|
+ extensioned_path = extension ? "#{path}.#{extension}" : path
+ template = find_template(extensioned_path) || find_template(path)
+ break if template
+ end
+ template
+ end
+
private
def templates_in_path
(Dir.glob("#{@path}/**/*/**") | Dir.glob("#{@path}/**")).each do |file|
@@ -73,7 +91,7 @@ def initialize(path)
@paths.freeze
end
- def [](path)
+ def find_template(path)
@paths[path]
end
end
@@ -177,18 +195,6 @@ def method_segment
end
memoize :method_segment
- def render_template(view, local_assigns = {})
- render(view, local_assigns)
- rescue Exception => e
- raise e unless filename
- if TemplateError === e
- e.sub_template_of(self)
- raise e
- else
- raise TemplateError.new(self, view.assigns, e)
- end
- end
-
def stale?
File.mtime(filename) > mtime
end
19 actionpack/lib/action_view/test_case.rb
View
@@ -7,18 +7,15 @@ def initialize(*args)
@_rendered = { :template => nil, :partials => Hash.new(0) }
initialize_without_template_tracking(*args)
end
- end
-
- module Renderable
- alias_method :render_without_template_tracking, :render
- def render(view, local_assigns = {})
- if respond_to?(:path) && !is_a?(InlineTemplate)
- rendered = view.instance_variable_get(:@_rendered)
- rendered[:partials][self] += 1 if is_a?(RenderablePartial)
- rendered[:template] ||= self
+
+ alias_method :_render_template_without_template_tracking, :_render_template
+ def _render_template(template, local_assigns = {})
+ if template.respond_to?(:path) && !template.is_a?(InlineTemplate)
+ @_rendered[:partials][template] += 1 if template.is_a?(RenderablePartial)
+ @_rendered[:template] ||= template
end
- render_without_template_tracking(view, local_assigns)
- end
+ _render_template_without_template_tracking(template, local_assigns)
+ end
end
class TestCase < ActiveSupport::TestCase
38 actionpack/test/controller/layout_test.rb
View
@@ -55,7 +55,7 @@ def test_controller_name_layout_name_match
def test_third_party_template_library_auto_discovers_layout
@controller = ThirdPartyTemplateLibraryController.new
get :hello
- assert_equal 'layouts/third_party_template_library.mab', @controller.active_layout.to_s
+ assert_equal 'layouts/third_party_template_library.mab', @controller.active_layout(true).to_s
assert_equal 'layouts/third_party_template_library', @response.layout
assert_response :success
assert_equal 'Mab', @response.body
@@ -64,14 +64,14 @@ def test_third_party_template_library_auto_discovers_layout
def test_namespaced_controllers_auto_detect_layouts
@controller = ControllerNameSpace::NestedController.new
get :hello
- assert_equal 'layouts/controller_name_space/nested', @controller.active_layout.to_s
+ assert_equal 'layouts/controller_name_space/nested', @controller.active_layout(true).to_s
assert_equal 'controller_name_space/nested.rhtml hello.rhtml', @response.body
end
def test_namespaced_controllers_auto_detect_layouts
@controller = MultipleExtensions.new
get :hello
- assert_equal 'layouts/multiple_extensions.html.erb', @controller.active_layout.to_s
+ assert_equal 'layouts/multiple_extensions.html.erb', @controller.active_layout(true).to_s
assert_equal 'multiple_extensions.html.erb hello.rhtml', @response.body.strip
end
end
@@ -83,6 +83,14 @@ class HasOwnLayoutController < LayoutTest
layout 'item'
end
+class OnlyLayoutController < LayoutTest
+ layout 'item', :only => "hello"
+end
+
+class ExceptLayoutController < LayoutTest
+ layout 'item', :except => "goodbye"
+end
+
class SetsLayoutInRenderController < LayoutTest
def hello
render :layout => 'third_party_template_library'
@@ -107,6 +115,30 @@ def test_layout_set_when_set_in_controller
get :hello
assert_equal 'layouts/item', @response.layout
end
+
+ def test_layout_only_exception_when_included
+ @controller = OnlyLayoutController.new
+ get :hello
+ assert_equal 'layouts/item', @response.layout
+ end
+
+ def test_layout_only_exception_when_excepted
+ @controller = OnlyLayoutController.new
+ get :goodbye
+ assert_equal nil, @response.layout
+ end
+
+ def test_layout_except_exception_when_included
+ @controller = ExceptLayoutController.new
+ get :hello
+ assert_equal 'layouts/item', @response.layout
+ end
+
+ def test_layout_except_exception_when_excepted
+ @controller = ExceptLayoutController.new
+ get :goodbye
+ assert_equal nil, @response.layout
+ end
def test_layout_set_when_using_render
@controller = SetsLayoutInRenderController.new
2  actionpack/test/controller/mime_responds_test.rb
View
@@ -437,7 +437,7 @@ def render(*args)
unless args.empty?
@action = args.first[:action]
end
- response.body = "#{@action} - #{@template.template_format}"
+ response.body = "#{@action} - #{@template.formats}"
end
end
6 actionpack/test/controller/render_test.rb
View
@@ -342,7 +342,7 @@ def render_to_string_with_caught_exception
end
def accessing_params_in_template_with_layout
- render :layout => nil, :inline => "Hello: <%= params[:name] %>"
+ render :layout => true, :inline => "Hello: <%= params[:name] %>"
end
def render_with_explicit_template
@@ -1612,7 +1612,7 @@ def test_logger_prints_layout_and_template_rendering_info
@controller.logger = MockLogger.new
get :layout_test
logged = @controller.logger.logged.find_all {|l| l =~ /render/i }
- assert_equal "Rendering template within layouts/standard", logged[0]
- assert_equal "Rendering test/hello_world", logged[1]
+ assert_equal "Rendering test/hello_world", logged[0]
+ assert_equal "Rendering template within layouts/standard", logged[1]
end
end
2  actionpack/test/controller/view_paths_test.rb
View
@@ -29,8 +29,8 @@ def setup
@controller = TestController.new
# Following is needed in order to setup @controller.template object properly
- @controller.send :initialize_template_class, @response
@controller.send :assign_shortcuts, @request, @response
+ @controller.send :initialize_template_class, @response
# Track the last warning.
@old_behavior = ActiveSupport::Deprecation.behavior
1  actionpack/test/fixtures/layout_tests/views/goodbye.rhtml
View
@@ -0,0 +1 @@
+hello.rhtml
2  actionpack/test/template/javascript_helper_test.rb
View
@@ -3,7 +3,7 @@
class JavaScriptHelperTest < ActionView::TestCase
tests ActionView::Helpers::JavaScriptHelper
- attr_accessor :template_format, :output_buffer
+ attr_accessor :formats, :output_buffer
def setup
@template = self
2  actionpack/test/template/prototype_helper_test.rb
View
@@ -25,7 +25,7 @@ class Author::Nested < Author; end
class PrototypeHelperBaseTest < ActionView::TestCase
- attr_accessor :template_format, :output_buffer
+ attr_accessor :formats, :output_buffer
def setup
@template = self
2  actionpack/test/template/render_test.rb
View
@@ -138,7 +138,7 @@ def test_render_partial_and_fallback_to_layout
# TODO: The reason for this test is unclear, improve documentation
def test_render_missing_xml_partial_and_raise_missing_template
- @view.template_format = :xml
+ @view.formats = [:xml]
assert_raise(ActionView::MissingTemplate) { @view.render(:partial => "test/layout_for_partial") }
end
1  activesupport/lib/active_support.rb
View
@@ -32,6 +32,7 @@ def self.load_all!
autoload :BufferedLogger, 'active_support/buffered_logger'
autoload :Cache, 'active_support/cache'
autoload :Callbacks, 'active_support/callbacks'
+ autoload :ConcurrentHash, 'active_support/concurrent_hash'
autoload :Deprecation, 'active_support/deprecation'
autoload :Duration, 'active_support/duration'
autoload :Gzip, 'active_support/gzip'
16 activesupport/lib/active_support/buffered_logger.rb
View
@@ -67,14 +67,14 @@ def add(severity, message = nil, progname = nil, &block)
end
for severity in Severity.constants
- class_eval <<-EOT, __FILE__, __LINE__
- def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
- add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
- end # end
- #
- def #{severity.downcase}? # def debug?
- #{severity} >= @level # DEBUG >= @level
- end # end
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
+ add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
+ end # end
+
+ def #{severity.downcase}? # def debug?
+ #{severity} >= @level # DEBUG >= @level
+ end # end
EOT
end
2  activesupport/lib/active_support/callbacks.rb
View
@@ -204,7 +204,7 @@ def self.included(base)
module ClassMethods
def define_callbacks(*callbacks)
callbacks.each do |callback|
- class_eval <<-"end_eval"
+ class_eval <<-"end_eval", __FILE__, __LINE__ + 1
def self.#{callback}(*methods, &block) # def self.before_save(*methods, &block)
callbacks = CallbackChain.build(:#{callback}, *methods, &block) # callbacks = CallbackChain.build(:before_save, *methods, &block)
@#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
26 activesupport/lib/active_support/concurrent_hash.rb
View
@@ -0,0 +1,26 @@
+module ActiveSupport
+ class ConcurrentHash
+ def initialize(hash = {})
+ @backup_cache = hash.dup
+ @frozen_cache = hash.dup.freeze
+ @mutex = Mutex.new
+ end
+
+ def []=(k,v)
+ @mutex.synchronize { @backup_cache[k] = v }
+ @frozen_cache = @backup_cache.dup.freeze
+ end
+
+ def [](k)
+ if @frozen_cache.key?(k)
+ @frozen_cache[k]
+ else
+ @mutex.synchronize { @backup_cache[k] }
+ end
+ end
+
+ def empty?
+ @backup_cache.empty?
+ end
+ end
+end
4 activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
View
@@ -10,7 +10,7 @@ class Class
def cattr_reader(*syms)
syms.flatten.each do |sym|
next if sym.is_a?(Hash)
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@hair_colors
@@#{sym} = nil # @@hair_colors = nil
end # end
@@ -29,7 +29,7 @@ def #{sym} # def hair_colors
def cattr_writer(*syms)
options = syms.extract_options!
syms.flatten.each do |sym|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@hair_colors
@@#{sym} = nil # @@hair_colors = nil
end # end
10 activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
View
@@ -8,7 +8,7 @@ class Class
def superclass_delegating_reader(*names)
class_name_to_stop_searching_on = self.superclass.name.blank? ? "Object" : self.superclass.name
names.each do |name|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{name} # def self.only_reader
if defined?(@#{name}) # if defined?(@only_reader)
@#{name} # @only_reader
@@ -32,10 +32,10 @@ def #{name}? # def only_reader?
def superclass_delegating_writer(*names)
names.each do |name|
- class_eval <<-EOS
- def self.#{name}=(value) # def self.only_writer=(value)
- @#{name} = value # @only_writer = value
- end # end
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def self.#{name}=(value) # def self.property=(value)
+ @#{name} = value # @property = value
+ end # end
EOS
end
end
22 activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
View
@@ -10,14 +10,14 @@ class Class # :nodoc:
def class_inheritable_reader(*syms)
syms.each do |sym|
next if sym.is_a?(Hash)
- class_eval <<-EOS
- def self.#{sym} # def self.before_add_for_comments
- read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:before_add_for_comments)
- end # end
- #
- def #{sym} # def before_add_for_comments
- self.class.#{sym} # self.class.before_add_for_comments
- end # end
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def self.#{sym} # def self.after_add
+ read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:after_add)
+ end # end
+
+ def #{sym} # def after_add
+ self.class.#{sym} # self.class.after_add
+ end # end
EOS
end
end
@@ -25,7 +25,7 @@ def #{sym} # def before_add_for_comments
def class_inheritable_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj) # def self.color=(obj)
write_inheritable_attribute(:#{sym}, obj) # write_inheritable_attribute(:color, obj)
end # end
@@ -42,7 +42,7 @@ def #{sym}=(obj) # def color=(obj)
def class_inheritable_array_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj) # def self.levels=(obj)
write_inheritable_array(:#{sym}, obj) # write_inheritable_array(:levels, obj)
end # end
@@ -59,7 +59,7 @@ def #{sym}=(obj) # def levels=(obj)
def class_inheritable_hash_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj) # def self.nicknames=(obj)
write_inheritable_hash(:#{sym}, obj) # write_inheritable_hash(:nicknames, obj)
end # end
4 activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
View
@@ -14,7 +14,7 @@ class Module
def mattr_reader(*syms)
syms.each do |sym|
next if sym.is_a?(Hash)
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@pagination_options
@@#{sym} = nil # @@pagination_options = nil
end # end
@@ -33,7 +33,7 @@ def #{sym} # def pagination_options
def mattr_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@pagination_options
@@#{sym} = nil # @@pagination_options = nil
end # end
6 activesupport/lib/active_support/core_ext/proc.rb
View
@@ -3,9 +3,9 @@ def bind(object)
block, time = self, Time.now
(class << object; self end).class_eval do
method_name = "__bind_#{time.to_i}_#{time.usec}"
- define_method(method_name, &block)
- method = instance_method(method_name)
- remove_method(method_name)
+ define_method(method_name, &block) # define_method("__bind_1230458026_720454", &block)
+ method = instance_method(method_name) # method = instance_method("__bind_1230458026_720454")
+ remove_method(method_name) # remove_method("__bind_1230458026_720454")
method
end.bind(object)
end
6 activesupport/lib/active_support/core_ext/string/multibyte.rb
View
@@ -55,7 +55,11 @@ def is_utf8?
unless '1.8.7 and later'.respond_to?(:chars)
def chars
- ActiveSupport::Deprecation.warn('String#chars has been deprecated in favor of String#mb_chars.', caller)
+ # FIXME:
+ # ActiveSupport::Deprecation refers to RAILS_ENV
+ # and is a show stopper for 3rd party applications
+ # that only want ActiveSupport
+ ActiveSupport::Deprecation.warn('String#chars has been deprecated in favor of String#mb_chars.', caller) if defined?(ActiveSupport::Deprecation)
mb_chars
end
end
2  activesupport/lib/active_support/deprecation.rb
View
@@ -89,7 +89,7 @@ def deprecate(*method_names)
method_names = method_names + options.keys
method_names.each do |method_name|
alias_method_chain(method_name, :deprecation) do |target, punctuation|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def #{target}_with_deprecation#{punctuation}(*args, &block) # def generate_secret_with_deprecation(*args, &block)
::ActiveSupport::Deprecation.warn( # ::ActiveSupport::Deprecation.warn(
self.class.deprecated_method_warning( # self.class.deprecated_method_warning(
2  activesupport/lib/active_support/memoizable.rb
View
@@ -58,7 +58,7 @@ def memoize(*symbols)
original_method = :"_unmemoized_#{symbol}"
memoized_ivar = ActiveSupport::Memoizable.memoized_ivar_for(symbol)
- class_eval <<-EOS, __FILE__, __LINE__
+ class_eval <<-EOS, __FILE__, __LINE__ + 1
include InstanceMethods # include InstanceMethods
#
if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type)
9 activesupport/lib/active_support/mini.rb
View
@@ -0,0 +1,9 @@
+$LOAD_PATH.unshift File.dirname(__FILE__)
+
+require "core_ext/blank"
+# whole object.rb pulls up rarely used introspection extensions
+require "core_ext/object/metaclass"
+require 'core_ext/array'
+require 'core_ext/hash'
+require 'core_ext/module/attribute_accessors'
+require 'core_ext/string/inflections'
10 activesupport/lib/active_support/multibyte/unicode_database.rb
View
@@ -23,11 +23,11 @@ def initialize
# Lazy load the Unicode database so it's only loaded when it's actually used
ATTRIBUTES.each do |attr_name|
- class_eval(<<-EOS, __FILE__, __LINE__)
- def #{attr_name} # def codepoints
- load # load
- @#{attr_name} # @codepoints
- end # end
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def #{attr_name} # def codepoints
+ load # load
+ @#{attr_name} # @codepoints
+ end # end
EOS
end
8 activesupport/lib/active_support/time_with_zone.rb
View