class Hiroiyomi::Html::Element

rubocop:disable Metrics/ClassLength Element

Constants

EXCEPTIONAL_ELEMENT_NAME_LIST

Attributes

attributes[RW]
children[RW]
name[RW]
parent[RW]

Public Class Methods

new(name, parent: nil, attributes: [], children: []) click to toggle source
# File lib/hiroiyomi/html/element.rb, line 147
def initialize(name, parent: nil, attributes: [], children: [])
  @name       = name
  @parent     = parent
  @attributes = attributes
  @children   = children
end
value_of(file, parent_element = nil) click to toggle source

rubocop:disable Metrics/MethodLength

# File lib/hiroiyomi/html/element.rb, line 21
def value_of(file, parent_element = nil)
  # name
  name = extract_element_name(file)

  return parent_element if name.empty?

  # element
  element = Element.new(name, parent: parent_element)

  if parent_element.nil?
    parent_element = element
  else
    parent_element.element = element
  end

  # attributes
  element.attributes = extract_attributes(file)

  # exceptional elements
  if EXCEPTIONAL_ELEMENT_NAME_LIST.include?(name.downcase)
    element.element = extract_exceptional_element_text(file, name)
    return parent_element
  end

  # text if >..., close if /, or open element if >...<
  Text.add_text_to_element_or_parse(file, element)

  # close check. move element children to parent element if not closed. e.g. <img ...>
  element.move_children_to(parent_element) unless validate_closing_element?(file, element)

  parent_element
end

Private Class Methods

extract_attributes(file) click to toggle source
# File lib/hiroiyomi/html/element.rb, line 138
def extract_attributes(file)
  attributes = []
  while (attribute = Attribute.value_of(file))
    attributes.push(attribute)
  end
  attributes
end
extract_element_name(file) click to toggle source
# File lib/hiroiyomi/html/element.rb, line 129
def extract_element_name(file)
  while (c = file.getc)
    next unless c == '<'
    next if skip_comments(file)
    return DOMParserHelper.extract_string(file)
  end
  ''
end
extract_exceptional_element_text(file, name) click to toggle source

rubocop:disable Metrics/AbcSize, Metrics/MethodLength For script, style. First char must be > after attributes

# File lib/hiroiyomi/html/element.rb, line 97
def extract_exceptional_element_text(file, name)
  DOMParserHelper.skip_ignore_chars(file)
  file.getc # drop >
  string = ''
  while (c = file.getc)
    if c == '<'
      cur_pos = file.pos
      if file.getc == '/' && name == DOMParserHelper.extract_string(file)
        DOMParserHelper.skip_ignore_chars(file)
        file.getc # drop >
        break
      end
      file.pos = cur_pos
    end
    string += c
  end
  return Text.new(string) unless string.empty?
  nil
end
skip_comments(file) click to toggle source

rubocop:enable Metrics/AbcSize, Metrics/MethodLength

# File lib/hiroiyomi/html/element.rb, line 118
def skip_comments(file)
  cur_pos = file.pos
  if file.getc == '!'
    # Skip like <!document html>, <!--
    DOMParserHelper.extract_comments(file)
    return true
  end
  file.pos = cur_pos
  false
end
validate_closing_element?(file, element) click to toggle source

rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity

# File lib/hiroiyomi/html/element.rb, line 58
def validate_closing_element?(file, element)
  open = false

  while (c = file.getc)
    # /> or </
    if c == '/'
      open = false
      cur_pos = DOMParserHelper.cur_pos(file, c)
      next_c = file.getc
      return true if next_c == '>' # case of />

      # Check whether name is the same or not
      file.ungetc(next_c)
      close_name = DOMParserHelper.extract_string(file)

      return false if close_name.empty?

      is_closed = close_name == element.name
      return true if is_closed

      # Try it again if name is not matched and next close element name does not exist in parent elements
      next unless element.parents?(close_name)

      file.pos = cur_pos
      return false
    elsif c == '<' # case of </
      Text.add_text_to_element_or_parse(file, element)
      open = true
    elsif open
      file.ungetc(c)
      return false
    end
  end
  false
end

Public Instance Methods

deep_select(search_name_list = [], searched = []) click to toggle source
# File lib/hiroiyomi/html/element.rb, line 177
def deep_select(search_name_list = [], searched = [])
  searched.push(self) if search_name_list.include?(name.downcase)
  children.each do |child|
    next if child.text?
    if search_name_list.include?(child.name.downcase)
      searched.push(child)
    else
      child.deep_select(search_name_list, searched)
    end
  end
  searched
end
each() { |child| ... } click to toggle source
# File lib/hiroiyomi/html/element.rb, line 158
def each
  @children.each do |child|
    yield child
  end
end
element=(element) click to toggle source
# File lib/hiroiyomi/html/element.rb, line 154
def element=(element)
  @children.push(element) unless element.nil?
end
inner_html() click to toggle source
# File lib/hiroiyomi/html/element.rb, line 190
def inner_html
  children.map(&:to_s).join
end
move_children_to(element) click to toggle source
# File lib/hiroiyomi/html/element.rb, line 164
def move_children_to(element)
  each do |child|
    element.element = child
  end
  children.clear
end
parents?(name) click to toggle source
# File lib/hiroiyomi/html/element.rb, line 171
def parents?(name)
  return false if parent.nil?
  return true if parent.name == name
  parent.parents?(name)
end
to_s() click to toggle source
# File lib/hiroiyomi/html/element.rb, line 194
def to_s
  attrs = attributes.map(&:to_s).join(' ')
  attrs = ' ' + attrs unless attrs.empty?
  "<#{name}#{attrs}>#{inner_html}</#{name}>"
end