Class: GraphQL::Language::Visitor

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/language/visitor.rb

Overview

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

Examples:

Create a visitor counting certain field names

class NameCounter < GraphQL::Language::Visitor
  def initialize(document, field_name)
    super(document)
    @field_name = field_name
    @count = 0
  end

  attr_reader :count

  def on_field(node, parent)
    # if this field matches our search, increment the counter
    if node.name == @field_name
      @count += 1
    end
    # Continue visiting subfields:
    super
  end
end

# Initialize a visitor
visitor = NameCounter.new(document, "name")
# Run it
visitor.visit
# Check the result
visitor.count
# => 3

Defined Under Namespace

Classes: DeleteNode, NodeVisitor

Constant Summary collapse

SKIP =
Deprecated.

Use super to continue the visit; or don’t call it to halt.

If any hook returns this value, the GraphQL::Language::Visitor stops visiting this node right away

:_skip
DELETE_NODE =

When this is returned from a visitor method, Then the node passed into the method is removed from parent’s children.

DeleteNode.new

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(document) ⇒ Visitor

Returns a new instance of Visitor

[View source]

45
46
47
48
49
# File 'lib/graphql/language/visitor.rb', line 45

def initialize(document)
  @document = document
  @visitors = {}
  @result = nil
end

Instance Attribute Details

#resultGraphQL::Language::Nodes::Document (readonly)

Returns The document with any modifications applied

Returns:


52
53
54
# File 'lib/graphql/language/visitor.rb', line 52

def result
  @result
end

Class Method Details

.make_visit_method(node_method) ⇒ Object

We don’t use alias here because it breaks super

[View source]

120
121
122
123
124
125
126
127
128
# File 'lib/graphql/language/visitor.rb', line 120

def self.make_visit_method(node_method)
  class_eval(<<-RUBY, __FILE__, __LINE__ + 1)
    def #{node_method}(node, parent)
      child_mod = on_abstract_node(node, parent)
      # If visiting the children returned changes, continue passing those.
      child_mod || [node, parent]
    end
  RUBY
end

Instance Method Details

#[](node_class) ⇒ NodeVisitor

Deprecated.

see on_ methods, like #on_field

Get a NodeVisitor for node_class

Examples:

Run a hook whenever you enter a new Field

visitor[GraphQL::Language::Nodes::Field] << ->(node, parent) { p "Here's a field" }

Parameters:

  • node_class (Class)

    The node class that you want to listen to

Returns:

[View source]

61
62
63
# File 'lib/graphql/language/visitor.rb', line 61

def [](node_class)
  @visitors[node_class] ||= NodeVisitor.new
end

#on_abstract_node(node, parent) ⇒ Array?

The default implementation for visiting an AST node. It doesn’t do anything, but it continues to visiting the node’s children. To customize this hook, override one of its make_visit_methodes (or the base method?) in your subclasses.

For compatibility, it calls hook procs, too.

Parameters:

Returns:

  • (Array, nil)

    If there were modifications, it returns an array of new nodes, otherwise, it returns nil.

[View source]

91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/graphql/language/visitor.rb', line 91

def on_abstract_node(node, parent)
  if node == DELETE_NODE
    # This might be passed to `super(DELETE_NODE, ...)`
    # by a user hook, don't want to keep visiting in that case.
    nil
  else
    # Run hooks if there are any
    new_node = node
    no_hooks = !@visitors.key?(node.class)
    if no_hooks || begin_visit(new_node, parent)
      node.children.each do |child_node|
        new_child_and_node = on_node_with_modifications(child_node, new_node)
        # Reassign `node` in case the child hook makes a modification
        if new_child_and_node.is_a?(Array)
          new_node = new_child_and_node[1]
        end
      end
    end
    end_visit(new_node, parent) unless no_hooks

    if new_node.equal?(node)
      nil
    else
      [new_node, parent]
    end
  end
end

#visitvoid

This method returns an undefined value.

Visit document and all children, applying hooks as you go

[View source]

67
68
69
70
71
72
73
74
75
# File 'lib/graphql/language/visitor.rb', line 67

def visit
  result = on_node_with_modifications(@document, nil)
  @result = if result.is_a?(Array)
    result.first
  else
    # The node wasn't modified
    @document
  end
end

#visit_node(node, parent) ⇒ Object

Call the user-defined handler for node.

[View source]

78
79
80
# File 'lib/graphql/language/visitor.rb', line 78

def visit_node(node, parent)
  public_send(node.visit_method, node, parent)
end