class Liquid::BlockBody

Constants

ContentOfVariable
FullToken
FullTokenPossiblyInvalid
LiquidTagToken
TAGSTART
VARSTART
WhitespaceOrNothing

Attributes

nodelist[R]

Public Class Methods

new() click to toggle source
# File lib/liquid/block_body.rb, line 17
def initialize
  @nodelist = []
  @blank    = true
end
raise_missing_tag_terminator(token, parse_context) click to toggle source

@api private

# File lib/liquid/block_body.rb, line 76
def self.raise_missing_tag_terminator(token, parse_context)
  raise SyntaxError, parse_context.locale.t("errors.syntax.tag_termination", token: token, tag_end: TagEnd.inspect)
end
raise_missing_variable_terminator(token, parse_context) click to toggle source

@api private

# File lib/liquid/block_body.rb, line 81
def self.raise_missing_variable_terminator(token, parse_context)
  raise SyntaxError, parse_context.locale.t("errors.syntax.variable_termination", token: token, tag_end: VariableEnd.inspect)
end
render_node(context, output, node) click to toggle source

@api private

# File lib/liquid/block_body.rb, line 86
def self.render_node(context, output, node)
  node.render_to_output_buffer(context, output)
rescue => exc
  blank_tag = !node.instance_of?(Variable) && node.blank?
  rescue_render_node(context, output, node.line_number, exc, blank_tag)
end
rescue_render_node(context, output, line_number, exc, blank_tag) click to toggle source

@api private

# File lib/liquid/block_body.rb, line 94
def self.rescue_render_node(context, output, line_number, exc, blank_tag)
  case exc
  when MemoryError
    raise
  when UndefinedVariable, UndefinedDropMethod, UndefinedFilter
    context.handle_error(exc, line_number)
  else
    error_message = context.handle_error(exc, line_number)
    unless blank_tag # conditional for backwards compatibility
      output << error_message
    end
  end
end
unknown_tag_in_liquid_tag(tag, parse_context) click to toggle source

@api private

# File lib/liquid/block_body.rb, line 71
def self.unknown_tag_in_liquid_tag(tag, parse_context)
  Block.raise_unknown_tag(tag, 'liquid', '%}', parse_context)
end

Public Instance Methods

blank?() click to toggle source
# File lib/liquid/block_body.rb, line 190
def blank?
  @blank
end
freeze() click to toggle source
Calls superclass method
# File lib/liquid/block_body.rb, line 34
def freeze
  @nodelist.freeze
  super
end
parse(tokenizer, parse_context, &block) click to toggle source
# File lib/liquid/block_body.rb, line 22
def parse(tokenizer, parse_context, &block)
  raise FrozenError, "can't modify frozen Liquid::BlockBody" if frozen?

  parse_context.line_number = tokenizer.line_number

  if tokenizer.for_liquid_tag
    parse_for_liquid_tag(tokenizer, parse_context, &block)
  else
    parse_for_document(tokenizer, parse_context, &block)
  end
end
remove_blank_strings() click to toggle source

