class YARD::Parser::Ruby::AstNode

An AST node is characterized by a type and a list of children. It is most easily represented by the s-expression {#s} such as:

# AST for "if true; 5 end":
s(s(:if, s(:var_ref, s(:kw, "true")), s(s(:int, "5")), nil))

The node type is not considered part of the list, only its children. So +ast+ does not refer to the type, but rather the first child (or object). Items that are not AstNode objects can be part of the list, like Strings or Symbols representing names. To return only the AstNode children of the node, use {#children}.

Constants

KEYWORDS

List of all known keywords @return [Hash]

Attributes

comments[RW]
comments_hash_flag[RW]
comments_range[RW]
docstring[RW]
docstring_hash_flag[RW]
docstring_range[RW]
file[W]
full_source[W]
group[RW]

@deprecated Groups are now defined by directives @see Tags::GroupDirective

line_range[W]
parent[RW]

@return [AstNode, nil] the node's parent or nil if it is a root node.

source[RW]
source_range[W]
to_s[RW]
type[RW]

@return [Symbol] the node's unique symbolic type

Public Class Methods

new(type, arr, opts = {}) click to toggle source

Creates a new AST node

@param [Symbol] type the type of node being created @param [Array<AstNode>] arr the child nodes @param [Hash] opts any extra line options @option opts [Fixnum] :line (nil) the line the node starts on in source @option opts [String] :char (nil) the character number the node starts on

in source

@option opts [Fixnum] :listline (nil) a special key like :line but for

list nodes

@option opts [Fixnum] :listchar (nil) a special key like :char but for

list nodes

@option opts [Boolean] :token (nil) whether the node represents a token

Calls superclass method
# File lib/yard/parser/ruby/ast_node.rb, line 152
def initialize(type, arr, opts = {})
  super(arr)
  self.type = type
  self.line_range = opts[:line]
  self.source_range = opts[:char]
  @fallback_line = opts[:listline]
  @fallback_source = opts[:listchar]
  @token = true if opts[:token]
end
node_class_for(type) click to toggle source

Finds the node subclass that should be instantiated for a specific node type

@param [Symbol] type the node type to find a subclass for @return [Class] a subclass of AstNode to instantiate the node with.

# File lib/yard/parser/ruby/ast_node.rb, line 110
def self.node_class_for(type)
  case type
  when :params
    ParameterNode
  when :call, :fcall, :vcall, :command, :command_call
    MethodCallNode
  when :if, :elsif, :if_mod, :unless, :unless_mod
    ConditionalNode
  when :for, :while, :while_mod, :until, :until_mod
    LoopNode
  when :def, :defs
    MethodDefinitionNode
  when :class, :sclass
    ClassNode
  when :module
    ModuleNode
  else
    if type.to_s =~ /_ref\Z/
      ReferenceNode
    elsif type.to_s =~ /_literal\Z/
      LiteralNode
    elsif KEYWORDS.has_key?(type)
      KeywordNode
    else
      AstNode
    end
  end
end

Public Instance Methods

==(ast) click to toggle source

@return [Boolean] whether the node is equal to another by checking

the list and type

@private

Calls superclass method
# File lib/yard/parser/ruby/ast_node.rb, line 165
def ==(ast)
  super && type == ast.type
end
block?() click to toggle source

@return [Boolean] whether the node has a block

# File lib/yard/parser/ruby/ast_node.rb, line 258
def block?
  respond_to?(:block) || condition?
end
call?() click to toggle source

@return [Boolean] whether the node is a method call

# File lib/yard/parser/ruby/ast_node.rb, line 238
def call?
  false
end
children() click to toggle source

@return [Array<AstNode>] the {AstNode} children inside the node

# File lib/yard/parser/ruby/ast_node.rb, line 197
def children
  @children ||= select {|e| AstNode === e }
end
condition?() click to toggle source

@return [Boolean] whether the node is a if/elsif/else condition

# File lib/yard/parser/ruby/ast_node.rb, line 248
def condition?
  false
end
def?() click to toggle source

@return [Boolean] whether the node is a method definition

# File lib/yard/parser/ruby/ast_node.rb, line 243
def def?
  false
end
file() click to toggle source

@return [String] the filename the node was parsed from

# File lib/yard/parser/ruby/ast_node.rb, line 75
def file
  return parent.file if parent
  @file
end
first_line() click to toggle source

@return [String] the first line of source represented by the node.

# File lib/yard/parser/ruby/ast_node.rb, line 275
def first_line
  full_source.split(/\r?\n/)[line - 1].strip
end
full_source() click to toggle source

@return [String] the full source that the node was parsed from

# File lib/yard/parser/ruby/ast_node.rb, line 81
def full_source
  return parent.full_source if parent
  return @full_source if @full_source
  return IO.read(@file) if file && File.exist?(file)
end
has_line?() click to toggle source

@return [Boolean] whether the node has a {#line_range} set

# File lib/yard/parser/ruby/ast_node.rb, line 265
def has_line?
  @line_range ? true : false
end
inspect() click to toggle source

@return [String] inspects the object

# File lib/yard/parser/ruby/ast_node.rb, line 322
def inspect
  typeinfo = type && type != :list ? ':' + type.to_s + ', ' : ''
  's(' + typeinfo + map(&:inspect).join(", ") + ')'
end
jump(*node_types) click to toggle source

Searches through the node and all descendants and returns the first node with a type matching any of node_types, otherwise returns the original node (self).

@example Returns the first method definition in a block of code

ast = YARD.parse_string("if true; def x; end end").ast
ast.jump(:def)
# => s(:def, s(:ident, "x"), s(:params, nil, nil, nil, nil,
#      nil), s(s(:void_stmt, )))

@example Returns first 'def' or 'class' statement

ast = YARD.parse_string("class X; def y; end end")
ast.jump(:def, :class).first
# =>

@example If the node types are not present in the AST

ast = YARD.parse("def x; end")
ast.jump(:def)

@param [Array<Symbol>] node_types a set of node types to match @return [AstNode] the matching node, if one was found @return [self] if no node was found

# File lib/yard/parser/ruby/ast_node.rb, line 191
def jump(*node_types)
  traverse {|child| return(child) if node_types.include?(child.type) }
  self
end
kw?() click to toggle source

@return [Boolean] whether the node is a keyword

# File lib/yard/parser/ruby/ast_node.rb, line 233
def kw?
  false
end
line() click to toggle source

@return [Fixnum] the starting line number of the node

# File lib/yard/parser/ruby/ast_node.rb, line 270
def line
  line_range && line_range.first
end
line_range() click to toggle source

@return [Range] the line range in {#full_source} represented

by the node
# File lib/yard/parser/ruby/ast_node.rb, line 69
def line_range
  reset_line_info unless @line_range
  @line_range
end
literal?() click to toggle source

@return [Boolean] whether the node is a literal value

# File lib/yard/parser/ruby/ast_node.rb, line 228
def literal?
  false
end
loop?() click to toggle source

@return [Boolean] whether the node is a loop

# File lib/yard/parser/ruby/ast_node.rb, line 253
def loop?
  false
end
pretty_print(q) click to toggle source

@return [nil] pretty prints the node

# File lib/yard/parser/ruby/ast_node.rb, line 287
def pretty_print(q)
  objs = self.dup + [:__last__]
  objs.unshift(type) if type && type != :list

  options = []
  if @docstring
    options << ['docstring', docstring]
  end
  if @source_range || @line_range
    options << ['line', line_range]
    options << ['source', source_range]
  end
  objs.pop if options.size == 0

  q.group(3, 's(', ')') do
    q.seplist(objs, nil, :each) do |v|
      if v == :__last__
        q.seplist(options, nil, :each) do |arr|
          k, v2 = *arr
          q.group(3) do
            q.text k
            q.group(3) do
              q.text ': '
              q.pp v2
            end
          end
        end
      else
        q.pp v
      end
    end
  end
end
ref?() click to toggle source

@return [Boolean] whether the node is a reference (variable,

constant name)
# File lib/yard/parser/ruby/ast_node.rb, line 223
def ref?
  false
end
show() click to toggle source

@return [String] the first line of source the node represents

# File lib/yard/parser/ruby/ast_node.rb, line 282
def show
  "\t#{line}: #{first_line}"
end
source_range() click to toggle source

@return [Range] the character range in {#full_source} represented

by the node
# File lib/yard/parser/ruby/ast_node.rb, line 62
def source_range
  reset_line_info unless @source_range
  @source_range
end
token?() click to toggle source

@return [Boolean] whether the node is a token

# File lib/yard/parser/ruby/ast_node.rb, line 217
def token?
  @token
end
traverse() { |node| ... } click to toggle source

Traverses the object and yields each node (including descendants) in order.

@yield each descendant node in order @yieldparam [AstNode] self, or a child/descendant node @return [void]

# File lib/yard/parser/ruby/ast_node.rb, line 206
def traverse
  nodes = [self]
  nodes.each.with_index do |node, index|
    yield node
    nodes.insert index+1, *node.children
  end
end
unfreeze() click to toggle source

Resets node state in tree

# File lib/yard/parser/ruby/ast_node.rb, line 330
def unfreeze
  @children = nil
end

Private Instance Methods

reset_line_info() click to toggle source

Resets line information @return [void]

# File lib/yard/parser/ruby/ast_node.rb, line 340
def reset_line_info
  if size == 0
    self.line_range = @fallback_line
    self.source_range = @fallback_source
  elsif children.size > 0
    f, l = children.first, children.last
    self.line_range = Range.new(f.line_range.first, l.line_range.last)
    self.source_range = Range.new(f.source_range.first, l.source_range.last)
  elsif @fallback_line || @fallback_source
    self.line_range = @fallback_line
    self.source_range = @fallback_source
  else
    self.line_range = 0...0
    self.source_range = 0...0
  end
end