Module: Infoboxer::Navigation::Lookup::Node

Included in:
Tree::Node
Defined in:
lib/infoboxer/navigation/lookup.rb

Overview

Lookup::Node module provides methods for navigating through page tree in XPath-like manner.

What you need to know about it:

Selectors

Each lookup_* method (and others similar) receive list of selectors. Examples of acceptable selectors:

# 1. Node class:
document.lookup(Bold) # all Bolds

# 2. Class symbol
document.lookup(:Bold)
# same as above, useful if you don't want to include Infoboxer::Tree
# in all of your code or write things like lookup(Infoboxer::Tree::Bold)

# 3. Getter/pattern:
document.lookup(text: /something/)
# finds all nodes where result of getter matches pattern

# Checks against patterns are performed with `===`, so you can
# use regexps to find by text, or ranges to find by number, like
document.lookup(:Heading, level: (3..4))

# Nodes where method is not defined are ignored, so you can
# rewrite above example as just
document.lookup(level: 3..4)
# ...and receive meaningful result without any NoMethodError

# 4. Check symbol
document.lookup(:bold?)
# finds all nodes for which `:bold?` is defined and returns
# truthy value;

# 5. Code block
document.lookup{|node| node.params.has_key?(:class)}

You also can use any of those method without any selector, thus receiving ALL parents, ALL children, ALL siblings and so on.

Chainable navigation

Each lookup_* method returns an instance of Tree::Nodes class, which behaves like an Array, but also defines similar set of lookup_* methods, so, you can brainlessly do the things like

document.
  lookup(:Paragraph){|p| p.text.length > 100}.
  lookup(:Wikilink, text: /^List of/).
  select(&:bold?)

Underscored methods

For all methods of this module you can notice "underscored" version (lookup_children vs _lookup_children and so on). Basically, underscored versions accept instance of Selector, which is already preprocessed version of all selectors. It is kinda internal thing, though can be useful if you store selectors in variables -- it is easier to have and use just one instance of Selector, than list of arguments and blocks.

Instance Method Summary collapse

Instance Method Details

#_lookup(selector) ⇒ Object

Underscored version of #lookup



111
112
113
114
# File 'lib/infoboxer/navigation/lookup.rb', line 111

def _lookup(selector)
  Tree::Nodes[_matches?(selector) ? self : nil, *children._lookup(selector)]
    .flatten.compact
end

#_lookup_children(selector) ⇒ Object

Underscored version of #lookup_children



117
118
119
# File 'lib/infoboxer/navigation/lookup.rb', line 117

def _lookup_children(selector)
  @children._find(selector)
end

#_lookup_next_siblings(selector) ⇒ Object

Underscored version of #lookup_next_siblings



149
150
151
# File 'lib/infoboxer/navigation/lookup.rb', line 149

def _lookup_next_siblings(selector)
  next_siblings._find(selector)
end

#_lookup_parents(selector) ⇒ Object

Underscored version of #lookup_parents



122
123
124
125
126
127
128
129
130
131
# File 'lib/infoboxer/navigation/lookup.rb', line 122

def _lookup_parents(selector)
  case
  when !parent
    Tree::Nodes[]
  when parent._matches?(selector)
    Tree::Nodes[parent, *parent._lookup_parents(selector)]
  else
    parent._lookup_parents(selector)
  end
end

#_lookup_prev_sibling(selector) ⇒ Object

Underscored version of #lookup_prev_sibling



144
145
146
# File 'lib/infoboxer/navigation/lookup.rb', line 144

def _lookup_prev_sibling(selector)
  prev_siblings.reverse.detect { |n| selector === n }
end

#_lookup_prev_siblings(selector) ⇒ Object

Underscored version of #lookup_prev_siblings



139
140
141
# File 'lib/infoboxer/navigation/lookup.rb', line 139

def _lookup_prev_siblings(selector)
  prev_siblings._find(selector)
end

#_lookup_siblings(selector) ⇒ Object

Underscored version of #lookup_siblings



134
135
136
# File 'lib/infoboxer/navigation/lookup.rb', line 134

def _lookup_siblings(selector)
  siblings._find(selector)
end

#_matches?(selector) ⇒ Boolean

Underscored version of #matches?

Returns:

  • (Boolean)


106
107
108
# File 'lib/infoboxer/navigation/lookup.rb', line 106

def _matches?(selector)
  selector === self
end

#lookup(*selectors, &block) ⇒ Object

Selects matching nodes from entire subtree inside current node.



# File 'lib/infoboxer/navigation/lookup.rb', line 80

#lookup_children(*selectors, &block) ⇒ Object

Selects nodes only from this node's direct children.



# File 'lib/infoboxer/navigation/lookup.rb', line 83

#lookup_next_siblings(*selectors, &block) ⇒ Object

Selects matching nodes from current node's siblings, which are below current node in parents children list.



# File 'lib/infoboxer/navigation/lookup.rb', line 93

#lookup_parents(*selectors, &block) ⇒ Object

Selects matching nodes of this node's parents chain, up to entire Document.



# File 'lib/infoboxer/navigation/lookup.rb', line 86

#lookup_prev_sibling(*selectors, &block) ⇒ Object

Selects first matching nodes from current node's siblings, which are above current node in parents children list.



# File 'lib/infoboxer/navigation/lookup.rb', line 101

#lookup_prev_siblings(*selectors, &block) ⇒ Object

Selects matching nodes from current node's siblings, which are above current node in parents children list.



# File 'lib/infoboxer/navigation/lookup.rb', line 97

#lookup_siblings(*selectors, &block) ⇒ Object

Selects matching nodes from current node's siblings.



# File 'lib/infoboxer/navigation/lookup.rb', line 90

#matches?(*selectors, &block) ⇒ Object

Checks if current node matches selectors.



# File 'lib/infoboxer/navigation/lookup.rb', line 77

#parent?(*selectors, &block) ⇒ Boolean

Checks if node has any parent matching selectors.

Returns:

  • (Boolean)


168
169
170
# File 'lib/infoboxer/navigation/lookup.rb', line 168

def parent?(*selectors, &block)
  !lookup_parents(*selectors, &block).empty?
end