123456789_123456789_123456789_123456789_123456789_

Class: YARD::Parser::Ruby::AstNode

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, ::Array
Instance Chain:
self, ::Array
Inherits: Array
  • Object
Defined in: lib/yard/parser/ruby/ast_node.rb

Overview

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[0] 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.

Constant Summary

  • KEYWORDS =

    List of all known keywords

    Returns:

    # File 'lib/yard/parser/ruby/ast_node.rb', line 96
    {:class => true, :alias => true, :lambda => true, :do_block => true,
    :def => true, :defs => true, :begin => true, :rescue => true, :rescue_mod => true,
    :if => true, :if_mod => true, :else => true, :elsif => true, :case => true,
    :when => true, :next => true, :break => true, :retry => true, :redo => true,
    :return => true, :throw => true, :catch => true, :until => true, :until_mod => true,
    :while => true, :while_mod => true, :yield => true, :yield0 => true, :zsuper => true,
    :unless => true, :unless_mod => true, :for => true, :super => true, :return0 => true}

Creating an AstNode

Traversing a Node

Node Meta Types

Getting Line Information

Printing a Node

Managing node state

Instance Attribute Summary

Instance Method Summary

::Array - Inherited

#place

Places values before or after another object (by value) in an array.

Constructor Details

.new(type, arr, opts = {}) ⇒ AstNode

Creates a new AST node

Parameters:

  • type (Symbol)

    the type of node being created

  • arr (Array<AstNode>)

    the child nodes

  • opts (Hash) (defaults to: {})

    any extra line options

Options Hash (opts):

  • :line (Fixnum) — default: nil

    the line the node starts on in source

  • :char (String) — default: nil

    the character number the node starts on in source

  • :listline (Fixnum) — default: nil

    a special key like :line but for list nodes

  • :listchar (Fixnum) — default: nil

    a special key like :char but for list nodes

  • :token (Boolean) — default: nil

    whether the node represents a token

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 153

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]
  @docstring = nil
end

Class Method Details

.node_class_for(type) ⇒ Class

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

Parameters:

  • type (Symbol)

    the node type to find a subclass for

Returns:

  • (Class)

    a subclass of AstNode to instantiate the node with.

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 111

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.key?(type)
      KeywordNode
    else
      AstNode
    end
  end
end

Instance Attribute Details

#block?Boolean (readonly)

Returns:

  • (Boolean)

    whether the node has a block

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 261

def block?
  respond_to?(:block) || condition?
end

#call?Boolean (readonly)

Returns:

  • (Boolean)

    whether the node is a method call

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 241

def call?
  false
end

#comments (readonly)

Alias for #docstring.

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 50

alias comments docstring

#comments_hash_flag (readonly)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 52

alias comments_hash_flag docstring_hash_flag

#comments_range (readonly)

Alias for #docstring_range.

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 51

alias comments_range docstring_range

#condition?Boolean (readonly)

Returns:

  • (Boolean)

    whether the node is a if/elsif/else condition

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 251

def condition?
  false
end

#def?Boolean (readonly)

Returns:

  • (Boolean)

    whether the node is a method definition

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 246

def def?
  false
end

#docstring (rw) Also known as: #comments

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 43

attr_accessor :docstring, :docstring_range, :source

#docstring_hash_flag (rw) Also known as: #comments_hash_flag

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 42

attr_accessor :docstring_hash_flag

#docstring_range (rw) Also known as: #comments_range

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 43

attr_accessor :docstring, :docstring_range, :source

#fileString (rw)

Returns:

  • (String)

    the filename the node was parsed from

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 76

def file
  return parent.file if parent
  @file
end

#file=(value) (rw)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 49

attr_writer :source_range, :line_range, :file, :full_source

#full_sourceString (rw)

Returns:

  • (String)

    the full source that the node was parsed from

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 82

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

#full_source=(value) (rw)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 49

attr_writer :source_range, :line_range, :file, :full_source

#group (rw)

Deprecated.

Groups are now defined by directives

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 47

attr_accessor :group

#has_line?Boolean (readonly)

Returns:

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 268

def has_line?
  @line_range ? true : false
end

#kw?Boolean (readonly)

Returns:

  • (Boolean)

    whether the node is a keyword

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 236

