diff options
51 files changed, 759 insertions, 556 deletions
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb index eda5de4e18..473703b629 100644 --- a/actionmailer/lib/action_mailer/base.rb +++ b/actionmailer/lib/action_mailer/base.rb @@ -371,6 +371,14 @@ module ActionMailer #:nodoc: 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 @@ module ActionMailer #: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 @@ module ActionMailer #: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 @@ module ActionMailer #: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 @@ module ActionMailer #:nodoc: # no alternate has been given as the parameter, this will fail. def deliver!(mail = @mail) raise "no mail object available for delivery!" unless mail + unless logger.nil? logger.info "Sent mail to #{Array(recipients).join(', ')}" logger.debug "\n#{mail.encoded}" @@ -543,27 +552,43 @@ module ActionMailer #:nodoc: @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 @@ module ActionMailer #:nodoc: 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 @@ module ActionMailer #:nodoc: 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 diff --git a/actionmailer/test/mail_service_test.rb b/actionmailer/test/mail_service_test.rb index a886b1143e..d14f326163 100644 --- a/actionmailer/test/mail_service_test.rb +++ b/actionmailer/test/mail_service_test.rb @@ -566,13 +566,31 @@ class ActionMailerTest < Test::Unit::TestCase 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 diff --git a/actionpack/lib/action_controller.rb b/actionpack/lib/action_controller.rb index 3e77970367..6000ee15c6 100644 --- a/actionpack/lib/action_controller.rb +++ b/actionpack/lib/action_controller.rb @@ -35,6 +35,8 @@ gem 'rack', '>= 0.9.0' 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. diff --git a/actionpack/lib/action_controller/base.rb b/actionpack/lib/action_controller/base.rb index 50b965ce4c..78c8bf0647 100644 --- a/actionpack/lib/action_controller/base.rb +++ b/actionpack/lib/action_controller/base.rb @@ -514,8 +514,8 @@ module ActionController #:nodoc: 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 @@ module ActionController #:nodoc: 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 @@ module ActionController #:nodoc: 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 @@ module ActionController #: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 @@ module ActionController #:nodoc: @_response.session = request.session @_session = @_response.session - @template = @_response.template @_headers = @_response.headers end @@ -1257,23 +1292,21 @@ module ActionController #: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 @@ module ActionController #:nodoc: path.split('/', 2).last end + def template_path_includes_controller?(path) self.controller_path.split('/')[-1] == path.split('/')[0] end diff --git a/actionpack/lib/action_controller/layout.rb b/actionpack/lib/action_controller/layout.rb index 159c5c7326..926ae26f92 100644 --- a/actionpack/lib/action_controller/layout.rb +++ b/actionpack/lib/action_controller/layout.rb @@ -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 @@ module ActionController #:nodoc: # # 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 diff --git a/actionpack/lib/action_controller/mime_responds.rb b/actionpack/lib/action_controller/mime_responds.rb index b755363873..bac225ab2a 100644 --- a/actionpack/lib/action_controller/mime_responds.rb +++ b/actionpack/lib/action_controller/mime_responds.rb @@ -109,16 +109,13 @@ module ActionController #:nodoc: 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 @@ module ActionController #:nodoc: @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 diff --git a/actionpack/lib/action_controller/mime_type.rb b/actionpack/lib/action_controller/mime_type.rb index 017626ba27..3d26870f4f 100644 --- a/actionpack/lib/action_controller/mime_type.rb +++ b/actionpack/lib/action_controller/mime_type.rb @@ -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 @@ module Mime # 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 @@ module Mime 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 @@ module Mime # 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+)\?$/ diff --git a/actionpack/lib/action_controller/request.rb b/actionpack/lib/action_controller/request.rb index 09dcd684e8..f8c77241b9 100755 --- a/actionpack/lib/action_controller/request.rb +++ b/actionpack/lib/action_controller/request.rb @@ -101,10 +101,16 @@ module ActionController 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 @@ module ActionController 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. diff --git a/actionpack/lib/action_controller/rescue.rb b/actionpack/lib/action_controller/rescue.rb index 4b7d1e32fd..3beeb2da83 100644 --- a/actionpack/lib/action_controller/rescue.rb +++ b/actionpack/lib/action_controller/rescue.rb @@ -125,11 +125,13 @@ module ActionController #:nodoc: @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 @@ module ActionController #: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) diff --git a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb b/actionpack/lib/action_controller/templates/rescues/diagnostics.erb index 669da1b26e..95be64511d 100644 --- a/actionpack/lib/action_controller/templates/rescues/diagnostics.erb +++ b/actionpack/lib/action_controller/templates/rescues/diagnostics.erb @@ -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")) %>
\ No newline at end of file diff --git a/actionpack/lib/action_view.rb b/actionpack/lib/action_view.rb index 0b710bd8d9..aa06c19a48 100644 --- a/actionpack/lib/action_view.rb +++ b/actionpack/lib/action_view.rb @@ -31,6 +31,8 @@ rescue LoadError end end +require File.join(File.dirname(__FILE__), "action_pack") + module ActionView def self.load_all! [Base, InlineTemplate, TemplateError] @@ -38,15 +40,16 @@ module ActionView 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 diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index 70a0ba91a7..80b8ea6a4c 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -160,14 +160,13 @@ module ActionView #:nodoc: # # 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 @@ module ActionView #:nodoc: 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 @@ module ActionView #:nodoc: 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 @@ module ActionView #:nodoc: 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 @@ module ActionView #: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 diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 18a209dcea..99676a9c27 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -987,13 +987,13 @@ module ActionView 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) diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb index 19207e7262..4c3a226ac6 100644 --- a/actionpack/lib/action_view/paths.rb +++ b/actionpack/lib/action_view/paths.rb @@ -32,14 +32,24 @@ module ActionView #:nodoc: 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 diff --git a/actionpack/lib/action_view/partials.rb b/actionpack/lib/action_view/render/partials.rb index 59e82b98a4..aa4c4af213 100644 --- a/actionpack/lib/action_view/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -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 diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb new file mode 100644 index 0000000000..a02c058725 --- /dev/null +++ b/actionpack/lib/action_view/render/rendering.rb @@ -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
\ No newline at end of file diff --git a/actionpack/lib/action_view/renderable_partial.rb b/actionpack/lib/action_view/renderable_partial.rb deleted file mode 100644 index 3ea836fa25..0000000000 --- a/actionpack/lib/action_view/renderable_partial.rb +++ /dev/null @@ -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 diff --git a/actionpack/lib/action_view/template_error.rb b/actionpack/lib/action_view/template/error.rb index 37cb1c7c6c..37cb1c7c6c 100644 --- a/actionpack/lib/action_view/template_error.rb +++ b/actionpack/lib/action_view/template/error.rb diff --git a/actionpack/lib/action_view/template_handler.rb b/actionpack/lib/action_view/template/handler.rb index 672da0ed2b..672da0ed2b 100644 --- a/actionpack/lib/action_view/template_handler.rb +++ b/actionpack/lib/action_view/template/handler.rb diff --git a/actionpack/lib/action_view/template_handlers.rb b/actionpack/lib/action_view/template/handlers.rb index 205f8628f0..fb85f28851 100644 --- a/actionpack/lib/action_view/template_handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -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 diff --git a/actionpack/lib/action_view/template_handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb index 788dc93326..788dc93326 100644 --- a/actionpack/lib/action_view/template_handlers/builder.rb +++ b/actionpack/lib/action_view/template/handlers/builder.rb diff --git a/actionpack/lib/action_view/template_handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index e3120ba267..e3120ba267 100644 --- a/actionpack/lib/action_view/template_handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb diff --git a/actionpack/lib/action_view/template_handlers/rjs.rb b/actionpack/lib/action_view/template/handlers/rjs.rb index 41a1fddb47..802a79b3fc 100644 --- a/actionpack/lib/action_view/template_handlers/rjs.rb +++ b/actionpack/lib/action_view/template/handlers/rjs.rb @@ -4,7 +4,7 @@ module ActionView include Compilable def compile(template) - "@template_format = :html;" + + "@formats = [:html];" + "controller.response.content_type ||= Mime::JS;" + "update_page do |page|;#{template.source}\nend" end diff --git a/actionpack/lib/action_view/inline_template.rb b/actionpack/lib/action_view/template/inline.rb index 54efa543c8..54efa543c8 100644 --- a/actionpack/lib/action_view/inline_template.rb +++ b/actionpack/lib/action_view/template/inline.rb diff --git a/actionpack/lib/action_view/template/partial.rb b/actionpack/lib/action_view/template/partial.rb new file mode 100644 index 0000000000..30dec1dc5b --- /dev/null +++ b/actionpack/lib/action_view/template/partial.rb @@ -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 diff --git a/actionpack/lib/action_view/renderable.rb b/actionpack/lib/action_view/template/renderable.rb index 153e14f68b..35c832aaba 100644 --- a/actionpack/lib/action_view/renderable.rb +++ b/actionpack/lib/action_view/template/renderable.rb @@ -23,28 +23,6 @@ module ActionView 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 @@ module ActionView 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 diff --git a/actionpack/lib/action_view/template.rb b/actionpack/lib/action_view/template/template.rb index 9d1e0d3ac5..235a95a0f3 100644 --- a/actionpack/lib/action_view/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -38,7 +38,7 @@ module ActionView #:nodoc: # 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 @@ module ActionView #:nodoc: 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 @@ module ActionView #:nodoc: @paths.freeze end - def [](path) + def find_template(path) @paths[path] end end @@ -177,18 +195,6 @@ module ActionView #:nodoc: 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 diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index ec337bb05b..c8f204046b 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -7,18 +7,15 @@ module ActionView @_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 diff --git a/actionpack/test/controller/layout_test.rb b/actionpack/test/controller/layout_test.rb index 2f5e830fba..16c16aa88d 100644 --- a/actionpack/test/controller/layout_test.rb +++ b/actionpack/test/controller/layout_test.rb @@ -55,7 +55,7 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase 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 @@ class LayoutAutoDiscoveryTest < ActionController::TestCase 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 @@ class LayoutSetInResponseTest < ActionController::TestCase 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 diff --git a/actionpack/test/controller/mime_responds_test.rb b/actionpack/test/controller/mime_responds_test.rb index dc59180a68..948e90254d 100644 --- a/actionpack/test/controller/mime_responds_test.rb +++ b/actionpack/test/controller/mime_responds_test.rb @@ -437,7 +437,7 @@ class MimeControllerTest < ActionController::TestCase unless args.empty? @action = args.first[:action] end - response.body = "#{@action} - #{@template.template_format}" + response.body = "#{@action} - #{@template.formats}" end end diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 8809aa7c34..11b502a564 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -342,7 +342,7 @@ class TestController < ActionController::Base 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 @@ class RenderingLoggingTest < ActionController::TestCase @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 diff --git a/actionpack/test/controller/view_paths_test.rb b/actionpack/test/controller/view_paths_test.rb index ac84e2dfcd..1539f8f506 100644 --- a/actionpack/test/controller/view_paths_test.rb +++ b/actionpack/test/controller/view_paths_test.rb @@ -29,8 +29,8 @@ class ViewLoadPathsTest < ActionController::TestCase @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 diff --git a/actionpack/test/fixtures/layout_tests/views/goodbye.rhtml b/actionpack/test/fixtures/layout_tests/views/goodbye.rhtml new file mode 100644 index 0000000000..bbccf0913e --- /dev/null +++ b/actionpack/test/fixtures/layout_tests/views/goodbye.rhtml @@ -0,0 +1 @@ +hello.rhtml
\ No newline at end of file diff --git a/actionpack/test/template/javascript_helper_test.rb b/actionpack/test/template/javascript_helper_test.rb index d41111127b..d814f84752 100644 --- a/actionpack/test/template/javascript_helper_test.rb +++ b/actionpack/test/template/javascript_helper_test.rb @@ -3,7 +3,7 @@ require 'abstract_unit' class JavaScriptHelperTest < ActionView::TestCase tests ActionView::Helpers::JavaScriptHelper - attr_accessor :template_format, :output_buffer + attr_accessor :formats, :output_buffer def setup @template = self diff --git a/actionpack/test/template/prototype_helper_test.rb b/actionpack/test/template/prototype_helper_test.rb index d6b86a3964..8ff29412bf 100644 --- a/actionpack/test/template/prototype_helper_test.rb +++ b/actionpack/test/template/prototype_helper_test.rb @@ -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 diff --git a/actionpack/test/template/render_test.rb b/actionpack/test/template/render_test.rb index 4bd897efeb..47348ebdb8 100644 --- a/actionpack/test/template/render_test.rb +++ b/actionpack/test/template/render_test.rb @@ -138,7 +138,7 @@ module RenderTestCases # 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 diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 7ebb3c48e0..62d538e2d5 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -32,6 +32,7 @@ module ActiveSupport 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' diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb index 33bcf327f8..568c596f91 100644 --- a/activesupport/lib/active_support/buffered_logger.rb +++ b/activesupport/lib/active_support/buffered_logger.rb @@ -67,14 +67,14 @@ module ActiveSupport 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 diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 86e66e0588..4bac8292e2 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -204,7 +204,7 @@ module ActiveSupport 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 diff --git a/activesupport/lib/active_support/concurrent_hash.rb b/activesupport/lib/active_support/concurrent_hash.rb new file mode 100644 index 0000000000..c9f9b16da3 --- /dev/null +++ b/activesupport/lib/active_support/concurrent_hash.rb @@ -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 diff --git a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb index c795871474..75e481fc54 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb @@ -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 @@ class Class 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 diff --git a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb index 000ccf4d55..d893818695 100644 --- a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb +++ b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb @@ -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 @@ class Class 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 diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb index 1794afe77c..70fdde3a58 100644 --- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb +++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb @@ -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 @@ class Class # :nodoc: 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 @@ class Class # :nodoc: 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 @@ class Class # :nodoc: 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 diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb index 9402cb8534..137590d286 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -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 @@ class Module 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 diff --git a/activesupport/lib/active_support/core_ext/proc.rb b/activesupport/lib/active_support/core_ext/proc.rb index 2ca23f62ef..5c29cc32a2 100644 --- a/activesupport/lib/active_support/core_ext/proc.rb +++ b/activesupport/lib/active_support/core_ext/proc.rb @@ -3,9 +3,9 @@ class Proc #:nodoc: 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 diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb index a4caa83b74..8f8f0968fd 100644 --- a/activesupport/lib/active_support/core_ext/string/multibyte.rb +++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb @@ -55,7 +55,11 @@ module ActiveSupport #:nodoc: 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 diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index d20151661b..202b46ce7a 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -89,7 +89,7 @@ module ActiveSupport 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( diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb index 952b4d8063..4ffb5d9520 100644 --- a/activesupport/lib/active_support/memoizable.rb +++ b/activesupport/lib/active_support/memoizable.rb @@ -58,7 +58,7 @@ module ActiveSupport 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) diff --git a/activesupport/lib/active_support/mini.rb b/activesupport/lib/active_support/mini.rb new file mode 100644 index 0000000000..fe7ba48e58 --- /dev/null +++ b/activesupport/lib/active_support/mini.rb @@ -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'
\ No newline at end of file diff --git a/activesupport/lib/active_support/multibyte/unicode_database.rb b/activesupport/lib/active_support/multibyte/unicode_database.rb index a08f38cdbb..074ad8613a 100644 --- a/activesupport/lib/active_support/multibyte/unicode_database.rb +++ b/activesupport/lib/active_support/multibyte/unicode_database.rb @@ -23,11 +23,11 @@ module ActiveSupport #:nodoc: # 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 diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 1a59b2a08d..3a5a083629 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -237,10 +237,10 @@ module ActiveSupport end %w(year mon month day mday wday yday hour min sec to_date).each do |method_name| - class_eval <<-EOV - def #{method_name} # def year - time.#{method_name} # time.year - end # end + class_eval <<-EOV, __FILE__, __LINE__ + 1 + def #{method_name} # def month + time.#{method_name} # time.month + end # end EOV end |