class Himl::Parser::Document

Constants

BLOCK_KEYWORD_REGEX
BLOCK_REGEXP
ERB_TAG
ERB_TAG_REGEXP
ErbBlockStartMarker
ErbEndMarker
MID_BLOCK_KEYWORDS

Copied from Haml

ROOT_NODE
START_BLOCK_KEYWORDS
START_BLOCK_KEYWORD_REGEX
Tag
VOID_TAGS

Attributes

context[RW]

Public Class Methods

new(template) click to toggle source
# File lib/himl/parser.rb, line 52
def initialize(template)
  @original_template, @tags, @end_tags = template, [], []
  template = template.gsub(ERB_TAG_REGEXP, "<#{ERB_TAG}>\\1</#{ERB_TAG}>")
  @lines = "<#{ROOT_NODE}>\n#{template}</#{ROOT_NODE}>\n".lines
end

Public Instance Methods

characters(string) click to toggle source
# File lib/himl/parser.rb, line 106
def characters(string)
  if (last_tag = @tags.last).erb_tag?
    case string.strip
    when 'end', '}'
      @tags.pop
      @tags << ErbEndMarker.new(nil, last_tag.indentation, last_tag.line)
    when BLOCK_KEYWORD_REGEX
      @tags.pop
      @tags.pop if (ErbBlockStartMarker === @tags.last) && (@tags.last.indentation == last_tag.indentation)
      @tags << ErbBlockStartMarker.new(nil, last_tag.indentation, last_tag.line, 'end')
    end
  end

  erb_tag = @tags.reverse_each.detect(&:erb_tag?)
  if erb_tag && (match = BLOCK_REGEXP.match(string))
    erb_tag.block_start = match[1].strip
  end
end
close_document!() click to toggle source
# File lib/himl/parser.rb, line 125
def close_document!
  @current_tag = nil
  close_tags

  raise SyntaxError, "Unclosed tag: #{@tags.last}" if @tags.last.name != ROOT_NODE
end
end_element(name) click to toggle source
# File lib/himl/parser.rb, line 80
def end_element(name)
  last_tag = @tags.last
  return if last_tag.name == ROOT_NODE

  if (name == ERB_TAG) && last_tag.is_a?(ErbEndMarker)
    raise SyntaxError, "end of block indentation mismatch at line: #{current_line}, column: #{current_indentation}" if last_tag.indentation != @tags[-2].indentation

    @tags.pop

    if (ErbBlockStartMarker === @tags.last) && (@tags.last.indentation == last_tag.indentation)
      @tags.pop
    else
      raise SyntaxError, "end of block mismatch at line: #{current_line}, column: #{current_indentation}" unless (ErbBlockStartMarker === @tags.last) && (@tags.last.indentation == last_tag.indentation)
    end
  end

  if name == last_tag.name
    if ((last_tag.indentation == current_indentation) || (last_tag.line == current_line))
      @tags.pop
    else
      raise SyntaxError, "end tag indentation mismatch for <#{name}> at line: #{current_line}, column: #{current_indentation}"
    end
  end
  @tags << ErbBlockStartMarker.new(nil, last_tag.indentation, last_tag.line, last_tag.block_end) if (last_tag.name == ERB_TAG) && last_tag.has_block?
end
erb_template() click to toggle source
# File lib/himl/parser.rb, line 62
def erb_template
  lines = @original_template.lines

  @end_tags.reverse_each do |index, tag|
    lines.insert index - 1, tag
  end

  lines.join
end
start_element(name, *) click to toggle source
# File lib/himl/parser.rb, line 72
def start_element(name, *)
  @current_tag = name

  close_tags unless name == ROOT_NODE

  @tags << Tag.new(name, current_indentation, current_line) unless VOID_TAGS.include? name.downcase
end
template() click to toggle source
# File lib/himl/parser.rb, line 58
def template
  @lines.join
end

Private Instance Methods

close_tags() click to toggle source
# File lib/himl/parser.rb, line 148
def close_tags
  while (@tags.last.name != ROOT_NODE) && (current_indentation <= @tags.last.indentation)
    if (@current_tag == ERB_TAG) && (ErbBlockStartMarker === @tags.last) && (@tags.last.indentation == current_indentation)
      break
    else
      @end_tags << [last_non_empty_line, @tags.last.end_tag]
      @tags.pop
    end
  end
end
current_indentation() click to toggle source
# File lib/himl/parser.rb, line 134
def current_indentation
  line = current_line
  line -=1 until (ret = @lines[line].slice(0, context.column).rindex('<'))
  ret
end
current_line() click to toggle source
# File lib/himl/parser.rb, line 140
def current_line
  (context.column == 1) && (context.line > 1) ? context.line - 2 : context.line - 1
end
last_non_empty_line() click to toggle source
# File lib/himl/parser.rb, line 144
def last_non_empty_line
  @lines[0, current_line].each_with_index.reverse_each {|str, i| break i + 1 unless str.chomp.empty? }
end