module Roda::RodaPlugins::Render::InstanceMethods

def _cached_template_method(template)

with a single string or symbol argument.
method symbol. This optimization is only used for render/view calls
If there is an instance method for the template, return the instance
def _cached_template_method(template)
  case template
  when String, Symbol
    if (method_cache = render_opts[:template_method_cache])
      _cached_template_method_lookup(method_cache, template)
    end
  end
end

def _cached_template_method(_)

def _cached_template_method(_)
  nil
end

def _cached_template_method_key(template)

The key to use in the template method cache for the given template.
def _cached_template_method_key(template)
  template
end

def _cached_template_method_key(_)

def _cached_template_method_key(_)
  nil
end

def _cached_template_method_lookup(method_cache, template)

Return the instance method symbol for the template in the method cache.
def _cached_template_method_lookup(method_cache, template)
  method_cache[template]
end

def _layout_method

Return a symbol containing the optimized layout method
def _layout_method
  self.class.opts[:render][:template_method_cache][:_roda_layout]
end

def _layout_method

def _layout_method
  nil
end

def _optimized_render_method_for_locals(template, locals)

path is not used and the long method needs to be used.
of the template render if the optimized path is used, or nil if the optimized
Use an optimized render path for templates with a hash of locals. Returns the result
def _optimized_render_method_for_locals(template, locals)
  return unless method_cache = render_opts[:template_method_cache]
  locals_keys = locals.keys.sort
  key = [:_render_locals, template, locals_keys]
  optimized_template = case template
  when String, Symbol
    _cached_template_method_lookup(method_cache, key)
  else
    return
  end
  case optimized_template
  when Symbol
    optimized_template
  else
    if method_cache_key = _cached_template_method_key(key)
      template_obj = retrieve_template(render_template_opts(template, NO_CACHE))
      method_name = :"_roda_template_locals_#{self.class.object_id}_#{method_cache_key}"
      method_cache[method_cache_key] = case template_obj
      when Render::TemplateMtimeWrapper
        template_obj.define_compiled_method(self.class, method_name, locals_keys)
      else
        begin
          unbound_method = Render.tilt_template_compiled_method(template_obj, locals_keys, self.class)
        rescue ::NotImplementedError
          false
        else
          self.class::RodaCompiledTemplates.send(:define_method, method_name, unbound_method)
          self.class::RodaCompiledTemplates.send(:private, method_name)
          method_name
        end
      end
    end
  end
end

def _optimized_render_method_for_locals(_, _)

def _optimized_render_method_for_locals(_, _)
  nil
end

def _optimized_view_content(template)

a single argument is passed to view.
Get the content for #view, or return nil to use the unoptimized approach. Only called if
def _optimized_view_content(template)
  if optimized_template = _cached_template_method(template)
    send(optimized_template, OPTS)
  elsif template.is_a?(Hash) && template.length == 1
    template[:content]
  end
end

def _optimized_view_content(template)

def _optimized_view_content(template)
  nil
end

def cached_template(opts, &block)

to get the template.
If caching templates, attempt to retrieve the template from the cache. Otherwise, just yield
def cached_template(opts, &block)
  if key = opts[:cache_key]
    cache = render_opts[:cache]
    unless template = cache[key]
      template = cache[key] = yield
    end
    template
  else
    yield
  end
end

def find_template(opts)

template block, and locals to use for the render in the passed options.
Given the template name and options, set the template class, template path/content,
def find_template(opts)
  render_opts = self.class.opts[:render]
  engine_override = opts[:engine]
  engine = opts[:engine] ||= render_opts[:engine]
  if content = opts[:inline]
    path = opts[:path] = content
    template_class = opts[:template_class] ||= ::Tilt[engine]
    opts[:template_block] = self.class.inline_template_block(content)
  else
    opts[:views] ||= render_opts[:views]
    path = opts[:path] ||= template_path(opts)
    template_class = opts[:template_class]
    opts[:template_class] ||= ::Tilt
  end
  if (cache = opts[:cache]).nil?
    cache = content || !opts[:template_block]
  end
  if cache
    unless opts.has_key?(:cache_key)
      template_block = opts[:template_block] unless content
      template_opts = opts[:template_opts]
      opts[:cache_key] = if template_class || engine_override || template_opts || template_block
        [path, template_class, engine_override, template_opts, template_block]
      else
        path
      end
    end
  else
    opts.delete(:cache_key)
  end
  opts
end

def parse_template_opts(template, opts)

Return a single hash combining the template and opts arguments.
def parse_template_opts(template, opts)
  opts = Hash[opts]
  if template.is_a?(Hash)
    opts.merge!(template)
  else
    if opts.empty? && (key = _cached_template_method_key(template))
      opts[:template_method_cache_key] = key
    end
    opts[:template] = template
    opts
  end
end

def render(template, opts = (no_opts = true; optimized_template = _cached_template_method(template); OPTS), &block)

