class TraceTree

Constants

Events
GemPaths
MainFile
VERSION

Attributes

bi[R]
build_command[R]
config[R]
log[R]
opt[R]
point_loader[R]
timer[R]
trace_points[R]

Public Class Methods

new(bi) click to toggle source
# File lib/trace_tree.rb, line 35
def initialize bi
  @bi = bi
  @trace_points = Queue.new
  @timer = Timer.new
  @config = Config.load
end
tmp() click to toggle source
# File lib/trace_tree/tmp_file.rb, line 6
def tmp
  Dir.tmpdir
end

Public Instance Methods

generate(*log, **opt, &to_do) click to toggle source
# File lib/trace_tree.rb, line 42
def generate *log, **opt, &to_do
  @opt = opt
  @log = dump_location(*log)
  @debug = debug_location
  enhance_point
  @build_command = (opt[:html] || opt[:htmp]) ? :tree_html_full : :tree_graph
  make_filter
  @__file__, @__line__, there = bi.eval('[__FILE__, __LINE__, self]')

  dry_run

  #start_trace
  timer[:trace]
  @tp = TracePoint.new(*Events, &@deal)
  @tp.enable

  there.instance_eval(&to_do)
ensure
  #stop_trace
  return unless @tp
  @tp.disable
  timer[:trace]
  dump_trace_tree
end

Private Instance Methods

debug_location() click to toggle source
# File lib/trace_tree.rb, line 78
def debug_location
  loc = opt[:debug]
  return nil unless loc
  return loc if loc.respond_to? :puts
  TmpFile.new loc, transcode: opt[:transcode]
end
dry_run() click to toggle source
# File lib/trace_tree.rb, line 71
def dry_run
  tp = TracePoint.new{}
  tp.enable
ensure
  tp.disable
end
dump_location(*log) click to toggle source
# File lib/trace_tree.rb, line 85
def dump_location *log
  return TmpFile.new(opt[:tmp], transcode: opt[:transcode]) if opt[:tmp]
  return TmpFile.new((opt[:htmp] + '.html'), transcode: opt[:transcode]) if opt[:htmp]
  log.empty? ? STDOUT : log[0]
end
dump_trace_tree() click to toggle source
# File lib/trace_tree.rb, line 104
def dump_trace_tree
  timer[:tree]
  tree = sort(trace_points_array).send build_command
  timer[:tree]
  @debug.puts table_of_points if @debug
  log.puts tree
  log.puts timer.to_s if opt[:timer]
rescue => e
  log.puts timer.to_s, e.inspect, e.backtrace
  log.puts table_of_points
end
enhance_point() click to toggle source
# File lib/trace_tree.rb, line 91
def enhance_point
  enhancement = []
  enhancement << TraceTree::Color unless opt[:color] == false
  enhancement << TraceTree::ShortGemPath unless opt[:gem] == false
  if opt[:return].nil? || opt[:return] == true
    enhancement << TraceTree::ConsoleReturnValue
  elsif opt[:return] == :lux
    enhancement << TraceTree::LuxuryReturnValue
  end
  enhancement << TraceTree::Args if opt[:args] == true
  @point_loader = Point::Loader.new(*enhancement, config)
end
make_filter() click to toggle source
# File lib/trace_tree.rb, line 122
  def make_filter
    stack_filter =
      if (@no_methods = Array(opt[:no_methods])).empty?
        nil
      else
        'return false unless outside_hidden_stack?(point)'
      end

    path_filter = nil

    if stack_filter.nil? && path_filter.nil?
      return @deal = -> point { trace_points << point_loader.create(point) }
    end

    filter_method = <<-EOM
      def wanted? point
        return false if point.end_of_trace?
        #{stack_filter}
        return true if native?(point) || point.thread_relative?
        return true if point.method_defined_by_define_method?
        #{path_filter}
        true
      end
    EOM

    self.singleton_class.class_eval filter_method

    @deal = -> point do
      po = point_loader.create(point)
      trace_points << po if wanted? po
    end
  end
native?(point) click to toggle source
# File lib/trace_tree.rb, line 183
def native? point
  MainFile == point.path ||
    (:b_call == point.event && @__file__ == point.path && @__line__ == point.lineno)
end
outside_hidden_stack?(point) click to toggle source
# File lib/trace_tree.rb, line 155
def outside_hidden_stack? point
  stack = (point.thread[:trace_tree_no_methods_stack] ||= [])
  empty = stack.empty?

  if point.event == :b_call || point.event == :b_return
    return true if empty
    if point.terminate?(stack.last)
      stack.pop
    else
      stack << point
    end
    return false
  end

  if @no_methods.any?{ |pattern| pattern =~ point.method_id }
    if !empty && point.terminate?(stack.last)
      stack.pop
      return stack.empty?
    else
      stack << point
      point << Point::Omitted.new
      return empty
    end
  end

  empty
end
sort(trace_points) click to toggle source
# File lib/trace_tree.rb, line 188
def sort trace_points
  stacks = Hash.new{|h, thread| h[thread] = []}
  initialized_threads, began_threads = {}, {}

  trace_points.each do |point|
    stack = stacks[point.thread]
    unless stack.empty?
      if point.terminate? stack.last
        stack.last.terminal = point
        stack.pop
      else
        stack.last << point
        stack << point
      end
    else
      stack << point
    end
    initialized_threads[point.return_value] = point if Point::CreturnThreadInitialize.class_of? point
    began_threads[point.thread] = point if Point::Threadbegin.class_of? point
  end

  initialized_threads.each do |thread, point|
    point.thread_begin = began_threads[thread]
  end

  stacks.keys.each{ |thread| thread[:trace_tree_no_methods_stack] = nil }

  # binding.pry

  stacks[trace_points.first.thread][0].
    callees[0].
    callees[0]
end
table_of_points() click to toggle source
# File lib/trace_tree.rb, line 116
def table_of_points
  Terminal::Table.from_hashes trace_points_array.map(&:to_h)
rescue => e
  log.puts "#{__method__}", e.inspect, e.backtrace
end
trace_points_array() click to toggle source
# File lib/trace_tree.rb, line 222
def trace_points_array
  return @tpa if defined? @tpa
  @tpa = []
  @tpa << trace_points.deq until trace_points.size == 0
  @tpa
end