class Jekyll::Tags::TemplateBlock

Constants

CONTEXT_CACHE_NAME
CONTEXT_DATA_NAME
CONTEXT_NAME
CONTEXT_SCOPE_NAME
CONTEXT_STORE_NAME
LIQUID_SYNTAX_REGEXP
PROPS_NAME
PROPS_REGEXP
TEMPLATE_DIR
WHITESPACE_REGEXP
YAML_FRONT_MATTER_REGEXP

Source github.com/jekyll/jekyll/blob/35c5e073625100b0f8f8eab6f7da6cb6d5734930/lib/jekyll/document.rb

Public Class Methods

new(tag_name, markup, tokens) click to toggle source

initialize Description: Extends Liquid's default initialize method.

Calls superclass method
# File lib/jekyll/jolt.rb, line 28
def initialize(tag_name, markup, tokens)
  super

  if markup =~ LIQUID_SYNTAX_REGEXP
    @attributes = {}
    @context = false
    @id = rand(36**8).to_s(36).freeze
    @props = {}
    @sanitize = false
    @site = false
    @template_name = $1.freeze

    @compressor = HtmlCompressor::Compressor.new({
      :remove_comments => true
    }).freeze

    # Parse parameters
    # Source: https://gist.github.com/jgatjens/8925165
    markup.scan(Liquid::TagAttributes) do |key, value|
      if (value =~ PROPS_REGEXP) != nil
        @props[key] = @attributes[key] = value
      else
        @props[key] = @attributes[key] = Liquid::Expression.parse(value)
      end
    end
  end
end

Public Instance Methods

add_template_to_dependency(path) click to toggle source

add_template_to_dependency(path = String) source: github.com/jekyll/jekyll/blob/e509cf2139d1a7ee11090b09721344608ecf48f6/lib/jekyll/tags/include.rb

# File lib/jekyll/jolt.rb, line 231
def add_template_to_dependency(path)
  if @context.registers[:page] && @context.registers[:page].key?("path")
    @site.regenerator.add_dependency(
      @site.in_source_dir(@context.registers[:page]["path"]),
      template_path(path)
    )
  end
end
blank?() click to toggle source

blank? Description: Override's Liquid's default blank checker. This allows for templates to be used without passing inner content.

# File lib/jekyll/jolt.rb, line 59
def blank?
  false
end
evaluate_props() click to toggle source

evaluate_props Description: Evaluates props that are being passed into the template.

# File lib/jekyll/jolt.rb, line 101
def evaluate_props()
  store = @context.registers[CONTEXT_STORE_NAME]
  data = store[@id]
  index = data[:index]

  if (index > 0)
    parent = store[store.keys[index - 1]]
    # Update the data scope
    @context[CONTEXT_SCOPE_NAME] = parent
    data.each do |key, value|
      if prop?(value)
        value = prop(parent, value)
        if value
          @props[key] = value
        end
      end
    end
  end
end
get_front_matter(content) click to toggle source

get_front_matter(content = String) Returns: A hash of data parsed from the content's YAML

# File lib/jekyll/jolt.rb, line 321
def get_front_matter(content)
  # Strip leading white-spaces
  content = unindent(content)
  if content =~ YAML_FRONT_MATTER_REGEXP
    front_matter = Regexp.last_match(0)
    values = SafeYAML.load(front_matter)
  else
    Hash.new
  end
end
load_cached_template(path) click to toggle source

load_cached_template(path = String) source: github.com/jekyll/jekyll/blob/e509cf2139d1a7ee11090b09721344608ecf48f6/lib/jekyll/tags/include.rb Returns: Liquid template from Jekyll's cache.

# File lib/jekyll/jolt.rb, line 243
def load_cached_template(path)
  @context.registers[CONTEXT_CACHE_NAME] ||= {}
  cached_templates = @context.registers[CONTEXT_CACHE_NAME]

  unless cached_templates.key?(path)
    cached_templates[path] = load_template()
  end
  template = cached_templates[path]

  update_attributes(template["data"])
  template["template"]
end
load_template() click to toggle source

load_template() Description: Extends Liquid's default load_template method. Also provides extra enhancements:

  • parses and sets template front-matter content

Returns: Template class

# File lib/jekyll/jolt.rb, line 274
def load_template()
  file = @site
    .liquid_renderer
    .file(template_path(@template_name))

  content = template_content(@template_name)

  template = Hash.new
  data = get_front_matter(content)
  markup = strip_front_matter(content)

  if content
    template["data"] = data
    template["template"] = file.parse(markup)
    template
  end
end
prop(data, value = "") click to toggle source

prop(data = Hash, value = String) Description: Returns the props value

# File lib/jekyll/jolt.rb, line 87
def prop(data, value = "")
  index = data[:index]
  value = data[value.gsub(PROPS_REGEXP, "")]
  if value and prop?(value) and index > 0
    store = @context.registers[CONTEXT_STORE_NAME]
    previous_scope = store[store.keys[index - 1]]
    prop(previous_scope, value)
  else
    value
  end
end
prop?(variable = "") click to toggle source

prop? Description: Determines if the variable is a template.props key Return: Boolean

# File lib/jekyll/jolt.rb, line 81
def prop?(variable = "")
  (variable =~ PROPS_REGEXP) != nil
end
render(context) click to toggle source

render Description: Extends Liquid's default render method. This method also adds additional features:

  • YAML front-matter parsing and handling

  • properly handles indentation and whitespace (resolves rendering issues)

  • ability to parse content as markdown vs. html

  • supports custom attributes to be used in template

