class Tilt::Template

methods.
the #prepare method and one of the #evaluate or #precompiled_template
Base class for template implementations. Subclasses must implement

def self.evaluate(scope, locals, &block)

Redefine itself to use method compilation the next time:
def self.evaluate(scope, locals, &block)
  method = compiled_method(locals.keys)
  method.bind(scope).call(locals, &block)
end

def basename(suffix='')

The basename of the template file.
def basename(suffix='')
  File.basename(file, suffix) if file
end

def compile_template_method(locals)

def compile_template_method(locals)
  source, offset = precompiled(locals)
  offset += 5
  method_name = "__tilt_#{Thread.current.object_id.abs}"
  Object.class_eval <<-RUBY, eval_file, line - offset
    #{extract_magic_comment source}
    TOPOBJECT.class_eval do
      def #{method_name}(locals)
        Thread.current[:tilt_vars] = [self, locals]
        class << self
          this, locals = Thread.current[:tilt_vars]
          this.instance_eval do
           #{source}
          end
        end
      end
    end
  RUBY
  unbind_compiled_method(method_name)
end

def compile_template_method(locals)

def compile_template_method(locals)
  source, offset = precompiled(locals)
  offset += 1
  method_name = "__tilt_#{Thread.current.object_id}"
  Object.class_eval <<-RUBY, eval_file, line - offset
    TOPOBJECT.class_eval do
      def #{method_name}(locals)
        #{source}
      end
    end
  RUBY
  unbind_compiled_method(method_name)
end

def compiled_method(locals_keys)

The compiled method for the locals keys provided.
def compiled_method(locals_keys)
  @compiled_method[locals_keys] ||=
    compile_template_method(locals_keys)
end

def eval_file

The filename used in backtraces to describe the template.
def eval_file
  file || '(__TEMPLATE__)'
end

def evaluate(scope, locals, &block)

with the locals specified and with support for yielding to the block.
template executation is guaranteed to be performed in the scope object
unbound method which will lead to better performance. In any case,
On the sequential method calls it will compile the template to an
method is called, the template source is evaluated with instance_eval.
Process the template and return the result. The first time this
def evaluate(scope, locals, &block)
  # Redefine itself to use method compilation the next time:
  def self.evaluate(scope, locals, &block)
    method = compiled_method(locals.keys)
    method.bind(scope).call(locals, &block)
  end
  # Use instance_eval the first time:
  evaluate_source(scope, locals, &block)
end

def evaluate_source(scope, locals, &block)

Evaluate the template source in the context of the scope object.
def evaluate_source(scope, locals, &block)
  source, offset = precompiled(locals)
  scope.instance_eval(source, eval_file, line - offset)
end

def evaluate_source(scope, locals, &block)

def evaluate_source(scope, locals, &block)
  source, offset = precompiled(locals)
  file, lineno = eval_file, (line - offset) - 1
  scope.instance_eval { Kernel::eval(source, binding, file, lineno) }
end

def extract_magic_comment(script)

