diff options
Diffstat (limited to 'actionpack/lib')
-rw-r--r-- | actionpack/lib/abstract_controller/layouts.rb | 13 | ||||
-rw-r--r-- | actionpack/lib/abstract_controller/rendering_controller.rb | 17 | ||||
-rw-r--r-- | actionpack/lib/action_controller/metal/rendering_controller.rb | 48 | ||||
-rw-r--r-- | actionpack/lib/action_controller/routing/resources.rb | 18 | ||||
-rw-r--r-- | actionpack/lib/action_controller/routing/route_set.rb | 29 | ||||
-rw-r--r-- | actionpack/lib/action_controller/testing/process.rb | 2 | ||||
-rwxr-xr-x | actionpack/lib/action_dispatch/http/request.rb | 36 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/middleware/params_parser.rb | 6 | ||||
-rw-r--r-- | actionpack/lib/action_view/base.rb | 29 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/prototype_helper.rb | 5 | ||||
-rw-r--r-- | actionpack/lib/action_view/render/partials.rb | 133 | ||||
-rw-r--r-- | actionpack/lib/action_view/render/rendering.rb | 79 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handler.rb | 6 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/resolver.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/template.rb | 28 |
15 files changed, 239 insertions, 212 deletions
diff --git a/actionpack/lib/abstract_controller/layouts.rb b/actionpack/lib/abstract_controller/layouts.rb index ac2154dffc..a8bd2b80e1 100644 --- a/actionpack/lib/abstract_controller/layouts.rb +++ b/actionpack/lib/abstract_controller/layouts.rb @@ -19,15 +19,20 @@ module AbstractController end end + def clear_template_caches! + @found_layouts.clear if @found_layouts + super + end + def cache_layout(details) layout = @found_layouts - values = details.values_at(:formats, :locale) + key = Thread.current[:format_locale_key] # Cache nil - if layout.key?(values) - return layout[values] + if layout.key?(key) + return layout[key] else - layout[values] = yield + layout[key] = yield end end diff --git a/actionpack/lib/abstract_controller/rendering_controller.rb b/actionpack/lib/abstract_controller/rendering_controller.rb index bb7891fbfd..feca1bc4b7 100644 --- a/actionpack/lib/abstract_controller/rendering_controller.rb +++ b/actionpack/lib/abstract_controller/rendering_controller.rb @@ -111,12 +111,21 @@ module AbstractController def _determine_template(options) name = (options[:_template_name] || action_name).to_s - options[:_template] ||= view_paths.find( - name, { :formats => formats }, options[:_prefix], options[:_partial] - ) + options[:_template] ||= with_template_cache(name) do + view_paths.find( + name, { :formats => formats }, options[:_prefix], options[:_partial] + ) + end + end + + def with_template_cache(name) + yield end module ClassMethods + def clear_template_caches! + end + # Append a path to the list of view paths for this controller. # # ==== Parameters @@ -134,6 +143,7 @@ module AbstractController # the default view path. You may also provide a custom view path # (see ActionView::ViewPathSet for more information) def prepend_view_path(path) + clear_template_caches! self.view_paths.unshift(path) end @@ -148,6 +158,7 @@ module AbstractController # paths<ViewPathSet, Object>:: If a ViewPathSet is provided, use that; # otherwise, process the parameter into a ViewPathSet. def view_paths=(paths) + clear_template_caches! self._view_paths = paths.is_a?(ActionView::PathSet) ? paths : ActionView::Base.process_view_paths(paths) end diff --git a/actionpack/lib/action_controller/metal/rendering_controller.rb b/actionpack/lib/action_controller/metal/rendering_controller.rb index 5b1be763ad..4da32ca1b3 100644 --- a/actionpack/lib/action_controller/metal/rendering_controller.rb +++ b/actionpack/lib/action_controller/metal/rendering_controller.rb @@ -1,20 +1,56 @@ module ActionController + class HashKey + @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } } + + def self.get(klass, formats, locale) + @hash_keys[klass][formats][locale] ||= new(klass, formats, locale) + end + + attr_accessor :hash + def initialize(klass, formats, locale) + @formats, @locale = formats, locale + @hash = [formats, locale].hash + end + + alias_method :eql?, :equal? + + def inspect + "#<HashKey -- formats: #{@formats} locale: #{@locale}>" + end + end + module RenderingController extend ActiveSupport::Concern include AbstractController::RenderingController + module ClassMethods + def clear_template_caches! + ActionView::Partials::PartialRenderer::TEMPLATES.clear + template_cache.clear + super + end + + def template_cache + @template_cache ||= Hash.new {|h,k| h[k] = {} } + end + end + def process_action(*) self.formats = request.formats.map {|x| x.to_sym} + + super + end + + def _determine_template(*) super end def render(options) + Thread.current[:format_locale_key] = HashKey.get(self.class, formats, I18n.locale) + super - self.content_type ||= begin - mime = options[:_template].mime_type - formats.include?(mime && mime.to_sym) || formats.include?(:all) ? mime : Mime::Type.lookup_by_extension(formats.first) - end.to_s + self.content_type ||= options[:_template].mime_type.to_s response_body end @@ -34,6 +70,10 @@ module ActionController controller_path end + def with_template_cache(name) + self.class.template_cache[Thread.current[:format_locale_key]][name] ||= super + end + def _determine_template(options) if options.key?(:text) options[:_template] = ActionView::TextTemplate.new(options[:text], formats.first) diff --git a/actionpack/lib/action_controller/routing/resources.rb b/actionpack/lib/action_controller/routing/resources.rb index 4862cf7115..06506435a2 100644 --- a/actionpack/lib/action_controller/routing/resources.rb +++ b/actionpack/lib/action_controller/routing/resources.rb @@ -531,14 +531,14 @@ module ActionController with_options :controller => resource.controller do |map| map_associations(resource, options) + if block_given? + with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block) + end + map_collection_actions(map, resource) map_default_collection_actions(map, resource) map_new_actions(map, resource) map_member_actions(map, resource) - - if block_given? - with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block) - end end end @@ -546,16 +546,16 @@ module ActionController resource = SingletonResource.new(entities, options) with_options :controller => resource.controller do |map| - map_collection_actions(map, resource) - map_new_actions(map, resource) - map_member_actions(map, resource) - map_default_singleton_actions(map, resource) - map_associations(resource, options) if block_given? with_options(options.slice(*INHERITABLE_OPTIONS).merge(:path_prefix => resource.nesting_path_prefix, :name_prefix => resource.nesting_name_prefix), &block) end + + map_collection_actions(map, resource) + map_new_actions(map, resource) + map_member_actions(map, resource) + map_default_singleton_actions(map, resource) end end diff --git a/actionpack/lib/action_controller/routing/route_set.rb b/actionpack/lib/action_controller/routing/route_set.rb index 09f6024d39..a4f54ad662 100644 --- a/actionpack/lib/action_controller/routing/route_set.rb +++ b/actionpack/lib/action_controller/routing/route_set.rb @@ -407,22 +407,9 @@ module ActionController # don't use the recalled keys when determining which routes to check routes = routes_by_controller[controller][action][options.reject {|k,v| !v}.keys.sort_by { |x| x.object_id }] - routes[1].each_with_index do |route, index| + routes.each_with_index do |route, index| results = route.__send__(method, options, merged, expire_on) if results && (!results.is_a?(Array) || results.first) - - # Compare results with Rails 3.0 behavior - if routes[0][index] != route - routes[0].each do |route2| - new_results = route2.__send__(method, options, merged, expire_on) - if new_results && (!new_results.is_a?(Array) || new_results.first) - ActiveSupport::Deprecation.warn "The URL you generated will use the first matching route in routes.rb rather than the \"best\" match. " + - "In Rails 3.0 #{new_results} would of been generated instead of #{results}" - break - end - end - end - return results end end @@ -463,10 +450,7 @@ module ActionController @routes_by_controller ||= Hash.new do |controller_hash, controller| controller_hash[controller] = Hash.new do |action_hash, action| action_hash[action] = Hash.new do |key_hash, keys| - key_hash[keys] = [ - routes_for_controller_and_action_and_keys(controller, action, keys), - deprecated_routes_for_controller_and_action_and_keys(controller, action, keys) - ] + key_hash[keys] = routes_for_controller_and_action_and_keys(controller, action, keys) end end end @@ -487,15 +471,6 @@ module ActionController end end - def deprecated_routes_for_controller_and_action_and_keys(controller, action, keys) - selected = routes.select do |route| - route.matches_controller_and_action? controller, action - end - selected.sort_by do |route| - (keys - route.significant_keys).length - end - end - # Subclasses and plugins may override this method to extract further attributes # from the request, for use by route conditions and such. def extract_request_environment(request) diff --git a/actionpack/lib/action_controller/testing/process.rb b/actionpack/lib/action_controller/testing/process.rb index 09b1a59254..6bc7d60d76 100644 --- a/actionpack/lib/action_controller/testing/process.rb +++ b/actionpack/lib/action_controller/testing/process.rb @@ -148,7 +148,7 @@ module ActionController #:nodoc: def xml_http_request(request_method, action, parameters = nil, session = nil, flash = nil) @request.env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' - @request.env['HTTP_ACCEPT'] = [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ') + @request.env['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ') returning __send__(request_method, action, parameters, session, flash) do @request.env.delete 'HTTP_X_REQUESTED_WITH' @request.env.delete 'HTTP_ACCEPT' diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index b23306af62..bff030f0e4 100755 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -106,16 +106,10 @@ module ActionDispatch @env["action_dispatch.request.accepts"] ||= begin header = @env['HTTP_ACCEPT'].to_s.strip - fallback = xhr? ? Mime::JS : Mime::HTML - if header.empty? - [content_type, fallback, Mime::ALL].compact + [content_type] else - ret = Mime::Type.parse(header) - if ret.last == Mime::ALL - ret.insert(-2, fallback) - end - ret + Mime::Type.parse(header) end end end @@ -163,26 +157,20 @@ module ActionDispatch # 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(view_path = []) - @env["action_dispatch.request.format"] ||= - if parameters[:format] - Mime[parameters[:format]] - elsif ActionController::Base.use_accept_header && !(accepts == ONLY_ALL) - accepts.first - elsif xhr? then Mime::JS - else Mime::HTML - end + formats.first end def formats - if ActionController::Base.use_accept_header - if param = parameters[:format] - Array.wrap(Mime[param]) + accept = @env['HTTP_ACCEPT'] + + @env["action_dispatch.request.formats"] ||= + if parameters[:format] + [Mime[parameters[:format]]] + elsif xhr? || (accept && !accept.include?(?,)) + accepts else - accepts.dup + [Mime::HTML] end - else - [format] - end end # Sets the \format by string extension, which can be used to force custom formats @@ -198,7 +186,7 @@ module ActionDispatch # end def format=(extension) parameters[:format] = extension.to_s - @env["action_dispatch.request.format"] = Mime::Type.lookup_by_extension(parameters[:format]) + @env["action_dispatch.request.formats"] = [Mime::Type.lookup_by_extension(parameters[:format])] end # Returns a symbolized version of the <tt>:format</tt> parameter of the request. diff --git a/actionpack/lib/action_dispatch/middleware/params_parser.rb b/actionpack/lib/action_dispatch/middleware/params_parser.rb index e83cf9236b..ff2b2fe74b 100644 --- a/actionpack/lib/action_dispatch/middleware/params_parser.rb +++ b/actionpack/lib/action_dispatch/middleware/params_parser.rb @@ -47,6 +47,8 @@ module ActionDispatch false end rescue Exception => e # YAML, XML or Ruby code block errors + logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}" + raise { "body" => request.raw_post, "content_type" => request.content_type, @@ -67,5 +69,9 @@ module ActionDispatch nil end + + def logger + defined?(Rails.logger) ? Rails.logger : Logger.new($stderr) + end end end diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index c171a5a8f5..ec1b07797b 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -175,6 +175,17 @@ module ActionView #:nodoc: attr_accessor :controller attr_internal :captures + def reset_formats(formats) + @formats = formats + + if defined?(ActionController) + # This is expensive, but we need to reset this when the format is updated, + # which currently only happens + Thread.current[:format_locale_key] = + ActionController::HashKey.get(self.class, formats, I18n.locale) + end + end + class << self delegate :erb_trim_mode=, :to => 'ActionView::TemplateHandlers::ERB' delegate :logger, :to => 'ActionController::Base', :allow_nil => true @@ -240,7 +251,7 @@ module ActionView #:nodoc: end def initialize(view_paths = [], assigns_for_first_render = {}, controller = nil, formats = nil)#:nodoc: - @formats = formats || [:html] + @formats = formats @assigns = assigns_for_first_render.each { |key, value| instance_variable_set("@#{key}", value) } @controller = controller @helpers = self.class.helpers || Module.new @@ -255,15 +266,6 @@ module ActionView #:nodoc: @view_paths = self.class.process_view_paths(paths) end - def with_template(current_template) - _evaluate_assigns_and_ivars - last_template, self.template = template, current_template - last_formats, self.formats = formats, current_template.formats - yield - ensure - self.template, self.formats = last_template, last_formats - end - def punctuate_body!(part) flush_output_buffer response.body_parts << part @@ -272,18 +274,11 @@ module ActionView #:nodoc: # Evaluates the local assigns and controller ivars, pushes them to the view. def _evaluate_assigns_and_ivars #:nodoc: - @assigns_added ||= _copy_ivars_from_controller - end - - private - - def _copy_ivars_from_controller #:nodoc: if @controller variables = @controller.instance_variable_names variables -= @controller.protected_instance_variables if @controller.respond_to?(:protected_instance_variables) variables.each { |name| instance_variable_set(name, @controller.instance_variable_get(name)) } end - true end end diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index 624b537ad2..03f1dabb4e 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -991,12 +991,13 @@ module ActionView def render(*options_for_render) old_formats = @context && @context.formats - @context.formats = [:html] if @context + + @context.reset_formats([:html]) if @context Hash === options_for_render.first ? @context.render(*options_for_render) : options_for_render.first.to_s ensure - @context.formats = old_formats if @context + @context.reset_formats(old_formats) if @context end def javascript_object_for(object) diff --git a/actionpack/lib/action_view/render/partials.rb b/actionpack/lib/action_view/render/partials.rb index 83175ab4cf..7f10f54d2e 100644 --- a/actionpack/lib/action_view/render/partials.rb +++ b/actionpack/lib/action_view/render/partials.rb @@ -173,44 +173,50 @@ module ActionView extend ActiveSupport::Concern class PartialRenderer - def self.partial_names - @partial_names ||= Hash.new {|h,k| h[k] = ActiveSupport::ConcurrentHash.new } - end + PARTIAL_NAMES = Hash.new {|h,k| h[k] = {} } + TEMPLATES = Hash.new {|h,k| h[k] = {} } - def self.formats - @formats ||= Hash.new {|h,k| h[k] = Hash.new{|h,k| h[k] = Hash.new {|h,k| h[k] = {}}}} - end + attr_reader :template def initialize(view_context, options, block) - partial = options[:partial] - - @memo = {} @view = view_context - @options = options - @locals = options[:locals] || {} - @block = block - - # Set up some instance variables to speed up memoizing - @partial_names = self.class.partial_names[@view.controller.class] - @templates = self.class.formats - @format = view_context.formats - - # Set up the object and path - @object = partial.is_a?(String) ? options[:object] : partial - @path = partial_path(partial) + @partial_names = PARTIAL_NAMES[@view.controller.class] + + key = Thread.current[:format_locale_key] + @templates = TEMPLATES[key] if key + + setup(options, block) + end + + def setup(options, block) + partial = options[:partial] + + @options = options + @locals = options[:locals] || {} + @block = block + + if String === partial + @object = options[:object] + @path = partial + else + @object = partial + @path = partial_path(partial) + end end def render - return render_collection if collection - - template = find_template - render_template(template, @object || @locals[template.variable_name]) + if @collection = collection + render_collection + else + @template = template = find_template + render_template(template, @object || @locals[template.variable_name]) + end end def render_collection - @options[:_template] = template = find_template + @template = template = find_template - return nil if collection.blank? + return nil if @collection.blank? if @options.key?(:spacer_template) spacer = find_template(@options[:spacer_template]).render(@view, @locals) @@ -223,57 +229,58 @@ module ActionView def collection_with_template(template) options = @options - segments, locals, as = [], @locals, options[:as] || :object + segments, locals, as = [], @locals, options[:as] || template.variable_name - variable_name = template.variable_name counter_name = template.counter_name locals[counter_name] = -1 - collection.each do |object| + @collection.each do |object| locals[counter_name] += 1 - locals[variable_name] = object - locals[as] = object if as + locals[as] = object segments << template.render(@view, locals) end + + @template = template segments end def collection_without_template options = @options - segments, locals, as = [], @locals, options[:as] || :object + segments, locals, as = [], @locals, options[:as] index, template = -1, nil - collection.each do |object| + @collection.each do |object| template = find_template(partial_path(object)) locals[template.counter_name] = (index += 1) locals[template.variable_name] = object - locals[as] = object if as segments << template.render(@view, locals) end - @options[:_template] = template + @template = template segments end def render_template(template, object = @object) - @options[:_template] ||= template + options, locals, view = @options, @locals, @view + locals[options[:as] || template.variable_name] = object - # TODO: is locals[:object] really necessary? - @locals[:object] = @locals[template.variable_name] = object - @locals[@options[:as]] = object if @options[:as] + content = template.render(view, locals) do |*name| + @view._layout_for(*name, &@block) + end - content = @view._render_single_template(template, @locals, &@block) - return content if @block || !@options[:layout] - find_template(@options[:layout]).render(@view, @locals) { content } + if @block || !options[:layout] + content + else + find_template(options[:layout]).render(@view, @locals) { content } + end end - private def collection - @collection ||= if @object.respond_to?(:to_ary) + if @object.respond_to?(:to_ary) @object elsif @options.key?(:collection) @options[:collection] || [] @@ -281,15 +288,19 @@ module ActionView end def find_template(path = @path) - return if !path - @templates[path][@view.controller_path][@format][I18n.locale] ||= begin - prefix = @view.controller.controller_path unless path.include?(?/) - @view.find(path, {:formats => @view.formats}, prefix, true) + unless @templates + path && _find_template(path) + else + path && @templates[path] ||= _find_template(path) end end + + def _find_template(path) + prefix = @view.controller.controller_path unless path.include?(?/) + @view.find(path, {:formats => @view.formats}, prefix, true) + end def partial_path(object = @object) - return object if object.is_a?(String) @partial_names[object.class] ||= begin return nil unless object.respond_to?(:to_model) @@ -302,14 +313,26 @@ module ActionView end def render_partial(options) - @assigns_added = false - # TODO: Handle other details here. - self.formats = options[:_details][:formats] if options[:_details] - _render_partial(options) + _evaluate_assigns_and_ivars + + details = options[:_details] + + # Is this needed + self.formats = details[:formats] if details + renderer = PartialRenderer.new(self, options, nil) + text = renderer.render + options[:_template] = renderer.template + text end def _render_partial(options, &block) #:nodoc: - PartialRenderer.new(self, options, block).render + if @renderer + @renderer.setup(options, block) + else + @renderer = PartialRenderer.new(self, options, block) + end + + @renderer.render end end diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index c7afc56e3b..b0b75918b7 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -12,8 +12,6 @@ module ActionView # as the locals hash. def render(options = {}, locals = {}, &block) #:nodoc: case options - when String, NilClass - _render_partial(:partial => options, :locals => locals || {}) when Hash layout = options[:layout] @@ -35,26 +33,8 @@ module ActionView end when :update update_page(&block) - end - end - - def _render_content(content, layout, locals) - return content unless layout - - locals ||= {} - - if controller && layout - @_layout = layout.identifier - logger.info("Rendering template within #{layout.identifier}") if logger - end - - begin - old_content, @_content_for[:layout] = @_content_for[:layout], content - - @cached_content_for_layout = @_content_for[:layout] - _render_single_template(layout, locals) - ensure - @_content_for[:layout] = old_content + else + _render_partial(:partial => options, :locals => locals) end end @@ -90,48 +70,25 @@ module ActionView # In this case, the layout would receive the block passed into <tt>render :layout</tt>, # and the Struct specified in the layout would be passed into the block. The result # would be <html>Hello David</html>. - def _layout_for(names, &block) - with_output_buffer do - # This is due to the potentially ambiguous use of yield when - # a block is passed in to a template *and* there is a content_for() - # of the same name. Suggested solution: require explicit use of content_for - # in these ambiguous cases. - # - # We would be able to continue supporting yield in all non-ambiguous - # cases. Question: should we deprecate yield in favor of content_for - # and reserve yield for cases where there is a yield into a real block? - if @_content_for.key?(names.first) || !block_given? - return @_content_for[names.first || :layout] - else - return yield(names) - end - end - end + def _layout_for(name = nil) + return @_content_for[name || :layout] if !block_given? || name - def _render_single_template(template, locals = {}, &block) - with_template(template) do - template.render(self, locals) do |*names| - _layout_for(names, &block) - end - end - rescue Exception => e - if e.is_a?(TemplateError) - e.sub_template_of(template) - raise e - else - raise TemplateError.new(template, assigns, e) + with_output_buffer do + return yield end end def _render_inline(inline, layout, options) handler = Template.handler_class_for_extension(options[:type] || "erb") template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) - content = _render_single_template(template, options[:locals] || {}) - layout ? _render_content(content, layout, options[:locals]) : content + locals = options[:locals] || {} + content = template.render(self, locals) + content = layout.render(self, locals) {|*name| _layout_for(*name) { content } } if layout + content end def _render_text(text, layout, options) - layout ? _render_content(text, layout, options[:locals]) : text + text = layout.render(self, options[:locals]) { text } if layout end # This is the API to render a ViewContext's template from a controller. @@ -141,7 +98,7 @@ module ActionView # _layout:: The layout, if any, to wrap the Template in # _partial:: true if the template is a partial def render_template(options) - @assigns_added = nil + _evaluate_assigns_and_ivars template, layout, partial = options.values_at(:_template, :_layout, :_partial) _render_template(template, layout, options, partial) end @@ -158,10 +115,18 @@ module ActionView content = if partial _render_partial_object(template, options) else - _render_single_template(template, locals) + template.render(self, locals) end - _render_content(content, layout, locals) + @cached_content_for_layout = content + @_content_for[:layout] = content + + if layout + @_layout = layout.identifier + logger.info("Rendering template within #{layout.identifier}") if logger + content = layout.render(self, locals) {|*name| _layout_for(*name) } + end + content end end end
\ No newline at end of file diff --git a/actionpack/lib/action_view/template/handler.rb b/actionpack/lib/action_view/template/handler.rb index 3071c78174..4bf58b9fa8 100644 --- a/actionpack/lib/action_view/template/handler.rb +++ b/actionpack/lib/action_view/template/handler.rb @@ -26,11 +26,7 @@ module ActionView self.default_format = Mime::HTML def self.call(template) - "#{name}.new(self).render(template, local_assigns)" - end - - def initialize(view = nil) - @view = view + raise "Need to implement #{self.class.name}#call(template)" end def render(template, local_assigns) diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index 10f664736f..fe657166d5 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -42,7 +42,7 @@ module ActionView def handler_glob @handler_glob ||= begin - e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join + e = TemplateHandlers.extensions.map{|h| ".#{h}"}.join(",") "{#{e}}" end end diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index 33d3f79ad3..7d6964e3e3 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -26,9 +26,16 @@ module ActionView @details[:formats] = Array.wrap(format.to_sym) end - def render(view, locals, &blk) + def render(view, locals, &block) method_name = compile(locals, view) - view.send(method_name, locals, &blk) + view.send(method_name, locals, &block) + rescue Exception => e + if e.is_a?(TemplateError) + e.sub_template_of(self) + raise e + else + raise TemplateError.new(self, view.assigns, e) + end end # TODO: Figure out how to abstract this @@ -90,7 +97,22 @@ module ActionView raise ActionView::TemplateError.new(self, {}, e) end end - + + class LocalsKey + @hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } } + + def self.get(*locals) + @hash_keys[*locals] ||= new(klass, format, locale) + end + + attr_accessor :hash + def initialize(klass, format, locale) + @hash = locals.hash + end + + alias_method :eql?, :equal? + end + def build_method_name(locals) # TODO: is locals.keys.hash reliably the same? @method_names[locals.keys.hash] ||= |