Calls superclass method
# File lib/jekyll/jolt.rb, line 128
def render(context)
  @context = context
  @site = @context.registers[:site]

  template_store_data(@attributes)

  # This allows for Jekyll intelligently re-render markup during
  # incremental builds.
  add_template_to_dependency(@template_name)
  # Loading the template from cache/template directory
  template = load_cached_template(@template_name)

  # Props must be evaluated before super is initialized.
  # This allows for props to be evaluated before they're parsed by Liquid.
  evaluate_props()

  content = super

  # Return the parsed/normalized content
  render_template(template, content)
end
render_template(template, content) click to toggle source

render_template(template = Liquid::Template, content = String) Description: Serializes the context to be rendered by Liquid. Also resets the context to ensure template data doesn't leak from the scope. Returns: String

# File lib/jekyll/jolt.rb, line 155
def render_template(template, content)
  # Define the default template attributes
  # Source:
  # https://github.com/Shopify/liquid/blob/9a7778e52c37965f7b47673da09cfb82856a6791/lib/liquid/tags/include.rb
  @context[CONTEXT_NAME] = Hash.new

  # Add props
  update_attributes(@props)
  # Parse and extend template's front-matter with content front-matter
  update_attributes(get_front_matter(content))
  # Update the template's store data
  template_store_data(@attributes)

  # Setting context's template attributes from @attributes
  # This allows for @attributes to be used within the template as
  # {{ template.atttribute_name }}
  if @attributes.length
    @attributes.each do |key, value|
      val = @context.evaluate(value)
      @context[CONTEXT_NAME][key] = val

      # Adjust sanitize if parse: html
      if (key == "parse") && (val == "html")
        @sanitize = true
      end
    end
  end

  # puts @attributes
  @context[CONTEXT_NAME]["content"] = sanitize(strip_front_matter(content))
  store_template_data()
  content = @compressor.compress(template.render(@context))
  reset_template_data()

  content
end
reset_template_data() click to toggle source

reset_template_data() Description: Works with store_template_data. This is a work-around to ensure data stays in scope and isn't leaked from child->parent template.

# File lib/jekyll/jolt.rb, line 215
def reset_template_data()
  @context.registers[CONTEXT_DATA_NAME] ||= {}
  store = @context.registers[CONTEXT_DATA_NAME]
  if store.keys.length
    if store.keys[0] == @id
      # Resets template data
      @context.registers[CONTEXT_DATA_NAME] = false
      @context.registers[CONTEXT_SCOPE_NAME] = false
    else
      @context[CONTEXT_NAME] = store[store.keys[0]]
    end
  end
end
sanitize(content) click to toggle source

sanitize(content = String) Description: Renders the content as markdown or HTML based on the “parse” attribute. Returns: Content (string).

# File lib/jekyll/jolt.rb, line 296
def sanitize(content)
  unless @sanitize
    converter = @site.find_converter_instance(::Jekyll::Converters::Markdown)
    converter.convert(unindent(content))
  else
    unindent(content)
  end
end
store_template_data() click to toggle source

store_template_data() Description: Works with reset_template_data. This is a work-around to ensure data stays in scope and isn't leaked from child->parent template.

# File lib/jekyll/jolt.rb, line 204
def store_template_data()
  @context.registers[CONTEXT_DATA_NAME] ||= {}
  unless @context.registers[CONTEXT_DATA_NAME].key?(@id)
    @context.registers[CONTEXT_DATA_NAME][@id] = @context[CONTEXT_NAME]
  end
end
strip_front_matter(content) click to toggle source

strip_front_matter(content = String) Description: Removes the YAML front-matter content. Returns: Template content, with front-matter removed.

# File lib/jekyll/jolt.rb, line 335
def strip_front_matter(content)
  # Strip leading white-spaces
  content = unindent(content)
  if content =~ YAML_FRONT_MATTER_REGEXP
    front_matter = Regexp.last_match(0)
    # Returns content with stripped front-matter
    content.gsub!(front_matter, "")
  end
  content
end
template_content(template_name) click to toggle source

template_content(template_name = String) Description: Opens, reads, and returns template content as string. Returns: Template content

# File lib/jekyll/jolt.rb, line 265
def template_content(template_name)
  File.read(template_path(template_name).strip)
end
template_path(path) click to toggle source

template_path(path = String) Returns: A full file path of the template

# File lib/jekyll/jolt.rb, line 258
def template_path(path)
  File.join(@site.source.to_s, TEMPLATE_DIR, path.to_s)
end
template_store_data(data = {}) click to toggle source

template_store_data(data = Array) Description: Stores/updates the template data in cache Returns: Hash of the template store data

# File lib/jekyll/jolt.rb, line 66
def template_store_data(data = {})
  @context.registers[CONTEXT_STORE_NAME] ||= {}
  unless @context.registers[CONTEXT_STORE_NAME].key?(@id)
    @context.registers[CONTEXT_STORE_NAME][@id] = {
      "id": @id,
      "index": @context.registers[CONTEXT_STORE_NAME].length,
      "template_name": @template_name
    }
  end
  @context.registers[CONTEXT_STORE_NAME][@id] = @context.registers[CONTEXT_STORE_NAME][@id].merge(data)
end
unindent(content) click to toggle source

unindent(content = String) Description: Removes initial indentation. Returns: Content (string).

# File lib/jekyll/jolt.rb, line 308
def unindent(content)
  # Remove initial whitespace
  content.gsub!(/\A^\s*\n/, "")
  # Remove indentations
  if content =~ WHITESPACE_REGEXP
    indentation = Regexp.last_match(0).length
    content.gsub!(/^\ {#{indentation}}/, "")
  end
  content
end
update_attributes(data) click to toggle source

update_attributes(data = Hash) Description: Merges data with @attributes.

# File lib/jekyll/jolt.rb, line 194
def update_attributes(data)
  if data
    @attributes.merge!(data)
  end
end