def extract_magic_comment(script)
  comment = script.slice(/\A[ \t]*\#.*coding\s*[=:]\s*([[:alnum:]\-_]+).*$/)
  return comment if comment and not %w[ascii-8bit binary].include?($1.downcase)
  "# coding: #{@default_encoding}" if @default_encoding
end

def initialize(file=nil, line=1, options={}, &block)

All arguments are optional.

a block is required.
it should read template data and return as a String. When file is nil,
default, template data is read from the file. When a block is given,
Create a new template with the file, line, and options specified. By
def initialize(file=nil, line=1, options={}, &block)
  @file, @line, @options = nil, 1, {}
  [options, line, file].compact.each do |arg|
    case
    when arg.respond_to?(:to_str)  ; @file = arg.to_str
    when arg.respond_to?(:to_int)  ; @line = arg.to_int
    when arg.respond_to?(:to_hash) ; @options = arg.to_hash.dup
    else raise TypeError
    end
  end
  raise ArgumentError, "file or block required" if (@file || block).nil?
  # call the initialize_engine method if this is the very first time
  # an instance of this class has been created.
  if !self.class.engine_initialized?
    initialize_engine
    self.class.engine_initialized = true
  end
  # used to hold compiled template methods
  @compiled_method = {}
  # used on 1.9 to set the encoding if it is not set elsewhere (like a magic comment)
  # currently only used if template compiles to ruby
  @default_encoding = @options.delete :default_encoding
  # load template data and prepare (uses binread to avoid encoding issues)
  @reader = block || lambda { |t| File.respond_to?(:binread) ? File.binread(@file) : File.read(@file) }
  @data = @reader.call(self)
  prepare
end

def initialize_engine

underlying template library and perform any initial setup.
the template class is initialized. This should be used to require the
Called once and only once for each template subclass the first time
def initialize_engine
end

def name

The template file's basename with all extensions chomped off.
def name
  basename.split('.', 2).first if basename
end

def precompiled(locals)

easier and more appropriate.
offset. In most cases, overriding the #precompiled_template method is
control over source generation or want to adjust the default line
Template subclasses may override this method when they need complete

offset is the integer line offset where line reporting should begin.
source is the string containing (Ruby) source code for the template and
postamble and returns a two-tuple of the form: [source, offset], where
Generates all template source by combining the preamble, template, and
def precompiled(locals)
  preamble = precompiled_preamble(locals)
  template = precompiled_template(locals)
  magic_comment = extract_magic_comment(template)
  if magic_comment
    # Magic comment e.g. "# coding: utf-8" has to be in the first line.
    # So we copy the magic comment to the first line.
    preamble = magic_comment + "\n" + preamble
  end
  parts = [
    preamble,
    template,
    precompiled_postamble(locals)
  ]
  [parts.join("\n"), preamble.count("\n") + 1]
end

def precompiled_postamble(locals)

template source.
string returned from this method is appended to the precompiled
Generates postamble code for the precompiled template source. The
def precompiled_postamble(locals)
  ''
end

def precompiled_preamble(locals)

reporting in Kernel::caller and backtraces.
source line offset, so adding code to the preamble does not effect line
assignment only. Lines included in the preamble are subtracted from the
locals assignment. The default implementation performs locals
Generates preamble code for initializing template state, and performing
def precompiled_preamble(locals)
  locals.map { |k,v| "#{k} = locals[:#{k}]" }.join("\n")
end

def precompiled_template(locals)

allows it.
scopes, and support for template compilation when the scope object
Template guarantees correct file/line handling, locals support, custom
or the #precompiled method be overridden. When defined, the base
default Template#evaluate implementation requires either this method
A string containing the (Ruby) source code for the template. The
def precompiled_template(locals)
  raise NotImplementedError
end

def prepare

Subclasses must provide an implementation of this method.

variables set in this method are available when #evaluate is called.
engine. Called immediately after template data is loaded. Instance
Do whatever preparation is necessary to setup the underlying template
def prepare
  if respond_to?(:compile!)
    # backward compat with tilt < 0.6; just in case
    warn 'Tilt::Template#compile! is deprecated; implement #prepare instead.'
    compile!
  else
    raise NotImplementedError
  end
end

def render(scope=Object.new, locals={}, &block)

+yield+.
block is given, it is typically available within the template via
Render the template in the given scope with the locals specified. If a
def render(scope=Object.new, locals={}, &block)
  evaluate scope, locals || {}, &block
end

def require_template_library(name)

running under a threaded environment.
Like Kernel::require but issues a warning urging a manual require when
def require_template_library(name)
  if Thread.list.size > 1
    warn "WARN: tilt autoloading '#{name}' in a non thread-safe way; " +
         "explicit require '#{name}' suggested."
  end
  require name
end

def unbind_compiled_method(method_name)

def unbind_compiled_method(method_name)
  method = TOPOBJECT.instance_method(method_name)
  TOPOBJECT.class_eval { remove_method(method_name) }
  method
end