lib/tracer.rb


DEFINITIONS

This source file includes following functions.


   1  #
   2  #   tracer.rb - 
   3  #       $Release Version: 0.2$
   4  #       $Revision: 1.8 $
   5  #       $Date: 1998/05/19 03:42:49 $
   6  #       by Keiju ISHITSUKA(Nippon Rational Inc.)
   7  #
   8  # --
   9  #
  10  #   
  11  #
  12  
  13  #
  14  # tracer main class
  15  #
  16  class Tracer
  17    @RCS_ID='-$Id: tracer.rb,v 1.8 1998/05/19 03:42:49 keiju Exp keiju $-'
  18  
  19    @stdout = STDOUT
  20    @verbose = false
  21    class << self
  22      attr :verbose, true
  23      alias verbose? verbose
  24      attr :stdout, true
  25    end
  26    
  27    MY_FILE_NAME = caller(0)[0].scan(/^(.*):[0-9]+$/)[0][0]
  28    
  29    EVENT_SYMBOL = {
  30      "line" => "-",
  31      "call" => ">",
  32      "return" => "<",
  33      "class" => "C",
  34      "end" => "E",
  35      "c-call" => ">",
  36      "c-return" => "<",
  37    }
  38    
  39    def initialize
  40      @threads = Hash.new
  41      if defined? Thread.main
  42        @threads[Thread.main.id] = 0
  43      else
  44        @threads[Thread.current.id] = 0
  45      end
  46  
  47      @get_line_procs = {}
  48  
  49      @filters = []
  50    end
  51    
  52    def stdout
  53      Tracer.stdout
  54    end
  55  
  56    def on
  57      if block_given?
  58        on
  59        begin
  60          yield
  61        ensure
  62          off
  63        end
  64      else
  65        set_trace_func proc{|event, file, line, id, binding, klass, *rest|
  66          trace_func event, file, line, id, binding, klass
  67        }
  68        stdout.print "Trace on\n" if Tracer.verbose?
  69      end
  70    end
  71    
  72    def off
  73      set_trace_func nil
  74      stdout.print "Trace off\n" if Tracer.verbose?
  75    end
  76  
  77    def add_filter(p = proc)
  78      @filters.push p
  79    end
  80  
  81    def set_get_line_procs(file, p = proc)
  82      @get_line_procs[file] = p
  83    end
  84    
  85    def get_line(file, line)
  86      if p = @get_line_procs[file]
  87        return p.call(line)
  88      end
  89  
  90      unless list = SCRIPT_LINES__[file]
  91        begin
  92          f = open(file)
  93          begin 
  94            SCRIPT_LINES__[file] = list = f.readlines
  95          ensure
  96            f.close
  97          end
  98        rescue
  99          SCRIPT_LINES__[file] = list = []
 100        end
 101      end
 102      if l = list[line - 1]
 103        l
 104      else
 105        "-\n"
 106      end
 107    end
 108    
 109    def get_thread_no
 110      if no = @threads[Thread.current.id]
 111        no
 112      else
 113        @threads[Thread.current.id] = @threads.size
 114      end
 115    end
 116    
 117    def trace_func(event, file, line, id, binding, klass)
 118      return if file == MY_FILE_NAME
 119      
 120      for p in @filters
 121        return unless p.call event, file, line, id, binding, klass
 122      end
 123      
 124      Thread.critical = true
 125      stdout.printf("#%d:%s:%d:%s:%s: %s",
 126        get_thread_no,
 127        file,
 128        line,
 129        klass || '',
 130        EVENT_SYMBOL[event],
 131        get_line(file, line))
 132      Thread.critical = false
 133    end
 134  
 135    Single = new
 136    def Tracer.on
 137      if block_given?
 138        Single.on{yield}
 139      else
 140        Single.on
 141      end
 142    end
 143    
 144    def Tracer.off
 145      Single.off
 146    end
 147    
 148    def Tracer.set_get_line_procs(file_name, p = proc)
 149      Single.set_get_line_procs(file_name, p)
 150    end
 151  
 152    def Tracer.add_filter(p = proc)
 153      Single.add_filter(p)
 154    end
 155    
 156  end
 157  
 158  SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
 159  
 160  if caller(0).size == 1
 161    if $0 == Tracer::MY_FILE_NAME
 162      # direct call
 163      
 164      $0 = ARGV[0]
 165      ARGV.shift
 166      Tracer.on
 167      require $0
 168    else
 169      Tracer.on
 170    end
 171  end