class Middleman::TemplateContext

The TemplateContext Class

A clean context, separate from Application, in which templates can be executed. All helper methods and values available in a template, but be accessible here. Also implements two helpers: wrap_layout & render (used by padrino’s partial method). A new context is created for each render of a path, but that context is shared through the request, passed from template, to layouts and partials.

Attributes

app[R]

Allow templates to directly access the current app instance. @return [Middleman::Application]

current_engine[RW]

Required for Padrino’s rendering

Public Class Methods

new(app, locs={}, opts={}) click to toggle source

Initialize a context with the current app and predefined locals and options hashes.

@param [Middleman::Application] app @param [Hash] locs @param [Hash] opts

# File lib/middleman-core/template_context.rb, line 33
def initialize(app, locs={}, opts={})
  @app = app
  @locs = locs
  @opts = opts
end

Public Instance Methods

current_page()
Alias for: current_resource
current_path() click to toggle source
# File lib/middleman-core/template_context.rb, line 164
def current_path
  @locs[:current_path]
end
current_resource() click to toggle source

Get the resource object for the current path @return [Middleman::Sitemap::Resource]

# File lib/middleman-core/template_context.rb, line 170
def current_resource
  return nil unless current_path
  sitemap.find_resource_by_destination_path(current_path)
end
Also aliased as: current_page
locate_partial(partial_path, try_static=true) click to toggle source
# File lib/middleman-core/template_context.rb, line 129
def locate_partial(partial_path, try_static=true)
  partial_file = nil
  lookup_stack = []
  non_root     = partial_path.to_s.sub(/^\//, '')
  non_root_no_underscore = non_root.sub(/^_/, '').sub(/\/_/, '/')

  if resource = current_resource
    current_dir  = resource.file_descriptor[:relative_path].dirname
    relative_dir = current_dir + Pathname(non_root)
    relative_dir_no_underscore = current_dir + Pathname(non_root_no_underscore)
  end

  if relative_dir
    lookup_stack.push [relative_dir.to_s,
                       { preferred_engine: resource.file_descriptor[:relative_path]
                         .extname[1..-1].to_sym }]
  end
  lookup_stack.push [non_root]
  lookup_stack.push [non_root,
                     { try_static: try_static }]
  if relative_dir_no_underscore
    lookup_stack.push [relative_dir_no_underscore.to_s,
                       { try_static: try_static }]
  end
  lookup_stack.push [non_root_no_underscore,
                     { try_static: try_static }]

  lookup_stack.each do |args|
    partial_file = ::Middleman::TemplateRenderer.resolve_template(@app, *args)
    break if partial_file
  end

  partial_file
end
render(_, name, options={}, locals={}, &block) click to toggle source
# File lib/middleman-core/template_context.rb, line 103
def render(_, name, options={}, locals={}, &block)
  name = name.to_s

  partial_file = locate_partial(name, false) || locate_partial(name, true)

  raise ::Middleman::TemplateRenderer::TemplateNotFound, "Could not locate partial: #{name}" unless partial_file

  source_path = sitemap.file_to_path(partial_file)
  r = sitemap.find_resource_by_path(source_path)

  if (r && !r.template?) || (Tilt[partial_file[:full_path]].nil? && partial_file[:full_path].exist?)
    partial_file.read
  else
    opts = options.dup
    locs = locals.dup

    render_file(partial_file, locs, opts, &block)
  end
end
restore_buffer(buf_was) click to toggle source

Restore a previously saved buffer.

@api private @param [String] buf_was @return [void]

# File lib/middleman-core/template_context.rb, line 54
def restore_buffer(buf_was)
  @_out_buf = buf_was
end
save_buffer() click to toggle source

Return the current buffer to the caller and clear the value internally. Used when moving between templates when rendering layouts or partials.

@api private @return [String] The old buffer.

# File lib/middleman-core/template_context.rb, line 44
def save_buffer
  @_out_buf, buf_was = '', @_out_buf
  buf_was
end
wrap_layout(layout_name, &block) click to toggle source

Allow layouts to be wrapped in the contents of other layouts.

@param [String, Symbol] layout_name @return [void]

# File lib/middleman-core/template_context.rb, line 62
def wrap_layout(layout_name, &block)
  # Save current buffer for later
  buf_was = save_buffer

  # Find a layout for this file
  layout_file = ::Middleman::TemplateRenderer.locate_layout(@app, layout_name, current_engine)

  # Get the layout engine
  extension = File.extname(layout_file[:relative_path])
  engine = extension[1..-1].to_sym

  # Store last engine for later (could be inside nested renders)
  self.current_engine = engine
  engine_was = current_engine

  # By default, no content is captured
  content = ''

  # Attempt to capture HTML from block
  begin
    content = capture_html(&block) if block_given?
  ensure
    # Reset stored buffer, regardless of success
    restore_buffer(buf_was)
  end

  # Render the layout, with the contents of the block inside.
  concat_safe_content render_file(layout_file, @locs, @opts) { content }
ensure
  # Reset engine back to template's value, regardless of success
  self.current_engine = engine_was
end

Protected Instance Methods

_render_with_all_renderers(path, locs, context, opts, &block) click to toggle source
# File lib/middleman-core/template_context.rb, line 192
def _render_with_all_renderers(path, locs, context, opts, &block)
  # Keep rendering template until we've used up all extensions. This
  # handles cases like `style.css.sass.erb`
  content = nil

  while ::Middleman::Util.tilt_class(path)
    begin
      opts[:template_body] = content if content

      content_renderer = ::Middleman::FileRenderer.new(@app, path)
      content = content_renderer.render(locs, opts, context, &block)

      path = File.basename(path, File.extname(path))
    rescue LocalJumpError
      raise "Tried to render a layout (calls yield) at #{path} like it was a template. Non-default layouts need to be in #{@app.config[:source]}/#{@app.config[:layouts_dir]}."
    end
  end

  content
end
render_file(file, locs, opts, &block) click to toggle source
# File lib/middleman-core/template_context.rb, line 187
def render_file(file, locs, opts, &block)
  _render_with_all_renderers(file[:relative_path].to_s, locs, self, opts, &block)
end