I’ve been doing a lot of pontification lately. Time for some code.

Warnings are a hot topic in the Ruby community. Some folks love ’em. Some folks hate ’em. What we can all agree on is that they do us no good when loading third-party gems in strict mode overruns our output with warnings we have no control over.

Here’s a file that will generate several warnings under -w:

Here’s the good news: Ruby uses the mutable $stderr global for all of its warnings. Why is this good news? Behold:

Let’s give it a try:

When I run this under Ruby 1.9.2, here’s what I get:

Loading messy.rb
---- Begin ----
/home/avdi/Dropbox/scratch/warnings/messy.rb:2: warning: useless use of a variable in void context
/home/avdi/Dropbox/scratch/warnings/messy.rb:4: warning: method redefined; discarding old bar
/home/avdi/Dropbox/scratch/warnings/messy.rb:3: warning: previous definition of bar was here
/home/avdi/Dropbox/scratch/warnings/messy.rb:6: warning: already initialized constant BAZ
---- End   ----
Loading messy.rb with warnings silenced
---- Begin ----
---- End   ----

So there you have it: a way to load warning-ridden files in -w mode without flooding your output.

I can think of lots of improvements–for starters, there’s no reason to fill up a StringIO buffer with output we’re just going to ignore. But I need to get ready for my trip to Ruby Hoedown, so I’ll leave the tinkering to you.

EDIT: Before you get too excited, though, the code above (or code using VERBOSE=nil, as commenters have pointed out)  only solves a small part of the problem. If third-party code generates warnings at runtime, you’ll have to wrap every single call to the third-party code with a warnings silencer block.

Published by Avdi Grimm

9 Comments

  1. You are a terrible, terrible person.  😉

    Reply
  2. Ruby has a variable for controlling the warnings level, called $VERBOSE.  We can just use this by saving it’s value at the beginning of the method (old_verbose, $VERBOSE = $VERBOSE, nil) and restoring it in the ensure clause ($VERBOSE = old_verbose).

    Reply
  3. There is also $VERBOSE = false if you don’t want to redirect stderr (maybe the library uses stderr for something useful).

    Although testing your messy.rb I found that $VERBOSE = false still complained about the constant redefinition. So your method is more complete. But if you need stderr to work then $VERBOSE = false is nice (of course you can turn on warnings with $VERBOSE = true).

    Rails uses this method in it’s implementation of “silence_warnings”.

    Reply
  4. $VERBOSE = false and $VERBOSE = nil mean different things.

    Only $VERBOSE = nil will squash interpreter warnings. $VERBOSE = false will squash Kernel.warn

    Reply
  5. Ruby’s $VERBOSE would be so much more useful if it could be enabled or disabled on a per-file basis.

    Reply
  6. $-v = true is simpler.

    Reply
  7. Thanks Avdi and James. The warning is no longer polluting my RSpec test.

    Too bad there’s not a narrower way to disable that output though — this one is not thread safe, in that code running in other threads that needs to report errors to stderr will not be able to do so.

    Reply
    • Interestingly, Matz said at the recent RubyConf that he regrets putting as many global variables in Ruby as he did.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *