module Middleman::CoreExtensions::Rendering::InstanceMethods

def _render_with_all_renderers(path, locs, context, opts, &block)

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 ::Tilt[path]
    begin
      opts[:template_body] = content if content
      content = if block_given?
        render_individual_file(path, locs, opts, context, &block)
      else
        render_individual_file(path, locs, opts, context)
      end
      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 #{source}/#{config[:layouts_dir]}."
    end
  end
  content
end

def current_engine

Returns:
  • (Symbol, nil) -
def current_engine
  @_current_engine ||= nil
end

def current_engine=(v)

Returns:
  • (Symbol, nil) -
def current_engine=(v)
  @_current_engine = v
end

def fetch_layout(engine, opts)

Returns:
  • (String) -

Parameters:
  • opts (Hash) --
  • engine (Symbol) --
def fetch_layout(engine, opts)
  # The layout name comes from either the system default or the options
  local_layout = opts.key?(:layout) ? opts[:layout] : config[:layout]
  return false unless local_layout
  # Look for engine-specific options
  engine_options = respond_to?(engine) ? send(engine) : {}
  # The engine for the layout can be set in options, engine_options or passed
  # into this method
  layout_engine = if opts.key?(:layout_engine)
    opts[:layout_engine]
  elsif engine_options.key?(:layout_engine)
    engine_options[:layout_engine]
  else
    engine
  end
  # Automatic mode
  if local_layout == :_auto_layout
    # Look for :layout of any extension
    # If found, use it. If not, continue
    locate_layout(:layout, layout_engine) || false
  else
    # Look for specific layout
    # If found, use it. If not, error.
    if layout_path = locate_layout(local_layout, layout_engine)
      layout_path
    else
      raise ::Middleman::CoreExtensions::Rendering::TemplateNotFound, "Could not locate layout: #{local_layout}"
    end
  end
end

def locate_layout(name, preferred_engine=nil)

Returns:
  • (String) -

Parameters:
  • preferred_engine (Symbol) --
  • name (String) --
def locate_layout(name, preferred_engine=nil)
  resolve_opts = {}
  resolve_opts[:preferred_engine] = preferred_engine unless preferred_engine.nil?
  # Check layouts folder
  layout_path = resolve_template(File.join(config[:layouts_dir], name.to_s), resolve_opts)
  # If we didn't find it, check root
  layout_path = resolve_template(name, resolve_opts) unless layout_path
  # Return the path
  layout_path
end

def locate_partial(partial_name, try_static=true)

Returns:
  • (String) -

Parameters:
  • partial_name (String) --
