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



109
110
111
112
# File 'lib/infoboxer/navigation/lookup.rb', line 109

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

#_lookup_children(selector) ⇒ Object

Underscored version of #lookup_children



115
116
117
# File 'lib/infoboxer/navigation/lookup.rb', line 115

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

#_lookup_next_siblings(selector) ⇒ Object

Underscored version of #lookup_next_siblings



147
148
149
# File 'lib/infoboxer/navigation/lookup.rb', line 147

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

#_lookup_parents(selector) ⇒ Object

Underscored version of #lookup_parents



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

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



142
143
144
# File 'lib/infoboxer/navigation/lookup.rb', line 142

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

#_lookup_prev_siblings(selector) ⇒ Object

Underscored version of #lookup_prev_siblings



137
138
139
# File 'lib/infoboxer/navigation/lookup.rb', line 137

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

#_lookup_siblings(selector) ⇒ Object

Underscored version of #lookup_siblings



132
133
134
# File 'lib/infoboxer/navigation/lookup.rb', line 132

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

#_matches?(selector) ⇒ Boolean

Underscored version of #matches?

Returns:

  • (Boolean)


104
105
106
# File 'lib/infoboxer/navigation/lookup.rb', line 104

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 78

#lookup_children(*selectors, &block) ⇒ Object

Selects nodes only from this node's direct children.



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

#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 91

#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 84

#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 99

#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 95

#lookup_siblings(*selectors, &block) ⇒ Object

Selects matching nodes from current node's siblings.



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

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

Checks if current node matches selectors.



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

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

Checks if node has any parent matching selectors.

Returns:

  • (Boolean)


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

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