class Solargraph::Arc::Walker

Public Class Methods

from_source(source) click to toggle source
# File lib/solargraph/arc/walker.rb, line 24
def self.from_source(source)
  self.new(self.normalize_ast(source))
end
new(ast) click to toggle source
# File lib/solargraph/arc/walker.rb, line 28
def initialize(ast)
  @ast   = ast
  @hooks = Hash.new([])
end
normalize_ast(source) click to toggle source

github.com/castwide/solargraph/issues/522

# File lib/solargraph/arc/walker.rb, line 14
def self.normalize_ast(source)
  ast = source.node

  if ast.is_a?(::Parser::AST::Node)
    ast
  else
    NodeParser.parse(source.code, source.filename)
  end
end

Public Instance Methods

on(node_type, args=[], &block) click to toggle source
# File lib/solargraph/arc/walker.rb, line 33
def on(node_type, args=[], &block)
  @hooks[node_type] << Hook.new(node_type, args, &block)
end
walk() click to toggle source
# File lib/solargraph/arc/walker.rb, line 37
def walk
  if @ast.is_a?(Array)
    @ast.each { |node| traverse(node) }
  else
    traverse(@ast)
  end
end

Private Instance Methods

match_children(args, children) click to toggle source
# File lib/solargraph/arc/walker.rb, line 78
def match_children(args, children)
  args.each_with_index.all? do |arg, i|
    if children[i].is_a?(::Parser::AST::Node)
      children[i].type == arg
    else
      children[i] == arg
    end
  end
end
traverse(node) click to toggle source
# File lib/solargraph/arc/walker.rb, line 47
def traverse(node)
  return unless node.is_a?(::Parser::AST::Node)

  @hooks[node.type].each do |hook|
    try_match(node, hook)
  end

  node.children.each {|child| traverse(child) }
end
try_match(node, hook) click to toggle source
# File lib/solargraph/arc/walker.rb, line 57
def try_match(node, hook)
  return unless node.type == hook.node_type
  return unless node.children

  matched = hook.args.empty? || if node.children.first.is_a?(::Parser::AST::Node)
    node.children.any? { |child| child.is_a?(::Parser::AST::Node) && match_children(hook.args[1..-1], child.children) }
  else
    match_children(hook.args, node.children)
  end

  if matched
    if hook.proc.arity == 1
      hook.proc.call(node)
    elsif hook.proc.arity == 2
      walker = Walker.new(node)
      hook.proc.call(node, walker)
      walker.walk
    end
  end
end