def locate_partial(partial_name, try_static=true)
  resolve_opts = { try_without_underscore: true, try_static: try_static }
  # If the path is known to the sitemap
  if resource = sitemap.find_resource_by_path(current_path)
    current_dir = File.dirname(resource.source_file)
    resolve_opts[:preferred_engine] = File.extname(resource.source_file)[1..-1].to_sym
    # Look for partials relative to the current path
    relative_dir = File.join(current_dir.sub(%r{^#{Regexp.escape(source_dir)}/?}, ''), partial_name)
    resolve_template(relative_dir, resolve_opts) || resolve_template(partial_name, resolve_opts)
  else
    resolve_template(partial_name, resolve_opts)
  end
end

def options_for_ext(ext)

Returns:
  • (Hash) -

Parameters:
  • ext (String) --
def options_for_ext(ext)
  # Read options for extension from config/Tilt or cache
  cache.fetch(:options_for_ext, ext) do
    options = {}
    # Find all the engines which handle this extension in tilt. Look for
    # config variables of that name and merge it
    extension_class = ::Tilt[ext]
    ::Tilt.mappings.each do |mapping_ext, engines|
      next unless engines.include? extension_class
      engine_options = config[mapping_ext.to_sym] || {}
      options.merge!(engine_options)
    end
    options
  end
end

def render(_, data, options={}, &block)

Returns:
  • (String) -

Parameters:
  • options (Hash) --
  • data (String, Symbol) --
  • engine (String, Symbol) --
def render(_, data, options={}, &block)
  partial_name = data.to_s
  found_partial = locate_partial(partial_name, false) || locate_partial(partial_name, true)
  # Look in the partials_dir for the partial with the current engine
  unless found_partial
    partials_path = File.join(config[:partials_dir], partial_name)
    found_partial = locate_partial(partials_path, false) || locate_partial(partials_path, true)
  end
  raise ::Middleman::CoreExtensions::Rendering::TemplateNotFound, "Could not locate partial: #{data}" unless found_partial
  locals = options[:locals]
  if ::Tilt[found_partial]
    # Render the partial if found, otherwide throw exception
    _render_with_all_renderers(found_partial, locals, self, options, &block)
  else
    File.read(found_partial)
  end
end

def render_individual_file(path, locs={}, opts={}, context=self, &block)

Returns:
  • (String) -

Parameters:
  • context (Class) --
  • opts (Hash) --
  • locs (Hash) --
  • path (String, Symbol) --
def render_individual_file(path, locs={}, opts={}, context=self, &block)
  path = path.to_s
  # Mutability is FUN!
  # Try to work around: https://github.com/middleman/middleman/issues/501
  locs = locs.dup
  # Detect the remdering engine from the extension
  extension = File.extname(path)
  engine = extension[1..-1].to_sym
  # Store last engine for later (could be inside nested renders)
  context.current_engine, engine_was = engine, context.current_engine
  # Save current buffer for later
  @_out_buf, _buf_was = '', @_out_buf
  # Read from disk or cache the contents of the file
  body = if opts[:template_body]
    opts.delete(:template_body)
  else
    template_data_for_file(path)
  end
  # Merge per-extension options from config
  extension = File.extname(path)
  options = opts.dup.merge(options_for_ext(extension))
  options[:outvar] ||= '@_out_buf'
  options.delete(:layout)
  # Overwrite with frontmatter options
  options = options.deep_merge(options[:renderer_options]) if options[:renderer_options]
  template_class = ::Tilt[path]
  # Allow hooks to manipulate the template before render
  self.class.callbacks_for_hook(:before_render).each do |callback|
    # Uber::Options::Value doesn't respond to call
    newbody = if callback.respond_to?(:call)
      callback.call(body, path, locs, template_class)
    elsif callback.respond_to?(:evaluate)
      callback.evaluate(self, body, path, locs, template_class)
    end
    body = newbody if newbody # Allow the callback to return nil to skip it
  end
  # Read compiled template from disk or cache
  template = cache.fetch(:compiled_template, extension, options, body) do
    ::Tilt.new(path, 1, options) { body }
  end
  # Render using Tilt
  content = template.render(context, locs, &block)
  # Allow hooks to manipulate the result after render
  self.class.callbacks_for_hook(:after_render).each do |callback|
    # Uber::Options::Value doesn't respond to call
    newcontent = if callback.respond_to?(:call)
      content = callback.call(content, path, locs, template_class)
    elsif callback.respond_to?(:evaluate)
      content = callback.evaluate(self, content, path, locs, template_class)
    end
    content = newcontent if newcontent # Allow the callback to return nil to skip it
  end
  output = ::ActiveSupport::SafeBuffer.new ''
  output.safe_concat content
  output
ensure
  # Reset stored buffer
  @_out_buf = _buf_was
  context.current_engine = engine_was
end

def render_template(path, locs={}, opts={}, blocks=[])

Returns:
  • (String) -

Parameters:
  • opts (Hash) --
  • locs (Hash) --
  • path (String) --
def render_template(path, locs={}, opts={}, blocks=[])
  extension = File.extname(path)
  engine = extension[1..-1].to_sym
  if defined?(::I18n)
    old_locale = ::I18n.locale
    ::I18n.locale = opts[:lang] if opts[:lang]
  end
  # Use a dup of self as a context so that instance variables set within
  # the template don't persist for other templates.
  context = dup
  blocks.each do |block|
    context.instance_eval(&block)
  end
  # Store current locs/opts for later
  @current_locs = locs
  @current_opts = opts
  content = _render_with_all_renderers(path, locs, context, opts)
  # If we need a layout and have a layout, use it
  if layout_path = fetch_layout(engine, opts)
    content = render_individual_file(layout_path, locs, opts, context) { content }
  end
  # Return result
  content
ensure
  # Pop all the saved variables from earlier as we may be returning to a
  # previous render (layouts, partials, nested layouts).
  ::I18n.locale = old_locale if defined?(::I18n)
  @content_blocks = nil
  @current_locs = nil
  @current_opts = nil
end

def resolve_template(request_path, options={})

Returns:
  • (Array, Boolean) -

Options Hash: (**options)
  • :try_static (Boolean) --
  • :try_without_underscore (Boolean) --
  • :preferred_engine (Boolean) -- If set, try this engine first, then fall back to any engine.

Parameters:
  • request_path (String) --
def resolve_template(request_path, options={})
  # Find the path by searching or using the cache
  request_path = request_path.to_s
  cache.fetch(:resolve_template, request_path, options) do
    relative_path = Util.strip_leading_slash(request_path)
    on_disk_path  = File.expand_path(relative_path, source_dir)
    preferred_engines = if options[:try_static]
      [nil]
    else
      possible_engines = ['*'] # By default, any engine will do
      # If we're specifically looking for a preferred engine
      if options.key?(:preferred_engine)
        extension_class = ::Tilt[options[:preferred_engine]]
        # Get a list of extensions for a preferred engine
        matched_exts = ::Tilt.mappings.select do |_, engines|
          engines.include? extension_class
        end.keys
        # Prefer to look for the matched extensions
        unless matched_exts.empty?
          possible_engines.unshift('{' + matched_exts.join(',') + '}')
        end
      end
      possible_engines
    end
    search_paths = preferred_engines.flat_map do |preferred_engine|
      path_with_ext = on_disk_path.dup
      path_with_ext << ('.' + preferred_engine) unless preferred_engine.nil?
      paths = [path_with_ext]
      if options[:try_without_underscore]
        paths << path_with_ext.sub(relative_path, relative_path.sub(/^_/, '').sub(/\/_/, '/'))
      end
      paths
    end
    found_path = nil
    search_paths.each do |path_with_ext|
      found_path = Dir[path_with_ext].find do |path|
        ::Tilt[path]
      end
      unless found_path
        found_path = path_with_ext if File.exist?(path_with_ext)
      end
      break if found_path
    end
    # If we found one, return it
    if found_path
      found_path
    elsif File.exist?(on_disk_path)
      on_disk_path
    else
      false
    end
  end
end

def template_data_for_file(path)

Returns:
  • (String) -

Parameters:
  • path (String) --
def template_data_for_file(path)
  File.read(File.expand_path(path, source_dir))
end

def template_extensions(extension_map=nil)

Returns:
  • (Hash) -

Parameters:
  • extension_map (Hash) --
def template_extensions(extension_map=nil)
  @_template_extensions ||= {}
  @_template_extensions.merge!(extension_map) if extension_map
  @_template_extensions
end

def wrap_layout(layout_name, &block)

Returns:
  • (void) -

Parameters:
  • layout_name (String, Symbol) --
def wrap_layout(layout_name, &block)
  # Save current buffer for later
  @_out_buf, _buf_was = '', @_out_buf
  layout_path = locate_layout(layout_name, current_engine)
  extension = File.extname(layout_path)
  engine = extension[1..-1].to_sym
  # Store last engine for later (could be inside nested renders)
  self.current_engine, engine_was = engine, current_engine
  begin
    content = if block_given?
      capture_html(&block)
    else
      ''
    end
  ensure
    # Reset stored buffer
    @_out_buf = _buf_was
  end
  concat_safe_content render_individual_file(layout_path, @current_locs || {}, @current_opts || {}, self) { content }
ensure
  self.current_engine = engine_was
end