Class: TreeStand::Visitor

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/tree_stand/visitor.rb

Overview

Depth-first traversal through the tree, calling hooks at each stop.

Hooks are language dependent and are defined by creating methods on the visitor with the form ‘on_*` or `around_*`, where `*` is Node#type.

  • Hooks prefixed with ‘on_*` are called before visiting a node.

  • Hooks prefixed with ‘around_*` must `yield` to continue visiting child nodes.

You can also define default hooks by implementing an #on or #around method to call when visiting each node.

Examples:

Create a visitor counting certain nodes

class CountingVisitor < TreeStand::Visitor
  attr_reader :count

  def initialize(root, type:)
    super(root)
    @type = type
    @count = 0
  end

  def on_predicate(node)
    # if this node matches our search, increment the counter
    @count += 1 if node.type == @type
  end
end

# Initialize a visitor
visitor = CountingVisitor.new(document, :predicate).visit
# Check the result
visitor.count
# => 3

A visitor using around hooks to contruct a tree

class TreeBuilder < TreeStand::Visitor
  TreeNode = Struct.new(:name, :children)

  attr_reader :stack

  def initialize(root)
    super(root)
    @stack = []
  end

  def around(node)
    @stack << TreeNode.new(node.type, [])

    # visit all children of this node
    yield

    # The last node on the stack is the root of the tree.
    return if @stack.size == 1

    # Pop the last node off the stack and add it to the parent
    @stack[-2].children << @stack.pop
  end
end

Direct Known Subclasses

TreeStand::Visitors::TreeWalker

Instance Method Summary collapse

Constructor Details

#initialize(node) ⇒ void

Parameters:



67
68
69
# File 'lib/tree_stand/visitor.rb', line 67

def initialize(node)
  @node = node
end

Instance Method Details

#around(node, &block) ⇒ void

This method is abstract.

The default implementation yields to visit all children.

This method returns an undefined value.

Examples:

Use around hooks to run logic before & after visiting a node. Pairs will with a stack.

def around(node)
  @stack << TreeNode.new(node.type, [])

  # visit all children of this node
  yield

  # The last node on the stack is the root of the tree.
  return if @stack.size == 1

  # Pop the last node off the stack and add it to the parent
  @stack[-2].children << @stack.pop
end

Parameters:



105
# File 'lib/tree_stand/visitor.rb', line 105

def around(node, &block) = yield

#on(node) ⇒ void

This method is abstract.

The default implementation does nothing.

This method returns an undefined value.

Examples:

Create callback to count all nodes in a tree.

def on(node)
  @count += 1
end

Parameters:



87
# File 'lib/tree_stand/visitor.rb', line 87

def on(node) = nil

#visitT.self_type

Run the visitor on the document and return self. Allows chaining create and visit.

Examples:

visitor = CountingVisitor.new(node, :predicate).visit

Returns:

  • (T.self_type)


75
76
77
78
# File 'lib/tree_stand/visitor.rb', line 75

def visit
  visit_node(@node)
  self
end