2009-04-23 22:58:38 +00:00
|
|
|
# encoding: utf-8
|
|
|
|
# This is so that templates compiled in this file are UTF-8
|
|
|
|
|
2009-04-22 23:41:06 +00:00
|
|
|
require 'set'
|
2009-06-17 22:39:41 +00:00
|
|
|
require "action_view/template/resolver"
|
2009-04-15 00:22:51 +00:00
|
|
|
|
2009-04-23 22:58:38 +00:00
|
|
|
module ActionView
|
2008-07-12 19:33:46 +00:00
|
|
|
class Template
|
2008-07-04 02:08:27 +00:00
|
|
|
extend TemplateHandlers
|
2009-08-09 04:37:03 +00:00
|
|
|
attr_reader :source, :identifier, :handler, :mime_type, :formats, :details
|
2009-09-24 17:30:13 +00:00
|
|
|
|
2009-04-23 22:58:38 +00:00
|
|
|
def initialize(source, identifier, handler, details)
|
|
|
|
@source = source
|
|
|
|
@identifier = identifier
|
|
|
|
@handler = handler
|
|
|
|
@details = details
|
2009-08-09 04:37:03 +00:00
|
|
|
@method_names = {}
|
2009-05-21 21:22:07 +00:00
|
|
|
|
2009-05-22 23:50:26 +00:00
|
|
|
format = details.delete(:format) || begin
|
2009-05-21 21:22:07 +00:00
|
|
|
# TODO: Clean this up
|
|
|
|
handler.respond_to?(:default_format) ? handler.default_format.to_sym.to_s : "html"
|
|
|
|
end
|
|
|
|
@mime_type = Mime::Type.lookup_by_extension(format.to_s)
|
2009-08-09 04:37:03 +00:00
|
|
|
@formats = [format.to_sym]
|
|
|
|
@formats << :html if format == :js
|
2009-06-17 19:00:23 +00:00
|
|
|
@details[:formats] = Array.wrap(format.to_sym)
|
2009-04-15 00:22:51 +00:00
|
|
|
end
|
2009-09-24 17:30:13 +00:00
|
|
|
|
2009-08-11 22:02:05 +00:00
|
|
|
def render(view, locals, &block)
|
2009-10-15 21:51:51 +00:00
|
|
|
ActiveSupport::Notifications.instrument(:render_template, :identifier => identifier) do
|
2009-09-18 11:08:02 +00:00
|
|
|
method_name = compile(locals, view)
|
|
|
|
view.send(method_name, locals, &block)
|
2009-10-07 14:17:50 +00:00
|
|
|
end
|
2009-08-11 22:02:05 +00:00
|
|
|
rescue Exception => e
|
|
|
|
if e.is_a?(TemplateError)
|
|
|
|
e.sub_template_of(self)
|
|
|
|
raise e
|
|
|
|
else
|
|
|
|
raise TemplateError.new(self, view.assigns, e)
|
|
|
|
end
|
2009-04-23 22:58:38 +00:00
|
|
|
end
|
2009-09-24 17:30:13 +00:00
|
|
|
|
2009-04-23 22:58:38 +00:00
|
|
|
# TODO: Figure out how to abstract this
|
|
|
|
def variable_name
|
2009-08-09 02:43:45 +00:00
|
|
|
@variable_name ||= identifier[%r'_?(\w+)(\.\w+)*$', 1].to_sym
|
2008-12-21 23:23:53 +00:00
|
|
|
end
|
|
|
|
|
2009-04-23 22:58:38 +00:00
|
|
|
# TODO: Figure out how to abstract this
|
|
|
|
def counter_name
|
2009-08-09 02:43:45 +00:00
|
|
|
@counter_name ||= "#{variable_name}_counter".to_sym
|
2009-04-23 22:58:38 +00:00
|
|
|
end
|
2009-09-24 17:30:13 +00:00
|
|
|
|
2009-04-23 22:58:38 +00:00
|
|
|
# TODO: kill hax
|
|
|
|
def partial?
|
|
|
|
@details[:partial]
|
|
|
|
end
|
2009-05-21 21:22:07 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
def inspect
|
|
|
|
if defined?(Rails.root)
|
|
|
|
identifier.sub("#{Rails.root}/", '')
|
|
|
|
else
|
|
|
|
identifier
|
|
|
|
end
|
|
|
|
end
|
2008-02-06 04:26:40 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
private
|
|
|
|
def compile(locals, view)
|
|
|
|
method_name = build_method_name(locals)
|
2009-04-23 22:58:38 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
return method_name if view.respond_to?(method_name)
|
2009-05-28 22:12:28 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
locals_code = locals.keys.map! { |key| "#{key} = local_assigns[:#{key}];" }.join
|
2009-04-23 22:58:38 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
code = @handler.call(self)
|
|
|
|
if code.sub!(/\A(#.*coding.*)\n/, '')
|
|
|
|
encoding_comment = $1
|
|
|
|
elsif defined?(Encoding) && Encoding.respond_to?(:default_external)
|
|
|
|
encoding_comment = "#coding:#{Encoding.default_external}"
|
|
|
|
end
|
2009-05-28 22:12:28 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
source = <<-end_src
|
|
|
|
def #{method_name}(local_assigns)
|
|
|
|
old_output_buffer = output_buffer;#{locals_code};#{code}
|
|
|
|
ensure
|
|
|
|
self.output_buffer = old_output_buffer
|
|
|
|
end
|
|
|
|
end_src
|
|
|
|
|
|
|
|
if encoding_comment
|
|
|
|
source = "#{encoding_comment}\n#{source}"
|
|
|
|
line = -1
|
|
|
|
else
|
|
|
|
line = 0
|
2009-04-23 22:58:38 +00:00
|
|
|
end
|
2008-07-12 19:33:46 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
begin
|
|
|
|
ActionView::CompiledTemplates.module_eval(source, identifier, line)
|
|
|
|
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
|
2009-04-23 22:58:38 +00:00
|
|
|
end
|
2009-08-14 19:00:52 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
class LocalsKey
|
|
|
|
@hash_keys = Hash.new {|h,k| h[k] = Hash.new {|h,k| h[k] = {} } }
|
2009-08-14 19:00:52 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
def self.get(*locals)
|
|
|
|
@hash_keys[*locals] ||= new(klass, format, locale)
|
|
|
|
end
|
2009-08-14 19:00:52 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
attr_accessor :hash
|
|
|
|
def initialize(klass, format, locale)
|
|
|
|
@hash = locals.hash
|
|
|
|
end
|
2009-08-14 19:00:52 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
alias_method :eql?, :equal?
|
|
|
|
end
|
2009-08-14 19:00:52 +00:00
|
|
|
|
2009-09-24 17:30:13 +00:00
|
|
|
def build_method_name(locals)
|
|
|
|
# TODO: is locals.keys.hash reliably the same?
|
|
|
|
@method_names[locals.keys.hash] ||=
|
|
|
|
"_render_template_#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
|
|
|
|
end
|
2009-04-23 22:58:38 +00:00
|
|
|
end
|
2009-05-28 22:12:28 +00:00
|
|
|
end
|