Class: Html2rss::SST::Node

Inherits:
Data
  • Object
show all
Defined in:
lib/html2rss/sst/node.rb

Overview

Immutable simplified semantic tree node. Predicates and traversal live on the type so Scoring/Segmenter never touch Nokogiri.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#attrsObject (readonly)

Returns the value of attribute attrs

Returns:

  • (Object)

    the current value of attrs



8
9
10
# File 'lib/html2rss/sst/node.rb', line 8

def attrs
  @attrs
end

#childrenObject (readonly)

Returns the value of attribute children

Returns:

  • (Object)

    the current value of children



8
9
10
# File 'lib/html2rss/sst/node.rb', line 8

def children
  @children
end

#nameObject (readonly)

Returns the value of attribute name

Returns:

  • (Object)

    the current value of name



8
9
10
# File 'lib/html2rss/sst/node.rb', line 8

def name
  @name
end

#own_textObject (readonly)

Returns the value of attribute own_text

Returns:

  • (Object)

    the current value of own_text



8
9
10
# File 'lib/html2rss/sst/node.rb', line 8

def own_text
  @own_text
end

#tag_pathObject (readonly)

Returns the value of attribute tag_path

Returns:

  • (Object)

    the current value of tag_path



8
9
10
# File 'lib/html2rss/sst/node.rb', line 8

def tag_path
  @tag_path
end

Class Method Details

.build(name:, attrs: nil, own_text: nil, children: nil, tag_path: nil) ⇒ Node

Parameters:

  • name (Symbol, String)
  • attrs (Attrs, nil) (defaults to: nil)
  • own_text (String, nil) (defaults to: nil)
  • children (Array<Node>, nil) (defaults to: nil)
  • tag_path (String, nil) (defaults to: nil)

    index-free ancestry path for list clustering

Returns:

Raises:

  • (ArgumentError)

    on invalid name/attrs/children



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/html2rss/sst/node.rb', line 17

def self.build(name:, attrs: nil, own_text: nil, children: nil, tag_path: nil)
  attrs_value = coerce_attrs(attrs)
  kids = coerce_children(children)

  new(
    name: coerce_name(name),
    attrs: attrs_value,
    own_text: own_text.to_s.freeze,
    children: kids,
    tag_path: tag_path.to_s.freeze
  )
end

Instance Method Details

#descendantsArray<Node>

Returns all descendants excluding self.

Returns:

  • (Array<Node>)

    all descendants excluding self



98
99
100
# File 'lib/html2rss/sst/node.rb', line 98

def descendants
  children.flat_map { |child| [child, *child.descendants] }
end

#each_node {|node| ... } ⇒ Enumerator, Array<Node>

Depth-first enumeration of self and descendants.

Yield Parameters:

Returns:

  • (Enumerator, Array<Node>)


89
90
91
92
93
94
# File 'lib/html2rss/sst/node.rb', line 89

def each_node(&block)
  return enum_for(:each_node) unless block

  yield self
  children.each { |child| child.each_node(&block) }
end

#eligible_href?Boolean

Returns:

  • (Boolean)


77
78
79
80
81
82
# File 'lib/html2rss/sst/node.rb', line 77

def eligible_href?
  href = attrs.href
  return false if href.nil? || href.empty?

  Tags::SKIP_HREF_PREFIXES.none? { |prefix| href.start_with?(prefix) }
end

#find(&predicate) ⇒ Node?

Returns:



110
111
112
# File 'lib/html2rss/sst/node.rb', line 110

def find(&predicate)
  each_node.find(&predicate)
end

#find_all(&predicate) ⇒ Array<Node>

Returns:



104
105
106
# File 'lib/html2rss/sst/node.rb', line 104

def find_all(&predicate)
  each_node.select(&predicate)
end

#heading?Boolean

Returns:

  • (Boolean)


65
# File 'lib/html2rss/sst/node.rb', line 65

def heading? = Tags::HEADING_NAMES.include?(name)

#ignored_container_name?Boolean

Returns:

  • (Boolean)


73
# File 'lib/html2rss/sst/node.rb', line 73

def ignored_container_name? = Tags::IGNORED_CONTAINER_NAMES.include?(name)

#image?Boolean

Returns:

  • (Boolean)


61
# File 'lib/html2rss/sst/node.rb', line 61

def image? = name == :img

#link?Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/html2rss/sst/node.rb', line 55

def link?
  name == :a && eligible_href?
end

#text_densityFloat

Returns words per descendant link.

Returns:

  • (Float)

    words per descendant link



140
141
142
143
144
# File 'lib/html2rss/sst/node.rb', line 140

def text_density
  words = word_count
  links = descendants.count(&:link?)
  links.zero? ? words.to_f : words.to_f / links
end

#utility_landmark?Boolean

Returns:

  • (Boolean)


69
# File 'lib/html2rss/sst/node.rb', line 69

def utility_landmark? = Tags::UTILITY_LANDMARK_NAMES.include?(name)

#visible_text(separator: ' ', exclude: nil) ⇒ String?

Visible text with block newlines, excluding optional subtrees.

Parameters:

  • separator (String) (defaults to: ' ')
  • exclude (Array<Node>, nil) (defaults to: nil)

Returns:

  • (String, nil)


120
121
122
123
124
125
126
# File 'lib/html2rss/sst/node.rb', line 120

def visible_text(separator: ' ', exclude: nil)
  if exclude.nil? && separator == ' ' && (index = Index.for_node(self))
    return index.memo_visible_text(self)
  end

  Text.extract(self, separator:, exclude:)
end

#word_countInteger

Returns alphanumeric word count of visible text.

Returns:

  • (Integer)

    alphanumeric word count of visible text



130
131
132
133
134
135
136
# File 'lib/html2rss/sst/node.rb', line 130

def word_count
  if (index = Index.for_node(self))
    return index.memo_word_count(self)
  end

  visible_text.to_s.scan(/\p{Alnum}+/).size
end