def kw?
  false
end

#line_rangeRange (rw)

Returns:

  • (Range)

    the line range in #full_source represented by the node

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 70

def line_range
  reset_line_info unless @line_range
  @line_range
end

#line_range=(value) (rw)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 49

attr_writer :source_range, :line_range, :file, :full_source

#literal?Boolean (readonly)

Returns:

  • (Boolean)

    whether the node is a literal value

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 231

def literal?
  false
end

#loop?Boolean (readonly)

Returns:

  • (Boolean)

    whether the node is a loop

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 256

def loop?
  false
end

#parentAstNode? (rw)

Returns:

  • (AstNode, nil)

    the node's parent or nil if it is a root node.

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 59

attr_accessor :parent

#ref?Boolean (readonly)

Returns:

  • (Boolean)

    whether the node is a reference (variable, constant name)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 226

def ref?
  false
end

#sourceString (rw) Also known as: #to_s

Returns:

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 89

attr_accessor :docstring, :docstring_range, :source

#source=(value) (rw)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 43

attr_accessor :docstring, :docstring_range, :source

#source_rangeRange (rw)

Returns:

  • (Range)

    the character range in #full_source represented by the node

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 63

def source_range
  reset_line_info unless @source_range
  @source_range
end

#source_range=(value) (rw)

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 49

attr_writer :source_range, :line_range, :file, :full_source

#to_s (readonly)

Alias for #source.

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 53

alias to_s source

#token?Boolean (readonly)

Returns:

  • (Boolean)

    whether the node is a token

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 220

def token?
  @token
end

#typeSymbol (rw)

Returns:

  • (Symbol)

    the node's unique symbolic type

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 56

attr_accessor :type

Instance Method Details

#==(other) ⇒ Boolean

This method is for internal use only.

Returns:

  • (Boolean)

    whether the node is equal to another by checking the list and type

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 167

def ==(other)
  super && type == other.type
end

#childrenArray<AstNode>

Returns:

  • (Array<AstNode>)

    the AstNode children inside the node

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 199

def children
  @children ||= select {|e| AstNode === e }
end

#first_lineString

Returns:

  • (String)

    the first line of source represented by the node.

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 278

def first_line
  full_source.split(/\r?\n/)[line - 1].strip
end

#inspectString

Returns:

  • (String)

    inspects the object

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 323

def inspect
  typeinfo = type && type != :list ? ':' + type.to_s + ', ' : ''
  's(' + typeinfo + map(&:inspect).join(", ") + ')'
end

#jump(*node_types) ⇒ AstNode, self

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).

Examples:

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, )))

Returns first 'def' or 'class' statement

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

If the node types are not present in the AST

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

Parameters:

  • node_types (Array<Symbol>)

    a set of node types to match

Returns:

  • (AstNode)

    the matching node, if one was found

  • (self)

    if no node was found

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 193

def jump(*node_types)
  traverse {|child| return(child) if node_types.include?(child.type) }
  self
end

#lineFixnum

Returns:

  • (Fixnum)

    the starting line number of the node

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 273

def line
  line_range && line_range.first
end

#pretty_print(q) ⇒ nil

Returns:

  • (nil)

    pretty prints the node

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 290

def pretty_print(q)
  objs = dup + [:__last__]
  objs.unshift(type) if type && type != :list

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

  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

#reset_line_infovoid (private)

This method returns an undefined value.

Resets line information

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 341

def reset_line_info
  if size == 0
    self.line_range = @fallback_line
    self.source_range = @fallback_source
  elsif !children.empty?
    f = children.first
    l = 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

#showString

Returns:

  • (String)

    the first line of source the node represents

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 285

def show
  "\t#{line}: #{first_line}"
end

#traverse {|self,| ... } ⇒ void

This method returns an undefined value.

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

Yields:

  • each descendant node in order

Yield Parameters:

  • self, (AstNode)

    or a child/descendant node

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 208

def traverse
  nodes = [self]
  until nodes.empty?
    node = nodes.pop
    yield node
    nodes += node.children.reverse unless node.children.empty?
  end
end

#unfreeze

Resets node state in tree

[ GitHub ]

  
# File 'lib/yard/parser/ruby/ast_node.rb', line 331

def unfreeze
  @children = nil
end