class GraphQL::Language::Visitor

# => 3
visitor.count
# Check the result
visitor.visit
# Run it
visitor = NameCounter.new(document, “name”)
# Initialize a visitor
end
end
super
# Continue visiting subfields:
end
@count += 1
if node.name == @field_name
# if this field matches our search, increment the counter
def on_field(node, parent)
attr_reader :count
end
@count = 0
@field_name = field_name
super(document)
def initialize(document, field_name)
class NameCounter < GraphQL::Language::Visitor
@example Create a visitor counting certain field names
Depth-first traversal through the tree, calling hooks at each stop.

def self.apply_hooks(hooks, node, parent)

If one of the visitors returns SKIP, stop visiting this node
def self.apply_hooks(hooks, node, parent)
  hooks.each do |proc|
    return false if proc.call(node, parent) == SKIP
  end
  true
end

def self.make_visit_method(node_method)

We don't use `alias` here because it breaks `super`
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

def [](node_class)

Deprecated:
  • see `on_` methods, like {#on_field}

Other tags:
    Example: Run a hook whenever you enter a new Field -

Returns:
  • (NodeVisitor) -

Parameters:
  • node_class (Class) -- The node class that you want to listen to
def [](node_class)
  @visitors[node_class] ||= NodeVisitor.new
end

def begin_visit(node, parent)

def begin_visit(node, parent)
  node_visitor = self[node.class]
  self.class.apply_hooks(node_visitor.enter, node, parent)
end

def end_visit(node, parent)

Should global `leave` visitors come first or last?
def end_visit(node, parent)
  node_visitor = self[node.class]
  self.class.apply_hooks(node_visitor.leave, node, parent)
end

def initialize(document)

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

def on_abstract_node(node, parent)

Returns:
  • (Array, nil) - If there were modifications, it returns an array of new nodes, otherwise, it returns `nil`.

Parameters:
  • parent (GraphQL::Language::Nodes::AbstractNode, nil) -- the previously-visited node, or `nil` if this is the root node.
  • node (GraphQL::Language::Nodes::AbstractNode) -- the node being visited
def on_abstract_node(node, parent)
  if node.equal?(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

def on_node_with_modifications(node, parent)

said value
If a non-array value is returned, consuming functions should ignore
then return the copies
copy `parent` so that it contains the copy of that node as a child,
Run the hooks for `node`, and if the hooks return a copy of `node`,
def on_node_with_modifications(node, parent)
  new_node_and_new_parent = visit_node(node, parent)
  if new_node_and_new_parent.is_a?(Array)
    new_node = new_node_and_new_parent[0]
    new_parent = new_node_and_new_parent[1]
    if new_node.is_a?(Nodes::AbstractNode) && !node.equal?(new_node)
      # The user-provided hook returned a new node.
      new_parent = new_parent && new_parent.replace_child(node, new_node)
      return new_node, new_parent
    elsif new_node.equal?(DELETE_NODE)
      # The user-provided hook requested to remove this node
      new_parent = new_parent && new_parent.delete_child(node)
      return nil, new_parent
    elsif new_node_and_new_parent.none? { |n| n == nil || n.class < Nodes::AbstractNode }
      # The user-provided hook returned an array of who-knows-what
      # return nil here to signify that no changes should be made
      nil
    else
      new_node_and_new_parent
    end
  else
    # The user-provided hook didn't make any modifications.
    # In fact, the hook might have returned who-knows-what, so
    # ignore the return value and use the original values.
    new_node_and_new_parent
  end
end

def visit

Returns:
  • (void) -
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

def visit_node(node, parent)

Call the user-defined handler for `node`.
def visit_node(node, parent)
  public_send(node.visit_method, node, parent)
end