Remove blank strings in the block body for a control flow tag (e.g. ‘if`, `for`, `case`, `unless`) with a blank body.

For example, in a conditional assignment like the following

“‘ {% if size > max_size %}

{% assign size = max_size %}

{% endif %} “‘

we assume the intention wasn’t to output the blank spaces in the ‘if` tag’s block body, so this method will remove them to reduce the render output size.

Note that it is now preferred to use the ‘liquid` tag for this use case.

# File lib/liquid/block_body.rb, line 209
def remove_blank_strings
  raise "remove_blank_strings only support being called on a blank block body" unless @blank
  @nodelist.reject! { |node| node.instance_of?(String) }
end
render(context) click to toggle source
# File lib/liquid/block_body.rb, line 214
def render(context)
  render_to_output_buffer(context, +'')
end
render_to_output_buffer(context, output) click to toggle source
# File lib/liquid/block_body.rb, line 218
def render_to_output_buffer(context, output)
  freeze unless frozen?

  context.resource_limits.increment_render_score(@nodelist.length)

  idx = 0
  while (node = @nodelist[idx])
    if node.instance_of?(String)
      output << node
    else
      render_node(context, output, node)
      # If we get an Interrupt that means the block must stop processing. An
      # Interrupt is any command that stops block execution such as {% break %}
      # or {% continue %}. These tags may also occur through Block or Include tags.
      break if context.interrupt? # might have happened in a for-block
    end
    idx += 1

    context.resource_limits.increment_write_score(output)
  end

  output
end
whitespace_handler(token, parse_context) click to toggle source
# File lib/liquid/block_body.rb, line 176
def whitespace_handler(token, parse_context)
  if token[2] == WhitespaceControl
    previous_token = @nodelist.last
    if previous_token.is_a?(String)
      first_byte = previous_token.getbyte(0)
      previous_token.rstrip!
      if previous_token.empty? && parse_context[:bug_compatible_whitespace_trimming] && first_byte
        previous_token << first_byte
      end
    end
  end
  parse_context.trim_whitespace = (token[-3] == WhitespaceControl)
end

Private Instance Methods

create_variable(token, parse_context) click to toggle source
# File lib/liquid/block_body.rb, line 248
def create_variable(token, parse_context)
  if token.end_with?("}}")
    i = 2
    i = 3 if token[i] == "-"
    parse_end = token.length - 3
    parse_end -= 1 if token[parse_end] == "-"
    markup_end = parse_end - i + 1
    markup = markup_end <= 0 ? "" : token.slice(i, markup_end)

    return Variable.new(markup, parse_context)
  end

  BlockBody.raise_missing_variable_terminator(token, parse_context)
end
handle_invalid_tag_token(token, parse_context) { |token, token| ... } click to toggle source
# File lib/liquid/block_body.rb, line 119
        def handle_invalid_tag_token(token, parse_context)
  if token.end_with?('%}')
    yield token, token
  else
    BlockBody.raise_missing_tag_terminator(token, parse_context)
  end
end
parse_for_document(tokenizer, parse_context) { |tag_name, markup| ... } click to toggle source
# File lib/liquid/block_body.rb, line 127
        def parse_for_document(tokenizer, parse_context, &block)
  while (token = tokenizer.shift)
    next if token.empty?
    case
    when token.start_with?(TAGSTART)
      whitespace_handler(token, parse_context)
      unless token =~ FullToken
        return handle_invalid_tag_token(token, parse_context, &block)
      end
      tag_name = Regexp.last_match(2)
      markup   = Regexp.last_match(4)

      if parse_context.line_number
        # newlines inside the tag should increase the line number,
        # particularly important for multiline {% liquid %} tags
        parse_context.line_number += Regexp.last_match(1).count("\n") + Regexp.last_match(3).count("\n")
      end

      if tag_name == 'liquid'
        parse_liquid_tag(markup, parse_context)
        next
      end

      unless (tag = parse_context.environment.tag_for_name(tag_name))
        # end parsing if we reach an unknown tag and let the caller decide
        # determine how to proceed
        return yield tag_name, markup
      end
      new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
      @blank &&= new_tag.blank?
      @nodelist << new_tag
    when token.start_with?(VARSTART)
      whitespace_handler(token, parse_context)
      @nodelist << create_variable(token, parse_context)
      @blank = false
    else
      if parse_context.trim_whitespace
        token.lstrip!
      end
      parse_context.trim_whitespace = false
      @nodelist << token
      @blank &&= token.match?(WhitespaceOrNothing)
    end
    parse_context.line_number = tokenizer.line_number
  end

  yield nil, nil
end
parse_for_liquid_tag(tokenizer, parse_context) { |token, token| ... } click to toggle source
# File lib/liquid/block_body.rb, line 39
        def parse_for_liquid_tag(tokenizer, parse_context)
  while (token = tokenizer.shift)
    unless token.empty? || token.match?(WhitespaceOrNothing)
      unless token =~ LiquidTagToken
        # line isn't empty but didn't match tag syntax, yield and let the
        # caller raise a syntax error
        return yield token, token
      end
      tag_name = Regexp.last_match(1)
      markup   = Regexp.last_match(2)

      if tag_name == 'liquid'
        parse_context.line_number -= 1
        next parse_liquid_tag(markup, parse_context)
      end

      unless (tag = parse_context.environment.tag_for_name(tag_name))
        # end parsing if we reach an unknown tag and let the caller decide
        # determine how to proceed
        return yield tag_name, markup
      end
      new_tag = tag.parse(tag_name, markup, tokenizer, parse_context)
      @blank &&= new_tag.blank?
      @nodelist << new_tag
    end
    parse_context.line_number = tokenizer.line_number
  end

  yield nil, nil
end
parse_liquid_tag(markup, parse_context) click to toggle source
# File lib/liquid/block_body.rb, line 108
        def parse_liquid_tag(markup, parse_context)
  liquid_tag_tokenizer = parse_context.new_tokenizer(
    markup, start_line_number: parse_context.line_number, for_liquid_tag: true
  )
  parse_for_liquid_tag(liquid_tag_tokenizer, parse_context) do |end_tag_name, _end_tag_markup|
    if end_tag_name
      BlockBody.unknown_tag_in_liquid_tag(end_tag_name, parse_context)
    end
  end
end
raise_missing_tag_terminator(token, parse_context) click to toggle source

@deprecated Use {.raise_missing_tag_terminator} instead

# File lib/liquid/block_body.rb, line 264
def raise_missing_tag_terminator(token, parse_context)
  BlockBody.raise_missing_tag_terminator(token, parse_context)
end
raise_missing_variable_terminator(token, parse_context) click to toggle source

@deprecated Use {.raise_missing_variable_terminator} instead

# File lib/liquid/block_body.rb, line 269
def raise_missing_variable_terminator(token, parse_context)
  BlockBody.raise_missing_variable_terminator(token, parse_context)
end
render_node(context, output, node) click to toggle source
# File lib/liquid/block_body.rb, line 244
def render_node(context, output, node)
  BlockBody.render_node(context, output, node)
end