Class: Dommy::TreeWalker

Inherits:
Object
  • Object
show all
Includes:
TreeTraversalCore
Defined in:
lib/dommy/tree_walker.rb

Overview

TreeWalker — stateful traversal with ‘next_node` / `previous_node` / `parent_node` / `first_child` / `last_child` / `next_sibling` / `previous_sibling` and a mutable `current_node` cursor.

Wraps Nokogiri descent; doesn’t snapshot the tree, so mutations during traversal are visible (matches DOM spec).

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from TreeTraversalCore

#__accept__

Constructor Details

#initialize(root, what_to_show = NodeFilter::SHOW_ALL, filter = nil) ⇒ TreeWalker

Returns a new instance of TreeWalker.



85
86
87
88
89
90
# File 'lib/dommy/tree_walker.rb', line 85

def initialize(root, what_to_show = NodeFilter::SHOW_ALL, filter = nil)
  @root = root
  @what_to_show = what_to_show.to_i
  @filter = filter
  @current_node = root
end

Instance Attribute Details

#current_nodeObject

Returns the value of attribute current_node.



83
84
85
# File 'lib/dommy/tree_walker.rb', line 83

def current_node
  @current_node
end

#filterObject (readonly)

Returns the value of attribute filter.



82
83
84
# File 'lib/dommy/tree_walker.rb', line 82

def filter
  @filter
end

#rootObject (readonly)

Returns the value of attribute root.



82
83
84
# File 'lib/dommy/tree_walker.rb', line 82

def root
  @root
end

#what_to_showObject (readonly)

Returns the value of attribute what_to_show.



82
83
84
# File 'lib/dommy/tree_walker.rb', line 82

def what_to_show
  @what_to_show
end

Instance Method Details

#__js_call__(method, _args) ⇒ Object



171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/dommy/tree_walker.rb', line 171

def __js_call__(method, _args)
  case method
  when "nextNode"
    next_node
  when "previousNode"
    previous_node
  when "parentNode"
    parent_node
  when "firstChild"
    first_child
  when "lastChild"
    last_child
  when "nextSibling"
    next_sibling
  when "previousSibling"
    previous_sibling
  end
end

#__js_get__(key) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/dommy/tree_walker.rb', line 153

def __js_get__(key)
  case key
  when "root"
    @root
  when "whatToShow"
    @what_to_show
  when "filter"
    @filter
  when "currentNode"
    @current_node
  end
end

#__js_set__(key, value) ⇒ Object



166
167
168
169
# File 'lib/dommy/tree_walker.rb', line 166

def __js_set__(key, value)
  @current_node = value if key == "currentNode"
  nil
end

#first_childObject



135
136
137
138
# File 'lib/dommy/tree_walker.rb', line 135

def first_child
  first = first_wrapped_child(@current_node)
  walk_siblings(first, :next_sibling_wrapped)
end

#last_childObject



140
141
142
143
# File 'lib/dommy/tree_walker.rb', line 140

def last_child
  last = last_wrapped_child(@current_node)
  walk_siblings(last, :previous_sibling_wrapped)
end

#next_nodeObject



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/dommy/tree_walker.rb', line 92

def next_node
  node = first_descendant_or_following(@current_node)
  while node
    verdict = __accept__(node)
    if verdict == NodeFilter::FILTER_ACCEPT
      @current_node = node
      return node
    end

    node = (verdict == NodeFilter::FILTER_REJECT) ? following_skip_subtree(node) : first_descendant_or_following(
      node
    )
  end

  nil
end

#next_siblingObject



145
146
147
# File 'lib/dommy/tree_walker.rb', line 145

def next_sibling
  walk_siblings(next_sibling_wrapped(@current_node), :next_sibling_wrapped)
end

#parent_nodeObject



124
125
126
127
128
129
130
131
132
133
# File 'lib/dommy/tree_walker.rb', line 124

def parent_node
  node = wrapped_parent(@current_node)
  while node && reachable_from_root?(node)
    return @current_node = node if __accept__(node) == NodeFilter::FILTER_ACCEPT

    node = wrapped_parent(node)
  end

  nil
end

#previous_nodeObject



109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/dommy/tree_walker.rb', line 109

def previous_node
  node = preceding(@current_node)
  while node && node != @root
    verdict = __accept__(node)
    if verdict == NodeFilter::FILTER_ACCEPT
      @current_node = node
      return node
    end

    node = preceding(node)
  end

  nil
end

#previous_siblingObject



149
150
151
# File 'lib/dommy/tree_walker.rb', line 149

def previous_sibling
  walk_siblings(previous_sibling_wrapped(@current_node), :previous_sibling_wrapped)
end