diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2009-04-30 13:29:33 +0100 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2009-04-30 13:29:33 +0100 |
commit | 5f24ed718f92abe97fc3f50a36c9fb09499d0173 (patch) | |
tree | d097bb0e59c4a31c262fe83081e396219e7186bd /actionpack/lib/action_view | |
parent | 35ca877abc889d863747726e3da6e359ba928506 (diff) | |
parent | 79420e71e0e75d6f81e5284184bac4e7d0b02c30 (diff) | |
download | rails-5f24ed718f92abe97fc3f50a36c9fb09499d0173.tar.gz rails-5f24ed718f92abe97fc3f50a36c9fb09499d0173.tar.bz2 rails-5f24ed718f92abe97fc3f50a36c9fb09499d0173.zip |
Merge commit 'mainstream/master'
Diffstat (limited to 'actionpack/lib/action_view')
-rw-r--r-- | actionpack/lib/action_view/base.rb | 6 | ||||
-rw-r--r-- | actionpack/lib/action_view/helpers/prototype_helper.rb | 20 | ||||
-rw-r--r-- | actionpack/lib/action_view/paths.rb | 12 | ||||
-rw-r--r-- | actionpack/lib/action_view/render/rendering.rb | 13 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/error.rb | 4 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/path.rb | 68 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/template.rb | 216 | ||||
-rw-r--r-- | actionpack/lib/action_view/test_case.rb | 12 |
9 files changed, 135 insertions, 218 deletions
diff --git a/actionpack/lib/action_view/base.rb b/actionpack/lib/action_view/base.rb index efed19a21d..44bd401631 100644 --- a/actionpack/lib/action_view/base.rb +++ b/actionpack/lib/action_view/base.rb @@ -191,12 +191,14 @@ module ActionView #:nodoc: ActionController::Base.allow_concurrency || (cache_template_loading.nil? ? !ActiveSupport::Dependencies.load? : cache_template_loading) end - attr_internal :request + attr_internal :request, :layout 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 + :flash, :action_name, :controller_name, :to => :controller + + delegate :logger, :to => :controller, :allow_nil => true delegate :find_by_parts, :to => :view_paths diff --git a/actionpack/lib/action_view/helpers/prototype_helper.rb b/actionpack/lib/action_view/helpers/prototype_helper.rb index fb8122af35..1fbe012a95 100644 --- a/actionpack/lib/action_view/helpers/prototype_helper.rb +++ b/actionpack/lib/action_view/helpers/prototype_helper.rb @@ -686,7 +686,7 @@ module ActionView # Returns an object whose <tt>to_json</tt> evaluates to +code+. Use this to pass a literal JavaScript # expression as an argument to another JavaScriptGenerator method. def literal(code) - ActiveSupport::JSON::Variable.new(code.to_s) + ::ActiveSupport::JSON::Variable.new(code.to_s) end # Returns a collection reference by finding it through a CSS +pattern+ in the DOM. This collection can then be @@ -973,7 +973,7 @@ module ActionView def loop_on_multiple_args(method, ids) record(ids.size>1 ? "#{javascript_object_for(ids)}.each(#{method})" : - "#{method}(#{ActiveSupport::JSON.encode(ids.first)})") + "#{method}(#{javascript_object_for(ids.first)})") end def page @@ -997,7 +997,7 @@ module ActionView end def javascript_object_for(object) - ActiveSupport::JSON.encode(object) + ::ActiveSupport::JSON.encode(object) end def arguments_for_call(arguments, block = nil) @@ -1139,7 +1139,7 @@ module ActionView class JavaScriptElementProxy < JavaScriptProxy #:nodoc: def initialize(generator, id) @id = id - super(generator, "$(#{ActiveSupport::JSON.encode(id)})") + super(generator, "$(#{::ActiveSupport::JSON.encode(id)})") end # Allows access of element attributes through +attribute+. Examples: @@ -1180,16 +1180,14 @@ module ActionView # The JSON Encoder calls this to check for the +to_json+ method # Since it's a blank slate object, I suppose it responds to anything. - def respond_to?(method) + def respond_to?(*) true end - def rails_to_json(options = nil) + def rails_to_json(*) @variable end - alias to_json rails_to_json - private def append_to_function_chain!(call) @generator << @variable if @empty @@ -1213,7 +1211,7 @@ module ActionView enumerate :eachSlice, :variable => variable, :method_args => [number], :yield_args => %w(value index), :return => true, &block else add_variable_assignment!(variable) - append_enumerable_function!("eachSlice(#{ActiveSupport::JSON.encode(number)});") + append_enumerable_function!("eachSlice(#{::ActiveSupport::JSON.encode(number)});") end end @@ -1234,7 +1232,7 @@ module ActionView def pluck(variable, property) add_variable_assignment!(variable) - append_enumerable_function!("pluck(#{ActiveSupport::JSON.encode(property)});") + append_enumerable_function!("pluck(#{::ActiveSupport::JSON.encode(property)});") end def zip(variable, *arguments, &block) @@ -1298,7 +1296,7 @@ module ActionView class JavaScriptElementCollectionProxy < JavaScriptCollectionProxy #:nodoc:\ def initialize(generator, pattern) - super(generator, "$$(#{ActiveSupport::JSON.encode(pattern)})") + super(generator, "$$(#{::ActiveSupport::JSON.encode(pattern)})") end end end diff --git a/actionpack/lib/action_view/paths.rb b/actionpack/lib/action_view/paths.rb index e48088f344..f6d021c92a 100644 --- a/actionpack/lib/action_view/paths.rb +++ b/actionpack/lib/action_view/paths.rb @@ -3,7 +3,7 @@ module ActionView #:nodoc: def self.type_cast(obj) if obj.is_a?(String) cache = !Object.const_defined?(:Rails) || Rails.configuration.cache_classes - Template::FileSystemPath.new(obj, :cache => cache) + Template::FileSystemPathWithFallback.new(obj, :cache => cache) else obj end @@ -34,18 +34,18 @@ module ActionView #:nodoc: end def find_by_parts(path, details = {}, prefix = nil, partial = false) - template_path = path.sub(/^\//, '') + # template_path = path.sub(/^\//, '') + template_path = path each do |load_path| if template = load_path.find_by_parts(template_path, details, prefix, partial) return template end end - - Template.new(path, self) - rescue ActionView::MissingTemplate => e + + # TODO: Have a fallback absolute path? extension = details[:formats] || [] - raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path}.{#{extension.join(",")}}") + raise ActionView::MissingTemplate.new(self, "#{prefix}/#{path} - #{details.inspect} - partial: #{!!partial}") end def find_by_parts?(path, extension = nil, prefix = nil, partial = false) diff --git a/actionpack/lib/action_view/render/rendering.rb b/actionpack/lib/action_view/render/rendering.rb index 4213b09e48..6e368f27eb 100644 --- a/actionpack/lib/action_view/render/rendering.rb +++ b/actionpack/lib/action_view/render/rendering.rb @@ -46,8 +46,8 @@ module ActionView 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 + @_layout = layout.identifier + logger.info("Rendering template within #{layout.identifier}") if logger end begin @@ -76,7 +76,6 @@ module ActionView end end rescue Exception => e - raise e if template.is_a?(InlineTemplate) || !template.filename if TemplateError === e e.sub_template_of(template) raise e @@ -86,7 +85,9 @@ module ActionView end def _render_inline(inline, layout, options) - content = _render_template(InlineTemplate.new(options[:inline], options[:type]), options[:locals] || {}) + handler = Template.handler_class_for_extension(options[:type] || "erb") + template = Template.new(options[:inline], "inline #{options[:inline].inspect}", handler, {}) + content = _render_template(template, options[:locals] || {}) layout ? _render_content_with_layout(content, layout, options[:locals]) : content end @@ -96,7 +97,7 @@ module ActionView def _render_template_with_layout(template, layout = nil, options = {}, partial = false) if controller && logger - logger.info("Rendering #{template.path_without_extension}" + + logger.info("Rendering #{template.identifier}" + (options[:status] ? " (#{options[:status]})" : '')) end @@ -107,7 +108,7 @@ module ActionView _render_template(template, options[:locals] || {}) end - return content unless layout && !template.exempt_from_layout? + return content unless layout _render_content_with_layout(content, layout, options[:locals] || {}) end end diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 37cb1c7c6c..a06e80b294 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -12,7 +12,7 @@ module ActionView end def file_name - @template.relative_path + @template.identifier end def message @@ -30,7 +30,7 @@ module ActionView def sub_template_message if @sub_templates "Trace of template inclusion: " + - @sub_templates.collect { |template| template.relative_path }.join(", ") + @sub_templates.collect { |template| template.identifier }.join(", ") else "" end diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index 448ab6731b..0590372d09 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -46,7 +46,7 @@ module ActionView #:nodoc: end def handler_class_for_extension(extension) - registered_template_handler(extension) || @@default_template_handlers + (extension && registered_template_handler(extension.to_sym)) || @@default_template_handlers end end end diff --git a/actionpack/lib/action_view/template/path.rb b/actionpack/lib/action_view/template/path.rb index 660a7e91a2..478bf96c9a 100644 --- a/actionpack/lib/action_view/template/path.rb +++ b/actionpack/lib/action_view/template/path.rb @@ -1,3 +1,5 @@ +require "pathname" + module ActionView class Template # Abstract super class @@ -26,13 +28,6 @@ module ActionView def find_templates(name, details, prefix, partial) raise NotImplementedError end - - # TODO: Refactor this to abstract out the file system - def initialize_template(file) - t = Template.new(file.split("#{self}/").last, self) - t.load! - t - end def valid_handlers @valid_handlers ||= TemplateHandlers.extensions @@ -44,10 +39,10 @@ module ActionView /\.(?:#{e})$/ end end - + def handler_glob - e = TemplateHandlers.extensions.join(',') - ".{#{e}}" + e = TemplateHandlers.extensions.map{|h| ".#{h},"}.join + "{#{e}}" end def formats_glob @@ -69,23 +64,19 @@ module ActionView def initialize(path, options = {}) raise ArgumentError, "path already is a Path class" if path.is_a?(Path) super(options) - @path = path + @path = Pathname.new(path).expand_path end - + # TODO: This is the currently needed API. Make this suck less # ==== <suck> attr_reader :path def to_s - if defined?(RAILS_ROOT) - path.to_s.sub(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') - else - path.to_s - end + path.to_s end def to_str - path.to_str + path.to_s end def ==(path) @@ -97,11 +88,15 @@ module ActionView end # ==== </suck> - def find_templates(name, details, prefix, partial) - if glob = parts_to_glob(name, details, prefix, partial) + def find_templates(name, details, prefix, partial, root = "#{@path}/") + if glob = details_to_glob(name, details, prefix, partial, root) cached(glob) do Dir[glob].map do |path| - initialize_template(path) unless File.directory?(path) + next if File.directory?(path) + source = File.read(path) + identifier = Pathname.new(path).expand_path.to_s + + Template.new(source, identifier, *path_to_details(path)) end.compact end end @@ -109,7 +104,8 @@ module ActionView private - def parts_to_glob(name, details, prefix, partial) + # :api: plugin + def details_to_glob(name, details, prefix, partial, root) path = "" path << "#{prefix}/" unless prefix.empty? path << (partial ? "_#{name}" : name) @@ -123,8 +119,34 @@ module ActionView end end - "#{@path}/#{path}#{extensions}#{handler_glob}" + "#{root}#{path}#{extensions}#{handler_glob}" + end + + # TODO: fix me + # :api: plugin + def path_to_details(path) + # [:erb, :format => :html, :locale => :en, :partial => true/false] + if m = path.match(%r'/(_)?[\w-]+(\.[\w-]+)*\.(\w+)$') + partial = m[1] == '_' + details = (m[2]||"").split('.').reject { |e| e.empty? } + handler = Template.handler_class_for_extension(m[3]) + + format = Mime[details.last] && details.pop.to_sym + locale = details.last && details.pop.to_sym + + return handler, :format => format, :locale => locale, :partial => partial + end end end + + class FileSystemPathWithFallback < FileSystemPath + + def find_templates(name, details, prefix, partial) + templates = super + return super(name, details, prefix, partial, '') if templates.empty? + templates + end + + end end end
\ No newline at end of file diff --git a/actionpack/lib/action_view/template/template.rb b/actionpack/lib/action_view/template/template.rb index e541336613..dcc5006103 100644 --- a/actionpack/lib/action_view/template/template.rb +++ b/actionpack/lib/action_view/template/template.rb @@ -1,188 +1,80 @@ +# encoding: utf-8 +# This is so that templates compiled in this file are UTF-8 + require 'set' require "action_view/template/path" -module ActionView #:nodoc: +module ActionView class Template extend TemplateHandlers - extend ActiveSupport::Memoizable - - module Loading - def load! - @cached = true - # freeze - end - end - include Loading - - include Renderable - - # Templates that are exempt from layouts - @@exempt_from_layout = Set.new([/\.rjs$/]) - - # Don't render layouts for templates with the given extensions. - def self.exempt_from_layout(*extensions) - regexps = extensions.collect do |extension| - extension.is_a?(Regexp) ? extension : /\.#{Regexp.escape(extension.to_s)}$/ - end - @@exempt_from_layout.merge(regexps) - end - - attr_accessor :template_path, :filename, :load_path, :base_path - attr_accessor :locale, :name, :format, :extension - delegate :to_s, :to => :path - - def initialize(template_path, load_paths = []) - template_path = template_path.dup - @load_path, @filename = find_full_path(template_path, load_paths) - @base_path, @name, @locale, @format, @extension = split(template_path) - @base_path.to_s.gsub!(/\/$/, '') # Push to split method - - # Extend with partial super powers - extend RenderablePartial if @name =~ /^_/ - end + attr_reader :source, :identifier, :handler - def accessible_paths - paths = [] - - if valid_extension?(extension) - paths << path - paths << path_without_extension - if multipart? - formats = format.split(".") - paths << "#{path_without_format_and_extension}.#{formats.first}" - paths << "#{path_without_format_and_extension}.#{formats.second}" - end - else - # template without explicit template handler should only be reachable through its exact path - paths << template_path - end - - paths + def initialize(source, identifier, handler, details) + @source = source + @identifier = identifier + @handler = handler + @details = details end - def relative_path - path = File.expand_path(filename) - path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT) - path + def render(view, locals, &blk) + method_name = compile(locals, view) + view.send(method_name, locals, &blk) end - memoize :relative_path - def source - File.read(filename) + # TODO: Figure out how to abstract this + def variable_name + identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym end - memoize :source - - def exempt_from_layout? - @@exempt_from_layout.any? { |exempted| path =~ exempted } - end - - def path_without_extension - [base_path, [name, locale, format].compact.join('.')].compact.join('/') - end - memoize :path_without_extension - def path_without_format_and_extension - [base_path, [name, locale].compact.join('.')].compact.join('/') + # TODO: Figure out how to abstract this + def counter_name + "#{variable_name}_counter".to_sym end - memoize :path_without_format_and_extension - def path - [base_path, [name, locale, format, extension].compact.join('.')].compact.join('/') + # TODO: kill hax + def partial? + @details[:partial] end - memoize :path + # TODO: Move out of Template def mime_type - Mime::Type.lookup_by_extension(format) if format && defined?(::Mime) + Mime::Type.lookup_by_extension(@details[:format].to_s) if @details[:format] end - memoize :mime_type - - def multipart? - format && format.include?('.') - end - - def content_type - format && format.gsub('.', '/') - end private - - def format_and_extension - (extensions = [format, extension].compact.join(".")).blank? ? nil : extensions - end - memoize :format_and_extension - - def mtime - File.mtime(filename) - end - memoize :mtime - - def method_segment - relative_path.to_s.gsub(/([^a-zA-Z0-9_])/) { $1.ord } - end - memoize :method_segment - - def stale? - File.mtime(filename) > mtime - end - - def recompile? - !@cached - end - - def valid_extension?(extension) - !Template.registered_template_handler(extension).nil? - end - def valid_locale?(locale) - I18n.available_locales.include?(locale.to_sym) - end + def compile(locals, view) + method_name = build_method_name(locals) + + return method_name if view.respond_to?(method_name) + + locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join + + source = <<-end_src + def #{method_name}(local_assigns) + old_output_buffer = output_buffer;#{locals_code};#{@handler.call(self)} + ensure + self.output_buffer = old_output_buffer + end + end_src + + begin + ActionView::Base::CompiledTemplates.module_eval(source, identifier, 0) + method_name + rescue Exception => e # errors from template code + if logger = (view && view.logger) + logger.debug "ERROR: compiling #{method_name} RAISED #{e}" + logger.debug "Function body: #{source}" + logger.debug "Backtrace: #{e.backtrace.join("\n")}" + end - def find_full_path(path, load_paths) - load_paths = Array(load_paths) + [nil] - load_paths.each do |load_path| - file = load_path ? "#{load_path.to_str}/#{path}" : path - return load_path, file if File.file?(file) + raise ActionView::TemplateError.new(self, {}, e) end - raise MissingTemplate.new(load_paths, path) end - - # Returns file split into an array - # [base_path, name, locale, format, extension] - def split(file) - if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/) - base_path = m[1] - name = m[2] - extensions = m[3] - else - return - end - - locale = nil - format = nil - extension = nil - - if m = extensions.split(".") - if valid_locale?(m[0]) && m[1] && valid_extension?(m[2]) # All three - locale = m[0] - format = m[1] - extension = m[2] - elsif m[0] && m[1] && valid_extension?(m[2]) # Multipart formats - format = "#{m[0]}.#{m[1]}" - extension = m[2] - elsif valid_locale?(m[0]) && valid_extension?(m[1]) # locale and extension - locale = m[0] - extension = m[1] - elsif valid_extension?(m[1]) # format and extension - format = m[0] - extension = m[1] - elsif valid_extension?(m[0]) # Just extension - extension = m[0] - else # No extension - format = m[0] - end - end - - [base_path, name, locale, format, extension] + + def build_method_name(locals) + # TODO: is locals.keys.hash reliably the same? + "_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_") end end -end +end
\ No newline at end of file diff --git a/actionpack/lib/action_view/test_case.rb b/actionpack/lib/action_view/test_case.rb index c8f204046b..50bed67f7d 100644 --- a/actionpack/lib/action_view/test_case.rb +++ b/actionpack/lib/action_view/test_case.rb @@ -7,15 +7,17 @@ module ActionView @_rendered = { :template => nil, :partials => Hash.new(0) } initialize_without_template_tracking(*args) end - + + attr_internal :rendered 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 + if template.respond_to?(:identifier) + @_rendered[:partials][template] += 1 if template.partial? + @_rendered[:template] ||= [] + @_rendered[:template] << template end _render_template_without_template_tracking(template, local_assigns) - end + end end class TestCase < ActiveSupport::TestCase |