diff options
Diffstat (limited to 'actionpack/lib/action_view/template')
-rw-r--r-- | actionpack/lib/action_view/template/error.rb | 5 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handler.rb | 10 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers.rb | 10 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers/builder.rb | 8 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers/erb.rb | 25 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers/rjs.rb | 12 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/inline.rb | 20 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/resolver.rb | 115 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/text.rb | 4 |
9 files changed, 144 insertions, 65 deletions
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb index 423e1e0bf5..ff256738a9 100644 --- a/actionpack/lib/action_view/template/error.rb +++ b/actionpack/lib/action_view/template/error.rb @@ -43,8 +43,9 @@ module ActionView end class Template - # The Template::Error exception is raised when the compilation of the template fails. This exception then gathers a - # bunch of intimate details and uses it to report a very precise exception message. + # The Template::Error exception is raised when the compilation or rendering of the template + # fails. This exception then gathers a bunch of intimate details and uses it to report a + # precise exception message. class Error < ActionViewError #:nodoc: SOURCE_CODE_RADIUS = 3 diff --git a/actionpack/lib/action_view/template/handler.rb b/actionpack/lib/action_view/template/handler.rb index c6a1bc6235..0a9d299807 100644 --- a/actionpack/lib/action_view/template/handler.rb +++ b/actionpack/lib/action_view/template/handler.rb @@ -1,4 +1,4 @@ -require "action_dispatch/http/mime_type" +require 'action_dispatch/http/mime_type' require 'active_support/core_ext/class/attribute' # Legacy TemplateHandler stub @@ -7,6 +7,8 @@ module ActionView module Handlers #:nodoc: module Compilable def self.included(base) + ActiveSupport::Deprecation.warn "Including Compilable in your template handler is deprecated. " << + "All the API your template handler needs to implement is to respond to #call." base.extend(ClassMethods) end @@ -26,6 +28,12 @@ module ActionView class_attribute :default_format self.default_format = Mime::HTML + def self.inherited(base) + ActiveSupport::Deprecation.warn "Inheriting from ActionView::Template::Handler is deprecated. " << + "All the API your template handler needs to implement is to respond to #call." + super + end + def self.call(template) raise "Need to implement #{self.class.name}#call(template)" end diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb index ed397699b0..60347e2a95 100644 --- a/actionpack/lib/action_view/template/handlers.rb +++ b/actionpack/lib/action_view/template/handlers.rb @@ -7,13 +7,9 @@ module ActionView #:nodoc: autoload :Builder, 'action_view/template/handlers/builder' def self.extended(base) - base.register_default_template_handler :erb, ERB - base.register_template_handler :rjs, RJS - base.register_template_handler :builder, Builder - - # TODO: Depreciate old template extensions - base.register_template_handler :rhtml, ERB - base.register_template_handler :rxml, Builder + base.register_default_template_handler :erb, ERB.new + base.register_template_handler :rjs, RJS.new + base.register_template_handler :builder, Builder.new end @@template_handlers = {} diff --git a/actionpack/lib/action_view/template/handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb index a93cfca8aa..2c52cfd90e 100644 --- a/actionpack/lib/action_view/template/handlers/builder.rb +++ b/actionpack/lib/action_view/template/handlers/builder.rb @@ -1,11 +1,11 @@ module ActionView module Template::Handlers - class Builder < Template::Handler - include Compilable - + class Builder + # Default format used by Builder. + class_attribute :default_format self.default_format = Mime::XML - def compile(template) + def call(template) require 'builder' "xml = ::Builder::XmlMarkup.new(:indent => 2);" + "self.output_buffer = xml.target!;" + diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb index 24e1e44c1d..b827610456 100644 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ b/actionpack/lib/action_view/template/handlers/erb.rb @@ -1,6 +1,7 @@ require 'active_support/core_ext/class/attribute_accessors' require 'active_support/core_ext/string/output_safety' -require "action_view/template" +require 'action_view/template' +require 'action_view/template/handler' require 'erubis' module ActionView @@ -47,28 +48,31 @@ module ActionView end end - class ERB < Handler - include Compilable - - ## - # :singleton-method: + class ERB # Specify trim mode for the ERB compiler. Defaults to '-'. # See ERb documentation for suitable values. - cattr_accessor :erb_trim_mode + class_attribute :erb_trim_mode self.erb_trim_mode = '-' + # Default format used by ERB. + class_attribute :default_format self.default_format = Mime::HTML - cattr_accessor :erb_implementation + # Default implemenation used. + class_attribute :erb_implementation self.erb_implementation = Erubis ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*") - def self.handles_encoding? + def self.call(template) + new.call(template) + end + + def handles_encoding? true end - def compile(template) + def call(template) if template.source.encoding_aware? # First, convert to BINARY, so in case the encoding is # wrong, we can still find an encoding tag @@ -94,6 +98,7 @@ module ActionView end private + def valid_encoding(string, encoding) # If a magic encoding comment was found, tag the # String with this encoding. This is for a case diff --git a/actionpack/lib/action_view/template/handlers/rjs.rb b/actionpack/lib/action_view/template/handlers/rjs.rb index 128be5077c..9d71059134 100644 --- a/actionpack/lib/action_view/template/handlers/rjs.rb +++ b/actionpack/lib/action_view/template/handlers/rjs.rb @@ -1,17 +1,13 @@ module ActionView module Template::Handlers - class RJS < Template::Handler - include Compilable - + class RJS + # Default format used by RJS. + class_attribute :default_format self.default_format = Mime::JS - def compile(template) + def call(template) "update_page do |page|;#{template.source}\nend" end - - def default_format - Mime::JS - end end end end diff --git a/actionpack/lib/action_view/template/inline.rb b/actionpack/lib/action_view/template/inline.rb new file mode 100644 index 0000000000..be08065b6b --- /dev/null +++ b/actionpack/lib/action_view/template/inline.rb @@ -0,0 +1,20 @@ +require 'digest/md5' + +module ActionView + class Template + class Inline < ::ActionView::Template + def initialize(source, handler, options={}) + super(source, "inline template", handler, options) + end + + def md5_source + @md5_source ||= Digest::MD5.hexdigest(source) + end + + def eql?(other) + other.is_a?(Inline) && other.md5_source == md5_source + end + end + end +end +
\ No newline at end of file diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb index a261e08dbc..7707dbcf98 100644 --- a/actionpack/lib/action_view/template/resolver.rb +++ b/actionpack/lib/action_view/template/resolver.rb @@ -6,9 +6,8 @@ module ActionView # = Action View Resolver class Resolver def initialize - @path = nil - @cached = Hash.new { |h1,k1| h1[k1] = - Hash.new { |h2,k2| h2[k2] = Hash.new { |h3, k3| h3[k3] = {} } } } + @cached = Hash.new { |h1,k1| h1[k1] = Hash.new { |h2,k2| + h2[k2] = Hash.new { |h3,k3| h3[k3] = Hash.new { |h4,k4| h4[k4] = {} } } } } end def clear_cache @@ -16,8 +15,8 @@ module ActionView end # Normalizes the arguments and passes it on to find_template. - def find_all(name, prefix=nil, partial=false, details={}, key=nil) - cached(key, prefix, name, partial) do + def find_all(name, prefix=nil, partial=false, details={}, locals=[], key=nil) + cached(key, [name, prefix, partial], details, locals) do find_templates(name, prefix, partial, details) end end @@ -35,34 +34,73 @@ module ActionView raise NotImplementedError end - def cached(key, prefix, name, partial) - return yield unless key && caching? - @cached[key][prefix][name][partial] ||= yield + # Helpers that builds a path. Useful for building virtual paths. + def build_path(name, prefix, partial) + path = "" + path << "#{prefix}/" unless prefix.empty? + path << (partial ? "_#{name}" : name) + path + end + + # Hnadles templates caching. If a key is given and caching is on + # always check the cache before hitting the resolver. Otherwise, + # it always hits the resolver but check if the resolver is fresher + # before returning it. + def cached(key, path_info, details, locals) #:nodoc: + name, prefix, partial = path_info + locals = sort_locals(locals) + + if key && caching? + @cached[key][name][prefix][partial][locals] ||= decorate(yield, path_info, details, locals) + else + fresh = decorate(yield, path_info, details, locals) + return fresh unless key + + scope = @cached[key][name][prefix][partial] + cache = scope[locals] + mtime = cache && cache.map(&:updated_at).max + + if !mtime || fresh.empty? || fresh.any? { |t| t.updated_at > mtime } + scope[locals] = fresh + else + cache + end + end + end + + # Ensures all the resolver information is set in the template. + def decorate(templates, path_info, details, locals) #:nodoc: + cached = nil + templates.each do |t| + t.locals = locals + t.formats = details[:formats] || [:html] if t.formats.empty? + t.virtual_path ||= (cached ||= build_path(*path_info)) + end + end + + if :symbol.respond_to?("<=>") + def sort_locals(locals) #:nodoc: + locals.sort.freeze + end + else + def sort_locals(locals) #:nodoc: + locals = locals.map{ |l| l.to_s } + locals.sort! + locals.freeze + end end end class PathResolver < Resolver EXTENSION_ORDER = [:locale, :formats, :handlers] - def to_s - @path.to_s - end - alias :to_path :to_s - - private + private def find_templates(name, prefix, partial, details) - path = build_path(name, prefix, partial, details) + path = build_path(name, prefix, partial) query(path, EXTENSION_ORDER.map { |ext| details[ext] }, details[:formats]) end - def build_path(name, prefix, partial, details) - path = "" - path << "#{prefix}/" unless prefix.empty? - path << (partial ? "_#{name}" : name) - path - end - def query(path, exts, formats) query = File.join(@path, path) @@ -76,26 +114,28 @@ module ActionView contents = File.open(p, "rb") {|io| io.read } Template.new(contents, File.expand_path(p), handler, - :virtual_path => path, :format => format) + :virtual_path => path, :format => format, :updated_at => mtime(p)) end end + # Returns the file mtime from the filesystem. + def mtime(p) + File.stat(p).mtime + end + # Extract handler and formats from path. If a format cannot be a found neither # from the path, or the handler, we should return the array of formats given # to the resolver. def extract_handler_and_format(path, default_formats) pieces = File.basename(path).split(".") pieces.shift - - handler = Template.handler_class_for_extension(pieces.pop) - format = pieces.last && Mime[pieces.last] && pieces.pop.to_sym - format ||= handler.default_format if handler.respond_to?(:default_format) - format ||= default_formats - + handler = Template.handler_class_for_extension(pieces.pop) + format = pieces.last && Mime[pieces.last] [handler, format] end end + # A resolver that loads files from the filesystem. class FileSystemResolver < PathResolver def initialize(path) raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver) @@ -103,9 +143,26 @@ module ActionView @path = File.expand_path(path) end + def to_s + @path.to_s + end + alias :to_path :to_s + def eql?(resolver) self.class.equal?(resolver.class) && to_path == resolver.to_path end alias :== :eql? end + + # The same as FileSystemResolver but does not allow templates to store + # a virtual path since it is invalid for such resolvers. + class FallbackFileSystemResolver < FileSystemResolver + def self.instances + [new(""), new("/")] + end + + def decorate(*) + super.each { |t| t.virtual_path = nil } + end + end end diff --git a/actionpack/lib/action_view/template/text.rb b/actionpack/lib/action_view/template/text.rb index 51be831dfb..4261c3b5e2 100644 --- a/actionpack/lib/action_view/template/text.rb +++ b/actionpack/lib/action_view/template/text.rb @@ -25,10 +25,6 @@ module ActionView #:nodoc: def formats [@mime_type.to_sym] end - - def partial? - false - end end end end |