Class: Himl::Parser::Document

Inherits:
Nokogiri::XML::SAX::Document
  • Object
show all
Defined in:
lib/himl/parser.rb

Defined Under Namespace

Classes: Tag

Constant Summary collapse

ErbEndMarker =
Class.new(Tag)
ErbBlockStartMarker =
Class.new(Tag)
ROOT_NODE =
'THE_HIML_ROOT_NODE'
ERB_TAG =
'HIML_ERB_TAG'
ERB_TAG_REGEXP =
/<%(?:=|==|-|#|%)?(.*?)(?:[-=])?%>/
BLOCK_REGEXP =
/\s*((\s+|\))do|\{)(\s*\|[^|]*\|)?\s*\Z/
VOID_TAGS =
%w(area base br col command embed hr img input keygen link meta param source track wbr).freeze
MID_BLOCK_KEYWORDS =

Copied from Haml

%w[else elsif rescue ensure end when]
START_BLOCK_KEYWORDS =
%w[if begin case unless]
START_BLOCK_KEYWORD_REGEX =
/(?:\w+(?:,\s*\w+)*\s*=\s*)?(#{START_BLOCK_KEYWORDS.join('|')})/
BLOCK_KEYWORD_REGEX =
/^-?\s*(?:(#{MID_BLOCK_KEYWORDS.join('|')})|#{START_BLOCK_KEYWORD_REGEX.source})\b/

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(template) ⇒ Document

Returns a new instance of Document.



52
53
54
55
56
# 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

Instance Attribute Details

#contextObject

Returns the value of attribute context.



50
51
52
# File 'lib/himl/parser.rb', line 50

def context
  @context
end

Instance Method Details

#characters(string) ⇒ Object



106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# 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!Object

Raises:

  • (SyntaxError)


125
126
127
128
129
130
# 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) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# 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_templateObject



62
63
64
65
66
67
68
69
70
# 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) ⇒ Object



72
73
74
75
76
77
78
# 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

#templateObject



58
59
60
# File 'lib/himl/parser.rb', line 58

def template
  @lines.join
end