# encoding: utf-8
# This is so that templates compiled in this file are UTF-8
require 'set'
require "action_view/template/path"
module ActionView
class Template
extend TemplateHandlers
attr_reader :source, :identifier, :handler
def initialize(source, identifier, handler, details)
@source = source
@identifier = identifier
@handler = handler
@details = details
end
def render(view, locals, &blk)
method_name = compile(locals, view)
view.send(method_name, locals, &blk)
end
# TODO: Figure out how to abstract this
def variable_name
identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym
end
# TODO: Figure out how to abstract this
def counter_name
"#{variable_name}_counter".to_sym
end
# TODO: kill hax
def partial?
@details[:partial]
end
# TODO: Move out of Template
def mime_type
Mime::Type.lookup_by_extension(@details[:format]) if @details[:format]
end
private
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
raise ActionView::TemplateError.new(self, {}, e)
end
end
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
if false
module ActionView #:nodoc:
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)
@name = template_path.to_s.split("/").last.split(".").first
# @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
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
end
def relative_path
path = File.expand_path(filename)
path.sub!(/^#{Regexp.escape(File.expand_path(RAILS_ROOT))}\//, '') if defined?(RAILS_ROOT)
path
end
memoize :relative_path
def source
File.read(filename)
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('/')
end
memoize :path_without_format_and_extension
def path
[base_path, [name, locale, format, extension].compact.join('.')].compact.join('/')
end
memoize :path
def mime_type
Mime::Type.lookup_by_extension(format) if format && defined?(::Mime)
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 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)
end
raise MissingTemplate.new(load_paths, path)
end
end
end
end