Render the given template. See Render for details.
def render(template, opts = (no_opts = true; optimized_template = _cached_template_method(template); OPTS), &block)
  if optimized_template
    send(optimized_template, OPTS, &block)
  elsif !no_opts && opts.length == 1 && (locals = opts[:locals]) && (optimized_template = _optimized_render_method_for_locals(template, locals))
    send(optimized_template, locals, &block)
  else
    opts = render_template_opts(template, opts)
    retrieve_template(opts).render((opts[:scope]||self), (opts[:locals]||OPTS), &block)
  end
end

def render_layout_opts

providing a :layout_opts option to the view/render method.
The default render options to use. These set defaults that can be overridden by
def render_layout_opts
  Hash[render_opts[:layout_opts]]
end

def render_opts

Return the render options for the instance's class.
def render_opts
  self.class.render_opts
end

def render_template_opts(template, opts)

Convert template options to single hash when rendering templates using render.
def render_template_opts(template, opts)
  parse_template_opts(template, opts)
end

def retrieve_template(opts)

Retrieve the Tilt::Template object for the given template and opts.
def retrieve_template(opts)
  cache = opts[:cache]
  if !opts[:cache_key] || cache == false
    found_template_opts = opts = find_template(opts)
  end
  cached_template(opts) do
    opts = found_template_opts || find_template(opts)
    render_opts = self.class.opts[:render]
    template_opts = render_opts[:template_opts]
    if engine_opts = render_opts[:engine_opts][opts[:engine]]
      template_opts = template_opts.merge(engine_opts)
    end
    if current_template_opts = opts[:template_opts]
      template_opts = template_opts.merge(current_template_opts)
    end
    define_compiled_method = COMPILED_METHOD_SUPPORT &&
       (method_cache_key = opts[:template_method_cache_key]) &&
       (method_cache = render_opts[:template_method_cache]) &&
       (method_cache[method_cache_key] != false) &&
       !opts[:inline]
    if render_opts[:check_template_mtime] && !opts[:template_block] && !cache
      template = TemplateMtimeWrapper.new(self.class, opts, template_opts)
      if define_compiled_method
        method_name = :"_roda_template_#{self.class.object_id}_#{method_cache_key}"
        method_cache[method_cache_key] = template.define_compiled_method(self.class, method_name)
      end
    else
      template = self.class.create_template(opts, template_opts)
      if define_compiled_method && cache != false
        begin
          unbound_method = Render.tilt_template_compiled_method(template, EMPTY_ARRAY, self.class)
        rescue ::NotImplementedError
          method_cache[method_cache_key] = false
        else
          method_name = :"_roda_template_#{self.class.object_id}_#{method_cache_key}"
          self.class::RodaCompiledTemplates.send(:define_method, method_name, unbound_method)
          self.class::RodaCompiledTemplates.send(:private, method_name)
          method_cache[method_cache_key] = method_name
        end
      end
    end
    template
  end
end

def template_name(opts)

The name to use for the template. By default, just converts the :template option to a string.
def template_name(opts)
  opts[:template].to_s
end

def template_path(opts)

The template path for the given options.
def template_path(opts)
  path = "#{opts[:views]}/#{template_name(opts)}.#{opts[:engine]}"
  if opts.fetch(:check_paths){render_opts[:check_paths]}
    full_path = self.class.expand_path(path)
    unless render_opts[:allowed_paths].any?{|f| full_path.start_with?(f)}
      raise RodaError, "attempt to render path not in allowed_paths: #{full_path} (allowed: #{render_opts[:allowed_paths].join(', ')})"
    end
  end
  path
end

def view(template, opts = (content = _optimized_view_content(template) unless defined?(yield); OPTS), &block)

See Render for details.
are passed to render when rendering the template.
and render it inside the layout. Blocks passed to view
for the class, take the result of the template rendering
Render the given template. If there is a default layout
def view(template, opts = (content = _optimized_view_content(template) unless defined?(yield); OPTS), &block)
  if content
    # First, check if the optimized layout method has already been created,
    # and use it if so.  This way avoids the extra conditional and local variable
    # assignments in the next section.
    if layout_method = _layout_method
      return send(layout_method, OPTS){content}
    end
    # If we have an optimized template method but no optimized layout method, create the
    # optimized layout method if possible and use it.  If you can't create the optimized
    # layout method, fall through to the slower approach.
    if layout_template = self.class.opts[:render][:optimize_layout]
      retrieve_template(:template=>layout_template, :cache_key=>nil, :template_method_cache_key => :_roda_layout)
      if layout_method = _layout_method
        return send(layout_method, OPTS){content}
      end
    end
  else
    opts = parse_template_opts(template, opts)
    content = opts[:content] || render_template(opts, &block)
  end
  if layout_opts  = view_layout_opts(opts)
    content = render_template(layout_opts){content}
  end
  content
end

def view_layout_opts(opts)

used, return nil.
rendering the layout template. If a layout should not be
If a layout should be used, return a hash of options for
def view_layout_opts(opts)
  if layout = opts.fetch(:layout, render_opts[:layout])
    layout_opts = render_layout_opts
    method_layout_opts = opts[:layout_opts]
    layout_opts.merge!(method_layout_opts) if method_layout_opts
    case layout
    when Hash
      layout_opts.merge!(layout)
    when true
      # use default layout
    else
      layout_opts[:template] = layout
    end
    layout_opts
  end
end