Temporarily disabling warnings in Ruby

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:

[gist id=1170926 file=messy.rb]

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

[gist id=1170926 file=silent_warnings.rb]

Let’s give it a try:

[gist id=1170926 file=main.rb]

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.

9 comments

  1. 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).

  2. 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”.

  3. $VERBOSE = false and $VERBOSE = nil mean different things.

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

  4. 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.

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

Comments are closed.