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
@deprecated Groups are now defined by directives @see Tags::GroupDirective
@return [AstNode, nil] the node's parent or nil if it is a root node.
@return [Symbol] the node's unique symbolic type
Public Class Methods
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
# 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
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 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
Public Instance Methods
@return [Boolean] whether the node is equal to another by checking
the list and type
@private
# File lib/yard/parser/ruby/ast_node.rb, line 167 def ==(other) super && type == other.type end
@return [Boolean] whether the node has a block
# File lib/yard/parser/ruby/ast_node.rb, line 260 def block? respond_to?(:block) || condition? end
@return [Boolean] whether the node is a method call
# File lib/yard/parser/ruby/ast_node.rb, line 240 def call? false end
@return [Array<AstNode>] the {AstNode} children inside the node
# File lib/yard/parser/ruby/ast_node.rb, line 199 def children @children ||= select {|e| AstNode === e } end
@return [Boolean] whether the node is a if/elsif/else condition
# File lib/yard/parser/ruby/ast_node.rb, line 250 def condition? false end
@return [Boolean] whether the node is a method definition
# File lib/yard/parser/ruby/ast_node.rb, line 245 def def? false end
@return [String] the filename the node was parsed from
# File lib/yard/parser/ruby/ast_node.rb, line 76 def file return parent.file if parent @file end
@return [String] the first line of source represented by the node.
# File lib/yard/parser/ruby/ast_node.rb, line 277 def first_line full_source.split(/\r?\n/)[line - 1].strip end
@return [String] the full source that the node was parsed from
# 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
@return [Boolean] whether the node has a {#line_range} set
# File lib/yard/parser/ruby/ast_node.rb, line 267 def has_line? @line_range ? true : false end
@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
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 193 def jump(*node_types) traverse {|child| return(child) if node_types.include?(child.type) } self end
@return [Boolean] whether the node is a keyword
# File lib/yard/parser/ruby/ast_node.rb, line 235 def kw? false end
@return [Fixnum] the starting line number of the node
# File lib/yard/parser/ruby/ast_node.rb, line 272 def line line_range && line_range.first end
@return [Range] the line range in {#full_source} represented
by the node
# File lib/yard/parser/ruby/ast_node.rb, line 70 def line_range reset_line_info unless @line_range @line_range end
@return [Boolean] whether the node is a literal value
# File lib/yard/parser/ruby/ast_node.rb, line 230 def literal? false end
@return [Boolean] whether the node is a loop
# File lib/yard/parser/ruby/ast_node.rb, line 255 def loop? false end
@return [nil] pretty prints the node
# File lib/yard/parser/ruby/ast_node.rb, line 289 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
@return [Boolean] whether the node is a reference (variable,
constant name)
# File lib/yard/parser/ruby/ast_node.rb, line 225 def ref? false end
@return [String] the first line of source the node represents
# File lib/yard/parser/ruby/ast_node.rb, line 284 def show "\t#{line}: #{first_line}" end
@return [Range] the character range in {#full_source} represented
by the node
# File lib/yard/parser/ruby/ast_node.rb, line 63 def source_range reset_line_info unless @source_range @source_range end
@return [Boolean] whether the node is a token
# File lib/yard/parser/ruby/ast_node.rb, line 219 def token? @token end
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 208 def traverse nodes = [self] nodes.each.with_index do |node, index| yield node nodes.insert index + 1, *node.children end end
Resets node state in tree
# File lib/yard/parser/ruby/ast_node.rb, line 330 def unfreeze @children = nil end
Private Instance Methods
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.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