ruby picture

RCR 180: Warning framework

Submitted by Paul Brannan (Mon Jan 05 11:01:05 UTC 2004)

Abstract

Ruby should have a framework for capturing, suppressing, and logging warnings.

Problem

Ruby currently sends all warnings to stderr. Some applications (for example, Ruby embedded in a text editor) would probably do better if they could capture warnings and present them to a user in a text box or log window. With a proper "warning framework," this would be possible.

Proposal

Ruby should call a method when a warning occurs; this will allow the user to define their own handler for warnings. This method should be a proc set via a method set_warn_func and should take as a parameter a String or a Warning object:

  Warning = Struct.new(
      :level, # integer from 1 to 10
      :file,  # file the warning came from (String)
      :line,  # line number the warning came from (Numeric)
      :msg)   # the actual warning message
  class Warning
    def to_s
      return msg()
    end
  end</pre>

The default action for the warn func should be:
  set_warn_func proc { |warning|

    
    $stderr.puts warning
  }</pre>

Calling set_warn_func with nil should reset Ruby to the default action.
The return value of set_warn_func should be the previously defined warn func so that warn funcs can be chained (Note: This differs from the behavior of set_trace_func, and I'm not sure how to reconcile this difference without giving up this feature).
In addition, the warn() method should be changed to accept:
  1. warn(Warning)        #=> call the warn func with the given warning

    
  2. warn(String, Fixnum) #=> create a new Warning with the given message and
                          #   warn level and pass it to the warn func
  3. warn(String)         #=> create a new Warning with the given message and
                          #   default warn level and pass it to the warn func</pre>

An example:
  set_warn_func proc { |warning|

    
    warning = Warning.new(warning) if not Warning === warning
    if warning.level &lt; 10 or
       warning.file == "a_file_I_want_to_ignore_warnings_in.rb" then
      # ignore this warning
    else
      $stderr.puts(warning)
      send_email_to_me_about(warning)
    end
  }
  class Foo
    def foo; end
    def foo; end # doesn't print anything since the warning's level is
                 # too low
  end</pre&gt;

  

Analysis

Handling warnings this way allows:
  <li>The user can hook into the existing warn func or redefine the existing warn func altogether.
  <li>The user can still call the warn() method with a String (so the existing interface for warn() is not broken) or with a Warning object (so, for example, drb can marshal warnings across the wire and have them show up as warnings on the client)
  <li>It has a similar interface to set_trace_func, so users will be familiar with how to use it.

Implementation

ruby picture
Comments Current voting
I like the idea of a application specific approach to handling warnings. However, I think a single, global, warning handler might be a bit too restrictive/cumbersome.

Having warnings behave like exceptions is an approach I have seen work well in. They can be rescued and logged, or converted into exception if appropriate (there might be areas of you code where particular warnings are unacceptable). This approach would require the addition of a "continue" (or equivalent) operation for rescue blocks which would simply continue the execution immediately following the raise statement. The "continue" operation would probably need to check the exception object and refuse to continue non-warning exceptions, just to be on the safe side.


Strongly opposed 0
Opposed 0
Neutral 0
In favor 13
Strongly advocate 8
ruby picture
If you have registered at RCRchive, you may now sign in below. If you have not registered, you may sign up for a username and password. Registering enables you to submit new RCRs, and vote and leave comments on existing RCRs.
Your username:
Your password:

ruby picture

Powered by .