class DeepCover::Node

Base class to handle covered nodes.

Constants

CLASSES

Reopened in base

Complex
Cvasgn
Dsym
Erange
Float
Int
Ivar
Kwarg
Kwoptarg
Kwrestarg
OrAsgn
Rational
Sym
True
Zsuper

Attributes

base_node[R]
children[R]
index[R]
next_sibling[RW]
parent[R]
previous_sibling[RW]

Public Class Methods

[](source) click to toggle source

Shortcut to create a node from source code

# File lib/deep_cover/node/base.rb, line 72
def self.[](source)
  CoveredCode.new(source: source).execute_code.covered_ast
end
atom(type) click to toggle source

Atoms

# File lib/deep_cover/node/literals.rb, line 26
def self.atom(type)
  ::Class.new(StaticLiteral) do
    has_child value: type
  end
end
define_module_class() { || ... } click to toggle source
# File lib/deep_cover/node/module.rb, line 24
def self.define_module_class
  check_completion
  has_tracker :body_entry
  yield
  has_child body: Node,
            can_be_empty: -> { base_node.loc.end.begin },
            rewrite: '%{body_entry_tracker};%{node}',
            is_statement: true,
            flow_entry_count: :body_entry_tracker_hits
  executed_loc_keys :keyword

  class_eval do
    def execution_count # Overrides ExecutedAfterChildren
      body_entry_tracker_hits
    end
  end
end
has_evaluated_segments() click to toggle source

Dynamic

# File lib/deep_cover/node/literals.rb, line 74
def self.has_evaluated_segments
  has_extra_children constituents: [Str, Begin, Ivar, Cvar, Gvar, Dstr, NthRef]
end
inherited(parent) click to toggle source
Calls superclass method
# File lib/deep_cover/node.rb, line 10
def self.inherited(parent)
  CLASSES << parent
  super
end
new(base_node, parent:, index: 0, base_children: base_node.children) click to toggle source
Calls superclass method DeepCover::Node::Mixin::HasChild::new
# File lib/deep_cover/node/base.rb, line 22
def initialize(base_node, parent:, index: 0, base_children: base_node.children)
  @base_node = base_node
  @parent = parent
  @index = index
  @children = []
  begin
    @children = augment_children(base_children)
    initialize_siblings
    super()
  rescue StandardError => e
    diagnose(e)
  end
end

Public Instance Methods

[](lookup) click to toggle source

Shortcut to access children

# File lib/deep_cover/node/base.rb, line 55
def [](lookup)
  if lookup.is_a?(Integer)
    children.fetch(lookup)
  else
    found = find_all(lookup)
    case found.size
    when 1
      found.first
    when 0
      raise "No children of type #{lookup}"
    else
      raise "Ambiguous lookup #{lookup}, found #{found}."
    end
  end
end
children_nodes() click to toggle source
# File lib/deep_cover/node/base.rb, line 76
def children_nodes
  children.select { |c| c.is_a? Node }
end
Also aliased as: children_nodes_in_flow_order
children_nodes_in_flow_order()
Alias for: children_nodes
covered_code() click to toggle source

Internal API

# File lib/deep_cover/node/base.rb, line 112
def covered_code
  parent.covered_code
end
each_node() { |self| ... } click to toggle source

Yields its children and itself

# File lib/deep_cover/node/base.rb, line 122
def each_node(&block)
  return to_enum :each_node unless block_given?
  children_nodes.each do |child|
    child.each_node(&block)
  end
  yield self
  self
end
execution_count() click to toggle source
# File lib/deep_cover/node/module.rb, line 36
def execution_count # Overrides ExecutedAfterChildren
  body_entry_tracker_hits
end
fancy_type() click to toggle source
# File lib/deep_cover/node/base.rb, line 131
def fancy_type
  class_name = self.class.to_s.gsub(/^DeepCover::/, '').gsub(/^Node::/, '')
  t = type.to_s
  t.casecmp(class_name) == 0 ? t : "#{t}[#{class_name}]"
end
find_all(lookup) click to toggle source

Search self and descendants for a particular Class or type

# File lib/deep_cover/node/base.rb, line 39
def find_all(lookup)
  case lookup
  when ::Module
    each_node.grep(lookup)
  when ::Symbol
    each_node.find_all { |n| n.type == lookup }
  when ::String
    each_node.find_all { |n| n.source == lookup }
  when ::Regexp
    each_node.find_all { |n| n.source =~ lookup }
  else
    raise ::TypeError, "Expected class or symbol, got #{lookup.class}: #{lookup.inspect}"
  end
end
inspect(indent = 0)
Alias for: to_s
simple_literal?() click to toggle source
# File lib/deep_cover/node/literals.rb, line 8
def simple_literal?
  false
end
to_s(indent = 0) click to toggle source

Adapted from github.com/whitequark/ast/blob/master/lib/ast/node.rb

# File lib/deep_cover/node/base.rb, line 93
def to_s(indent = 0)
  [
    '  ' * indent,
    '(',
    fancy_type,
    *children.map do |child, idx|
      if child.is_a?(Node)
        "\n#{child.to_s(indent + 1)}"
      else
        " #{child.inspect}"
      end
    end,
    ')',
  ].join
end
Also aliased as: inspect
type() click to toggle source
# File lib/deep_cover/node/base.rb, line 116
def type
  return base_node.type if base_node
  self.class.name.split('::').last.to_sym
end

Private Instance Methods

diagnose(exception) click to toggle source
# File lib/deep_cover/node/base.rb, line 139
def diagnose(exception)
  msg = if self.class == Node
          "Unknown node type encountered: #{base_node.type}"
        else
          "Node class #{self.class} incorrectly defined"
        end
  warn [msg,
        'Attempting to continue, but this node will not be handled properly',
        ('Its subnodes will be ignored' if children.empty?),
        'Source:',
        expression,
        'Original exception:',
        exception.inspect,
  ].join("\n")
end
initialize_siblings() click to toggle source
# File lib/deep_cover/node/base.rb, line 84
def initialize_siblings
  children_nodes_in_flow_order.each_cons(2) do |child, next_child|
    child.next_sibling = next_child
    next_child.previous_sibling = child
  end
end