diff options
Diffstat (limited to 'actionpack/lib/action_view/template')
-rw-r--r-- | actionpack/lib/action_view/template/error.rb | 138 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers.rb | 53 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers/builder.rb | 26 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers/erb.rb | 120 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/handlers/raw.rb | 11 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/resolver.rb | 326 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/text.rb | 34 | ||||
-rw-r--r-- | actionpack/lib/action_view/template/types.rb | 57 |
8 files changed, 0 insertions, 765 deletions
diff --git a/actionpack/lib/action_view/template/error.rb b/actionpack/lib/action_view/template/error.rb deleted file mode 100644 index a89d51221e..0000000000 --- a/actionpack/lib/action_view/template/error.rb +++ /dev/null @@ -1,138 +0,0 @@ -require "active_support/core_ext/enumerable" - -module ActionView - # = Action View Errors - class ActionViewError < StandardError #:nodoc: - end - - class EncodingError < StandardError #:nodoc: - end - - class MissingRequestError < StandardError #:nodoc: - end - - class WrongEncodingError < EncodingError #:nodoc: - def initialize(string, encoding) - @string, @encoding = string, encoding - end - - def message - @string.force_encoding(Encoding::ASCII_8BIT) - "Your template was not saved as valid #{@encoding}. Please " \ - "either specify #{@encoding} as the encoding for your template " \ - "in your text editor, or mark the template with its " \ - "encoding by inserting the following as the first line " \ - "of the template:\n\n# encoding: <name of correct encoding>.\n\n" \ - "The source of your template was:\n\n#{@string}" - end - end - - class MissingTemplate < ActionViewError #:nodoc: - attr_reader :path - - def initialize(paths, path, prefixes, partial, details, *) - @path = path - prefixes = Array(prefixes) - template_type = if partial - "partial" - elsif path =~ /layouts/i - 'layout' - else - 'template' - end - - searched_paths = prefixes.map { |prefix| [prefix, path].join("/") } - - out = "Missing #{template_type} #{searched_paths.join(", ")} with #{details.inspect}. Searched in:\n" - out += paths.compact.map { |p| " * #{p.to_s.inspect}\n" }.join - super out - end - end - - class Template - # 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 - - attr_reader :original_exception, :backtrace - - def initialize(template, original_exception) - super(original_exception.message) - @template, @original_exception = template, original_exception - @sub_templates = nil - @backtrace = original_exception.backtrace - end - - def file_name - @template.identifier - end - - def sub_template_message - if @sub_templates - "Trace of template inclusion: " + - @sub_templates.collect { |template| template.inspect }.join(", ") - else - "" - end - end - - def source_extract(indentation = 0, output = :console) - return unless num = line_number - num = num.to_i - - source_code = @template.source.split("\n") - - start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max - end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min - - indent = end_on_line.to_s.size + indentation - return unless source_code = source_code[start_on_line..end_on_line] - - formatted_code_for(source_code, start_on_line, indent, output) - end - - def sub_template_of(template_path) - @sub_templates ||= [] - @sub_templates << template_path - end - - def line_number - @line_number ||= - if file_name - regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/ - $1 if message =~ regexp || backtrace.find { |line| line =~ regexp } - end - end - - def annoted_source_code - source_extract(4) - end - - private - - def source_location - if line_number - "on line ##{line_number} of " - else - 'in ' - end + file_name - end - - def formatted_code_for(source_code, line_counter, indent, output) - start_value = (output == :html) ? {} : "" - source_code.inject(start_value) do |result, line| - line_counter += 1 - if output == :html - result.update(line_counter.to_s => "%#{indent}s %s\n" % ["", line]) - else - result << "%#{indent}s: %s\n" % [line_counter, line] - end - end - end - end - end - - TemplateError = Template::Error -end diff --git a/actionpack/lib/action_view/template/handlers.rb b/actionpack/lib/action_view/template/handlers.rb deleted file mode 100644 index d9cddc0040..0000000000 --- a/actionpack/lib/action_view/template/handlers.rb +++ /dev/null @@ -1,53 +0,0 @@ -module ActionView #:nodoc: - # = Action View Template Handlers - class Template - module Handlers #:nodoc: - autoload :ERB, 'action_view/template/handlers/erb' - autoload :Builder, 'action_view/template/handlers/builder' - autoload :Raw, 'action_view/template/handlers/raw' - - def self.extended(base) - base.register_default_template_handler :erb, ERB.new - base.register_template_handler :builder, Builder.new - base.register_template_handler :raw, Raw.new - base.register_template_handler :ruby, :source.to_proc - end - - @@template_handlers = {} - @@default_template_handlers = nil - - def self.extensions - @@template_extensions ||= @@template_handlers.keys - end - - # Register an object that knows how to handle template files with the given - # extensions. This can be used to implement new template types. - # The handler must respond to `:call`, which will be passed the template - # and should return the rendered template as a String. - def register_template_handler(*extensions, handler) - raise(ArgumentError, "Extension is required") if extensions.empty? - extensions.each do |extension| - @@template_handlers[extension.to_sym] = handler - end - @@template_extensions = nil - end - - def template_handler_extensions - @@template_handlers.keys.map {|key| key.to_s }.sort - end - - def registered_template_handler(extension) - extension && @@template_handlers[extension.to_sym] - end - - def register_default_template_handler(extension, klass) - register_template_handler(extension, klass) - @@default_template_handlers = klass - end - - def handler_for_extension(extension) - registered_template_handler(extension) || @@default_template_handlers - end - end - end -end diff --git a/actionpack/lib/action_view/template/handlers/builder.rb b/actionpack/lib/action_view/template/handlers/builder.rb deleted file mode 100644 index d90b0c6378..0000000000 --- a/actionpack/lib/action_view/template/handlers/builder.rb +++ /dev/null @@ -1,26 +0,0 @@ -module ActionView - module Template::Handlers - class Builder - # Default format used by Builder. - class_attribute :default_format - self.default_format = :xml - - def call(template) - require_engine - "xml = ::Builder::XmlMarkup.new(:indent => 2);" + - "self.output_buffer = xml.target!;" + - template.source + - ";xml.target!;" - end - - protected - - def require_engine - @required ||= begin - require "builder" - true - end - end - end - end -end diff --git a/actionpack/lib/action_view/template/handlers/erb.rb b/actionpack/lib/action_view/template/handlers/erb.rb deleted file mode 100644 index 5aaafc15c1..0000000000 --- a/actionpack/lib/action_view/template/handlers/erb.rb +++ /dev/null @@ -1,120 +0,0 @@ -require 'action_dispatch/http/mime_type' -require 'erubis' - -module ActionView - class Template - module Handlers - class Erubis < ::Erubis::Eruby - def add_preamble(src) - src << "@output_buffer = output_buffer || ActionView::OutputBuffer.new;" - end - - def add_text(src, text) - return if text.empty? - src << "@output_buffer.safe_concat('" << escape_text(text) << "');" - end - - # Erubis toggles <%= and <%== behavior when escaping is enabled. - # We override to always treat <%== as escaped. - def add_expr(src, code, indicator) - case indicator - when '==' - add_expr_escaped(src, code) - else - super - end - end - - BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/ - - def add_expr_literal(src, code) - if code =~ BLOCK_EXPR - src << '@output_buffer.append= ' << code - else - src << '@output_buffer.append= (' << code << ');' - end - end - - def add_expr_escaped(src, code) - if code =~ BLOCK_EXPR - src << "@output_buffer.safe_append= " << code - else - src << "@output_buffer.safe_concat((" << code << ").to_s);" - end - end - - def add_postamble(src) - src << '@output_buffer.to_s' - end - end - - class ERB - # Specify trim mode for the ERB compiler. Defaults to '-'. - # See ERB documentation for suitable values. - class_attribute :erb_trim_mode - self.erb_trim_mode = '-' - - # Default implementation used. - class_attribute :erb_implementation - self.erb_implementation = Erubis - - # Do not escape templates of these mime types. - class_attribute :escape_whitelist - self.escape_whitelist = ["text/plain"] - - ENCODING_TAG = Regexp.new("\\A(<%#{ENCODING_FLAG}-?%>)[ \\t]*") - - def self.call(template) - new.call(template) - end - - def supports_streaming? - true - end - - def handles_encoding? - true - end - - def call(template) - # First, convert to BINARY, so in case the encoding is - # wrong, we can still find an encoding tag - # (<%# encoding %>) inside the String using a regular - # expression - template_source = template.source.dup.force_encoding(Encoding::ASCII_8BIT) - - erb = template_source.gsub(ENCODING_TAG, '') - encoding = $2 - - erb.force_encoding valid_encoding(template.source.dup, encoding) - - # Always make sure we return a String in the default_internal - erb.encode! - - self.class.erb_implementation.new( - erb, - :escape => (self.class.escape_whitelist.include? template.type), - :trim => (self.class.erb_trim_mode == "-") - ).src - 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 - # where the original String was assumed to be, - # for instance, UTF-8, but a magic comment - # proved otherwise - string.force_encoding(encoding) if encoding - - # If the String is valid, return the encoding we found - return string.encoding if string.valid_encoding? - - # Otherwise, raise an exception - raise WrongEncodingError.new(string, string.encoding) - end - end - end - end -end diff --git a/actionpack/lib/action_view/template/handlers/raw.rb b/actionpack/lib/action_view/template/handlers/raw.rb deleted file mode 100644 index 0c0d1fffcb..0000000000 --- a/actionpack/lib/action_view/template/handlers/raw.rb +++ /dev/null @@ -1,11 +0,0 @@ -module ActionView - module Template::Handlers - class Raw - def call(template) - escaped = template.source.gsub(':', '\:') - - '%q:' + escaped + ':;' - end - end - end -end diff --git a/actionpack/lib/action_view/template/resolver.rb b/actionpack/lib/action_view/template/resolver.rb deleted file mode 100644 index 47bd011d5e..0000000000 --- a/actionpack/lib/action_view/template/resolver.rb +++ /dev/null @@ -1,326 +0,0 @@ -require "pathname" -require "active_support/core_ext/class" -require "active_support/core_ext/class/attribute_accessors" -require "action_view/template" -require "thread" -require "thread_safe" - -module ActionView - # = Action View Resolver - class Resolver - # Keeps all information about view path and builds virtual path. - class Path - attr_reader :name, :prefix, :partial, :virtual - alias_method :partial?, :partial - - def self.build(name, prefix, partial) - virtual = "" - virtual << "#{prefix}/" unless prefix.empty? - virtual << (partial ? "_#{name}" : name) - new name, prefix, partial, virtual - end - - def initialize(name, prefix, partial, virtual) - @name = name - @prefix = prefix - @partial = partial - @virtual = virtual - end - - def to_str - @virtual - end - alias :to_s :to_str - end - - # Threadsafe template cache - class Cache #:nodoc: - class SmallCache < ThreadSafe::Cache - def initialize(options = {}) - super(options.merge(:initial_capacity => 2)) - end - end - - # preallocate all the default blocks for performance/memory consumption reasons - PARTIAL_BLOCK = lambda {|cache, partial| cache[partial] = SmallCache.new} - PREFIX_BLOCK = lambda {|cache, prefix| cache[prefix] = SmallCache.new(&PARTIAL_BLOCK)} - NAME_BLOCK = lambda {|cache, name| cache[name] = SmallCache.new(&PREFIX_BLOCK)} - KEY_BLOCK = lambda {|cache, key| cache[key] = SmallCache.new(&NAME_BLOCK)} - - # usually a majority of template look ups return nothing, use this canonical preallocated array to safe memory - NO_TEMPLATES = [].freeze - - def initialize - @data = SmallCache.new(&KEY_BLOCK) - end - - # Cache the templates returned by the block - def cache(key, name, prefix, partial, locals) - if Resolver.caching? - @data[key][name][prefix][partial][locals] ||= canonical_no_templates(yield) - else - fresh_templates = yield - cached_templates = @data[key][name][prefix][partial][locals] - - if templates_have_changed?(cached_templates, fresh_templates) - @data[key][name][prefix][partial][locals] = canonical_no_templates(fresh_templates) - else - cached_templates || NO_TEMPLATES - end - end - end - - def clear - @data.clear - end - - private - - def canonical_no_templates(templates) - templates.empty? ? NO_TEMPLATES : templates - end - - def templates_have_changed?(cached_templates, fresh_templates) - # if either the old or new template list is empty, we don't need to (and can't) - # compare modification times, and instead just check whether the lists are different - if cached_templates.blank? || fresh_templates.blank? - return fresh_templates.blank? != cached_templates.blank? - end - - cached_templates_max_updated_at = cached_templates.map(&:updated_at).max - - # if a template has changed, it will be now be newer than all the cached templates - fresh_templates.any? { |t| t.updated_at > cached_templates_max_updated_at } - end - end - - cattr_accessor :caching - self.caching = true - - class << self - alias :caching? :caching - end - - def initialize - @cache = Cache.new - end - - def clear_cache - @cache.clear - end - - # Normalizes the arguments and passes it on to find_templates. - def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[]) - cached(key, [name, prefix, partial], details, locals) do - find_templates(name, prefix, partial, details) - end - end - - private - - delegate :caching?, to: :class - - # This is what child classes implement. No defaults are needed - # because Resolver guarantees that the arguments are present and - # normalized. - def find_templates(name, prefix, partial, details) - raise NotImplementedError, "Subclasses must implement a find_templates(name, prefix, partial, details) method" - end - - # Helpers that builds a path. Useful for building virtual paths. - def build_path(name, prefix, partial) - Path.build(name, prefix, partial) - end - - # Handles 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 if the key is present, check if the - # resolver is fresher before returning it. - def cached(key, path_info, details, locals) #:nodoc: - name, prefix, partial = path_info - locals = locals.map { |x| x.to_s }.sort! - - if key - @cache.cache(key, name, prefix, partial, locals) do - decorate(yield, path_info, details, locals) - end - else - decorate(yield, path_info, details, locals) - 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 - end - - # An abstract class that implements a Resolver with path semantics. - class PathResolver < Resolver #:nodoc: - EXTENSIONS = [:locale, :formats, :handlers] - DEFAULT_PATTERN = ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}" - - def initialize(pattern=nil) - @pattern = pattern || DEFAULT_PATTERN - super() - end - - private - - def find_templates(name, prefix, partial, details) - path = Path.build(name, prefix, partial) - query(path, details, details[:formats]) - end - - def query(path, details, formats) - query = build_query(path, details) - - # deals with case-insensitive file systems. - sanitizer = Hash.new { |h,dir| h[dir] = Dir["#{dir}/*"] } - - template_paths = Dir[query].reject { |filename| - File.directory?(filename) || - !sanitizer[File.dirname(filename)].include?(filename) - } - - template_paths.map { |template| - handler, format = extract_handler_and_format(template, formats) - contents = File.binread template - - Template.new(contents, File.expand_path(template), handler, - :virtual_path => path.virtual, - :format => format, - :updated_at => mtime(template)) - } - end - - # Helper for building query glob string based on resolver's pattern. - def build_query(path, details) - query = @pattern.dup - - prefix = path.prefix.empty? ? "" : "#{escape_entry(path.prefix)}\\1" - query.gsub!(/\:prefix(\/)?/, prefix) - - partial = escape_entry(path.partial? ? "_#{path.name}" : path.name) - query.gsub!(/\:action/, partial) - - details.each do |ext, variants| - query.gsub!(/\:#{ext}/, "{#{variants.compact.uniq.join(',')}}") - end - - File.expand_path(query, @path) - end - - def escape_entry(entry) - entry.gsub(/[*?{}\[\]]/, '\\\\\\&') - end - - # Returns the file mtime from the filesystem. - def mtime(p) - File.mtime(p) - 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 - - extension = pieces.pop - unless extension - message = "The file #{path} did not specify a template handler. The default is currently ERB, " \ - "but will change to RAW in the future." - ActiveSupport::Deprecation.warn message - end - - handler = Template.handler_for_extension(extension) - format = pieces.last && Template::Types[pieces.last] - [handler, format] - end - end - - # A resolver that loads files from the filesystem. It allows setting your own - # resolving pattern. Such pattern can be a glob string supported by some variables. - # - # ==== Examples - # - # Default pattern, loads views the same way as previous versions of rails, eg. when you're - # looking for `users/new` it will produce query glob: `users/new{.{en},}{.{html,js},}{.{erb,haml},}` - # - # FileSystemResolver.new("/path/to/views", ":prefix/:action{.:locale,}{.:formats,}{.:handlers,}") - # - # This one allows you to keep files with different formats in seperated subdirectories, - # eg. `users/new.html` will be loaded from `users/html/new.erb` or `users/new.html.erb`, - # `users/new.js` from `users/js/new.erb` or `users/new.js.erb`, etc. - # - # FileSystemResolver.new("/path/to/views", ":prefix/{:formats/,}:action{.:locale,}{.:formats,}{.:handlers,}") - # - # If you don't specify a pattern then the default will be used. - # - # In order to use any of the customized resolvers above in a Rails application, you just need - # to configure ActionController::Base.view_paths in an initializer, for example: - # - # ActionController::Base.view_paths = FileSystemResolver.new( - # Rails.root.join("app/views"), - # ":prefix{/:locale}/:action{.:formats,}{.:handlers,}" - # ) - # - # ==== Pattern format and variables - # - # Pattern has to be a valid glob string, and it allows you to use the - # following variables: - # - # * <tt>:prefix</tt> - usually the controller path - # * <tt>:action</tt> - name of the action - # * <tt>:locale</tt> - possible locale versions - # * <tt>:formats</tt> - possible request formats (for example html, json, xml...) - # * <tt>:handlers</tt> - possible handlers (for example erb, haml, builder...) - # - class FileSystemResolver < PathResolver - def initialize(path, pattern=nil) - raise ArgumentError, "path already is a Resolver class" if path.is_a?(Resolver) - super(pattern) - @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 - - # An Optimized resolver for Rails' most common case. - class OptimizedFileSystemResolver < FileSystemResolver #:nodoc: - def build_query(path, details) - exts = EXTENSIONS.map { |ext| details[ext] } - query = escape_entry(File.join(@path, path)) - - query + exts.map { |ext| - "{#{ext.compact.uniq.map { |e| ".#{e}," }.join}}" - }.join - end - 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 #:nodoc: - 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 deleted file mode 100644 index 859c7bc3ce..0000000000 --- a/actionpack/lib/action_view/template/text.rb +++ /dev/null @@ -1,34 +0,0 @@ -module ActionView #:nodoc: - # = Action View Text Template - class Template - class Text #:nodoc: - attr_accessor :type - - def initialize(string, type = nil) - @string = string.to_s - @type = Types[type] || type if type - @type ||= Types[:text] - end - - def identifier - 'text template' - end - - def inspect - 'text template' - end - - def to_str - @string - end - - def render(*args) - to_str - end - - def formats - [@type.to_sym] - end - end - end -end diff --git a/actionpack/lib/action_view/template/types.rb b/actionpack/lib/action_view/template/types.rb deleted file mode 100644 index db77cb5d19..0000000000 --- a/actionpack/lib/action_view/template/types.rb +++ /dev/null @@ -1,57 +0,0 @@ -require 'set' -require 'active_support/core_ext/class/attribute_accessors' - -module ActionView - class Template - class Types - class Type - cattr_accessor :types - self.types = Set.new - - def self.register(*t) - types.merge(t.map { |type| type.to_s }) - end - - register :html, :text, :js, :css, :xml, :json - - def self.[](type) - return type if type.is_a?(self) - - if type.is_a?(Symbol) || types.member?(type.to_s) - new(type) - end - end - - attr_reader :symbol - - def initialize(symbol) - @symbol = symbol.to_sym - end - - delegate :to_s, :to_sym, :to => :symbol - alias to_str to_s - - def ref - to_sym || to_s - end - - def ==(type) - return false if type.blank? - symbol.to_sym == type.to_sym - end - end - - cattr_accessor :type_klass - - def self.delegate_to(klass) - self.type_klass = klass - end - - delegate_to Type - - def self.[](type) - type_klass[type] - end - end - end -end |