Class: HTML5::Phase

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/html5/html5parser/phase.rb

Overview

Base class for helper objects that implement each phase of processing.

Handler methods should be in the following order (they can be omitted):

* EOF
* Comment
* Doctype
* SpaceCharacters
* Characters
* StartTag
  - startTag* methods
* EndTag
  - endTag* methods

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(parser, tree) ⇒ Phase

Returns a new instance of Phase.



81
82
83
# File 'lib/html5/html5parser/phase.rb', line 81

def initialize(parser, tree)
  @parser, @tree = parser, tree
end

Class Method Details

.end_tag_handlersObject



71
72
73
# File 'lib/html5/html5parser/phase.rb', line 71

def self.end_tag_handlers
  @end_tag_handlers ||= Hash.new('endTagOther')
end

.handle_end(*tags) ⇒ Object

Declare what end tags this Phase handles. Behaves like handle_start.



77
78
79
# File 'lib/html5/html5parser/phase.rb', line 77

def self.handle_end(*tags)
  end_tag_handlers.update tag_handlers('endTag', *tags)
end

.handle_start(*tags) ⇒ Object

Declare what start tags this Phase handles. Can be called more than once.

Example usage:

handle_start 'html'
# html start tags will be handled by a method named 'startTagHtml'

handle_start %( base link meta )
# base, link and meta start tags will be handled by a method named 'startTagBaseLinkMeta'

handle_start %( li dt dd ) => 'ListItem'
# li, dt, and dd start tags will be handled by a method named 'startTagListItem'


67
68
69
# File 'lib/html5/html5parser/phase.rb', line 67

def self.handle_start(*tags)
  start_tag_handlers.update tag_handlers('startTag', *tags)
end

.start_tag_handlersObject



50
51
52
# File 'lib/html5/html5parser/phase.rb', line 50

def self.start_tag_handlers
  @start_tag_handlers ||= Hash.new('startTagOther')
end

.tag_handlers(prefix, *tags) ⇒ Object

The following example call:

tag_handlers('startTag', 'html', %w( base link meta ), %w( li dt dd ) => 'ListItem')

…would return a hash equal to this:

{ 'html' => 'startTagHtml',
  'base' => 'startTagBaseLinkMeta',
  'link' => 'startTagBaseLinkMeta',
  'meta' => 'startTagBaseLinkMeta',
  'li'   => 'startTagListItem',
  'dt'   => 'startTagListItem',
  'dd'   => 'startTagListItem'  }


34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/html5/html5parser/phase.rb', line 34

def self.tag_handlers(prefix, *tags)
  mapping = {}
  if tags.last.is_a?(Hash)
    tags.pop.each do |names, handler_method_suffix|
      handler_method = prefix + handler_method_suffix
      Array(names).each {|name| mapping[name] = handler_method }
    end
  end
  tags.each do |names|
    names = Array(names)
    handler_method = prefix + names.map {|name| name.capitalize }.join
    names.each {|name| mapping[name] = handler_method }
  end
  mapping
end

Instance Method Details

#adjust_foreign_attributes(attributes) ⇒ Object



167
168
169
# File 'lib/html5/html5parser/phase.rb', line 167

def adjust_foreign_attributes(attributes)
  attributes
end

#adjust_mathml_attributes(attributes) ⇒ Object



157
158
159
160
161
162
163
164
165
# File 'lib/html5/html5parser/phase.rb', line 157

def adjust_mathml_attributes(attributes)
  attributes.collect do |a|
    if a.first =='definitionurl'
      ['definitionURL', a[1]]
    else
      a
    end
  end
end

#assert(value) ⇒ Object



140
141
142
# File 'lib/html5/html5parser/phase.rb', line 140

def assert(value)
  throw AssertionError.new unless value
end

#in_scope?(*args) ⇒ Boolean

Returns:

  • (Boolean)


144
145
146
# File 'lib/html5/html5parser/phase.rb', line 144

def in_scope?(*args)
  @tree.elementInScope(*args)
end

#process_eofObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/html5/html5parser/phase.rb', line 85

def process_eof
  @tree.generateImpliedEndTags

  if @tree.open_elements.length > 2
    parse_error("expected-closing-tag-but-got-eof")
  elsif @tree.open_elements.length == 2 and @tree.open_elements[1].name != 'body'
    # This happens for framesets or something?
    parse_error("expected-closing-tag-but-got-eof")
  elsif @parser.inner_html and @tree.open_elements.length > 1 
    # XXX This is not what the specification says. Not sure what to do here.
    parse_error("eof-in-innerhtml")
  end
  # Betting ends.
end

#processComment(data) ⇒ Object



100
101
102
103
104
# File 'lib/html5/html5parser/phase.rb', line 100

def processComment(data)
  # For most phases the following is correct. Where it's not it will be
  # overridden.
  @tree.insert_comment(data, @tree.open_elements.last)
end

#processDoctype(name, publicId, systemId, correct) ⇒ Object



106
107
108
# File 'lib/html5/html5parser/phase.rb', line 106

def processDoctype(name, publicId, systemId, correct)
  parse_error("unexpected-doctype")
end

#processEndTag(name) ⇒ Object



136
137
138
# File 'lib/html5/html5parser/phase.rb', line 136

def processEndTag(name)
  send self.class.end_tag_handlers[name], name
end

#processSpaceCharacters(data) ⇒ Object



110
111
112
# File 'lib/html5/html5parser/phase.rb', line 110

def processSpaceCharacters(data)
  @tree.insertText(data)
end

#processStartTag(name, attributes, self_closing = false) ⇒ Object



114
115
116
117
118
119
120
# File 'lib/html5/html5parser/phase.rb', line 114

def processStartTag(name, attributes, self_closing=false)
  if method(self.class.start_tag_handlers[name]).arity == 2
    send self.class.start_tag_handlers[name], name, attributes
  else
    send self.class.start_tag_handlers[name], name, attributes, self_closing
  end
end

#remove_open_elements_until(name = nil) ⇒ Object



148
149
150
151
152
153
154
155
# File 'lib/html5/html5parser/phase.rb', line 148

def remove_open_elements_until(name=nil)
  finished = false
  until finished || @tree.open_elements.length == 0
    element = @tree.open_elements.pop
    finished = name.nil? ? yield(element) : element.name == name
  end
  return element
end

#startTagHtml(name, attributes) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/html5/html5parser/phase.rb', line 122

def startTagHtml(name, attributes)
  if @parser.first_start_tag == false and name == 'html'
     parse_error("non-html-root")
  end
  # XXX Need a check here to see if the first start tag token emitted is
  # this token... If it's not, invoke parse_error.
  attributes.each do |attr, value|
    unless @tree.open_elements.first.attributes.has_key?(attr)
      @tree.open_elements.first.attributes[attr] = value
    end
  end
  @parser.first_start_tag = false
end