class ActionView::Template

Action View Template

def build_method_name(locals)

def build_method_name(locals)
  @method_names[locals.keys.hash] ||= "_#{identifier_method_name}__#{@identifier.hash}_#{__id__}_#{locals.keys.hash}".gsub('-', "_")
end

def compile(locals, view, mod)

regardless of the original source encoding.
this means that templates will be UTF-8 inside of Rails,
encode the source into Encoding.default_internal. In general,
Otherwise, after we figure out the correct encoding, we then

specifying the encoding. For instance, ERB supports <%# encoding: %>
the template engine to support additional mechanisms for
String to the engine without further processing. This allows
If the template engine handles encodings, we send the encoded

blank line in its stead.
before passing the source on to the template engine, leaving a
with any template engine, as we process out the encoding comment
line of the template (# encoding: NAME-OF-ENCODING). This will work
The user can also specify the encoding via a comment on the first

we assume the encoding is the same as Encoding.default_external.
source is BINARY data. If no additional information is supplied,
the encoding of the source. Until this point, we assume that the
Among other things, this method is responsible for properly setting
def compile(locals, view, mod)
  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
  if source.encoding_aware?
    # Avoid performing in-place mutation for SafeBuffer
    @source = source.to_str if source.html_safe?
    # Look for # encoding: *. If we find one, we'll encode the
    # String in that encoding, otherwise, we'll use the
    # default external encoding.
    if source.sub!(/\A#{ENCODING_FLAG}/, '')
      encoding = magic_encoding = $1
    else
      encoding = Encoding.default_external
    end
    # Tag the source with the default external encoding
    # or the encoding specified in the file
    source.force_encoding(encoding)
    # If the user didn't specify an encoding, and the handler
    # handles encodings, we simply pass the String as is to
    # the handler (with the default_external tag)
    if !magic_encoding && @handler.respond_to?(:handles_encoding?) && @handler.handles_encoding?
      source
    # Otherwise, if the String is valid in the encoding,
    # encode immediately to default_internal. This means
    # that if a handler doesn't handle encodings, it will
    # always get Strings in the default_internal
    elsif source.valid_encoding?
      source.encode!
    # Otherwise, since the String is invalid in the encoding
    # specified, raise an exception
    else
      raise WrongEncodingError.new(source, encoding)
    end
  end
  code = @handler.call(self)
  # Make sure that the resulting String to be evalled is in the
  # encoding of the code
  source = <<-end_src
    def #{method_name}(local_assigns)
      _old_virtual_path, @_virtual_path = @_virtual_path, #{@virtual_path.inspect};_old_output_buffer = @output_buffer;#{locals_code};#{code}
    ensure
      @_virtual_path, @output_buffer = _old_virtual_path, _old_output_buffer
    end
  end_src
  if source.encoding_aware?
    # Make sure the source is in the encoding of the returned code
    source.force_encoding(code.encoding)
    # In case we get back a String from a handler that is not in
    # BINARY or the default_internal, encode it to the default_internal
    source.encode!
    # Now, validate that the source we got back from the template
    # handler is valid in the default_internal. This is for handlers
    # that handle encoding but screw up
    unless source.valid_encoding?
      raise WrongEncodingError.new(@source, Encoding.default_internal)
    end
  end
  begin
    mod.module_eval(source, identifier, 0)
    ObjectSpace.define_finalizer(self, Finalizer[method_name, mod])
    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::Template::Error.new(self, {}, e)
  end
end

def counter_name

def counter_name
  @counter_name ||= "#{variable_name}_counter".to_sym
end

def identifier_method_name

def identifier_method_name
  @identifier_method_name ||= inspect.gsub(/[^a-z_]/, '_')
end

def initialize(source, identifier, handler, details)

def initialize(source, identifier, handler, details)
  @source             = source
  @identifier         = identifier
  @handler            = handler
  @original_encoding  = nil
  @method_names       = {}
  format   = details[:format] || :html
  @formats = Array.wrap(format).map { |f| f.is_a?(Mime::Type) ? f.ref : f }
  @virtual_path = details[:virtual_path].try(:sub, ".#{format}", "")
end

def inspect

def inspect
  @inspect ||=
    if defined?(Rails.root)
      identifier.sub("#{Rails.root}/", '')
    else
      identifier
    end
end

def mime_type

def mime_type
  @mime_type ||= Mime::Type.lookup_by_extension(@formats.first.to_s) if @formats.first
end

def render(view, locals, &block)

def render(view, locals, &block)
  # Notice that we use a bang in this instrumentation because you don't want to
  # consume this in production. This is only slow if it's being listened to.
  ActiveSupport::Notifications.instrument("!render_template.action_view", :virtual_path => @virtual_path) do
    if view.is_a?(ActionView::CompiledTemplates)
      mod = ActionView::CompiledTemplates
    else
      mod = view.singleton_class
    end
    method_name = compile(locals, view, mod)
    view.send(method_name, locals, &block)
  end
rescue Exception => e
  if e.is_a?(Template::Error)
    e.sub_template_of(self)
    raise e
  else
    raise Template::Error.new(self, view.respond_to?(:assigns) ? view.assigns : {}, e)
  end
end

def variable_name

def variable_name
  @variable_name ||= @virtual_path[%r'_?(\w+)(\.\w+)*$', 1].to_sym
end