Running Code Only in Debug Mode

Problem

You want to print out debugging messages or run some sanity-checking code, but only while you e developing your application;, not when you e running it in production.

Solution

Run the code only if the global variable $DEBUG is true. You can trigger debug mode by passing in the --debug switch to the Ruby interpreter, or you can set the variable $DEBUG to true within your code.

Heres a Ruby program to divide two random numbers. It contains a trivial bug. It usually runs to completion, but sometimes it crashes. A line of debug code has been added to give some more visibility into the internal workings of the program:

	#!/usr/bin/env ruby
	# divide.rb
	numerator = rand(100)
	denominator = rand(10)
	$stderr.puts "Dividing #{numerator} by #{denominator}" if $DEBUG
	puts numerator / denominator

When run with the --debug flag, the debug message is printed to standard error:

	$ ./divide.rb --debug
	Dividing 64 by 9
	7

	$ ./divide.rb --debug
	Dividing 93 by 2
	46

	$ ./divide.rb --debug
	Dividing 54 by 0
	Exception eroDivisionError at divide_buggy.rb:6 - divided by 0
	divide_buggy.rb:6:in /: divided by 0 (ZeroDivisionError)
	 from divide_buggy.rb:6

Once the bug is fixed, you can go back to running the script normally, and the debug message won show up:

	$ ./divide.rb
	24

Discussion

This is a common technique when a "real" debugger is too much trouble. Its usually used to send debug messages to standard error, but you can put any code at all within a $DEBUG conditional. For instance, many Ruby libraries have their own "verbose", " debug level", or " debug mode" settings: you can choose to set these other variables appropriately only when $DEBUG is true.

	require fileutils
	FileUtils.cp(source, destination, $DEBUG)

If your code is running deep within a framework, you may not have immediate access to the standard error stream of the process. You can always have your debug code write to a temporary logfile, and monitor the file.

Use of $DEBUG costs a little speed, but except in tight loops its not noticeable. At the cost of a little more speed, you can save yourself some typing by defining convenience methods like this one:

	def pdebug(str)
	 $stderr.puts(DEBUG:  + str) if $DEBUG
	end

	pdebug "Dividing #{numerator} by #{denominator}"

Once youve fixed the bug and you no longer need the debugging code, its better to put it into a conditional than to simply remove it. If the problem recurs later, youll find yourself adding the debugging code right back in.

Sometimes commenting out the debugging code is better than putting it into a conditional. Its more difficult to hunt down all the commented-out code, but you can pick and choose which pieces of code to uncomment. With the $DEBUG technique, its all or nothing.

It doesn have to be all or nothing, though. $DEBUG starts out a boolean but it doesn have to stay that way: you can make it a numeric "debug level". Instead of doing something if $DEBUG, you can check whether $DEBUG is greater than a certain number. A very important piece of debug code might be associated with a debug level of 1; a relatively unused piece might have a debug level of 5. Setting $DEBUG to zero would turn off debugging altogether.

Here are some convenience methods that make it easy to use $DEBUG as either a boolean or a numeric value:

	def debug(if_level) 
	 yield if ($DEBUG == true) || ($DEBUG && $DEBUG >= if_level)
	end

	def pdebug(str, if_level=1) 
	 debug(if_level) { $stderr.puts "DEBUG: " + str }
	end

One final note: make sure that you put the --debug switch on the command line before the name of your Ruby script. Its an argument to the Ruby interpreter, nottoyour script.

See Also

  • Recipe 17.5, "Adding Logging to Your Application," demonstrates a named system of debug levels; in fact, if your debug messages are mainly diagnostic, you might want to implement them as log messages


Strings

Numbers

Date and Time

Arrays

Hashes

Files and Directories

Code Blocks and Iteration

Objects and Classes8

Modules and Namespaces

Reflection and Metaprogramming

XML and HTML

Graphics and Other File Formats

Databases and Persistence

Internet Services

Web Development Ruby on Rails

Web Services and Distributed Programming

Testing, Debugging, Optimizing, and Documenting

Packaging and Distributing Software

Automating Tasks with Rake

Multitasking and Multithreading

User Interface

Extending Ruby with Other Languages

System Administration



Ruby Cookbook
Ruby Cookbook (Cookbooks (OReilly))
ISBN: 0596523696
EAN: 2147483647
Year: N/A
Pages: 399

Flylib.com © 2008-2020.
If you may any questions please contact us: flylib@qtcs.net