Siaris

Redefining warn with tracebacks
19 Feb 04 - http://www.siaris.net/index.cgi/Programming/LanguageBits/Ruby/Warnings.rdoc

A recent question on the ruby newsgroup asked about getting line and file information when using the #warn method. The standard #warn method is really just equivelant to:

  $stderr.puts "Some warning message"

While the #raise method includes a full traceback including the filename, linenumber, and the stack of calls that got to this point. The #caller method provides all the needed traceback information — here’s the relevant portion of the ri generated docs:

  Kernel#caller

    caller(start=1)    => array

    Returns the current execution stack---an array containing
    strings in the form ``_file:line_'' or ``_file:line: in
    `method'_''. The optional _start_ parameter determines the
    number of initial stack entries to omit from the result.

So we just need to redefine the Kernel#warn method to use this information.

  module Kernel
    alias :oldwarn :warn
    def warn (msg = "", fulltrace = false)
      trace = caller(1)
      where = trace[0].sub(/:in.*/,'')
      $stderr.puts "#{where}: Warning: #{msg}"
      $stderr.puts trace.map {|t| "\tfrom #{t}"} if fulltrace
    end
  end

Now we have a method that will provide the file and linenumber, and optionally (if you supply a true second argument), a stacktrace like #raise does. Here we have a simple example script:

  ~$ nl -w3 -ba -s" " -nrn  warn.rb
    1 module Kernel
    2   alias :oldwarn :warn
    3   def warn (msg = "", fulltrace = false)
    4     trace = caller(1)
    5     where = trace[0].sub(/:in.*/,'')
    6     $stderr.puts "#{where}: Warning: #{msg}"
    7     $stderr.puts trace.map {|t| "\tfrom #{t}"} if fulltrace
    8   end
    9 end
   10
   11 class Foo
   12   def bar
   13     warn "just a warning"
   14   end
   15   def qux
   16     warn "warning with trace", true
   17   end
   18 end
   19
   20 obj = Foo.new
   21 obj.bar
   22 obj.qux

Which produces:

  ~$ ruby warn.rb
  warn.rb:13: Warning: just a warning
  warn.rb:16: Warning: warning with trace
          from warn.rb:16:in `qux'
          from warn.rb:22

Simple, but effective.