Creating and Understanding Tracebacks

Problem

You are debugging a program, and need to understand the stack traces that come with Ruby exceptions. Or you need to see which path the Ruby interpreter took to get to a certain line of code.

Solution

You can call the Kernel#caller method at any time to look at the Ruby interpreters current call stack. The call stack is represented as a list of strings.

This Ruby program simulates a company with a top-down management style: one method delegates to another, which calls yet another. The method at the bottom can use caller to look upwards and see the methods that called it:

	 1 #!/usr/bin/ruby -w
	 2 # delegation.rb
	 3 class CEO
	 4 def CEO.new_vision
	 5 Manager.implement_vision
	 6 end
	 7 end
	 8
	 9 class Manager
	10 def Manager.implement_vision
	11 Engineer.do_work
	12 end
	13 end
	14
	15 class Engineer
	16 def Engineer.do_work
	17 puts How did I get here?
	18 first = true
	19 caller.each do |c|
	20 puts %{#{(first ? I :  which)} was called by "#{c}"}
	21 first = false
	22 end
	23 end
	24 end
	25
	26 CEO.new_vision

Running this program illustrates the path the interpreter takes to Engineer.do_work:

	$ ./delegation.rb
	How did I get here?
	I was called by "delegation.rb:11:in implement_vision"
	 which was called by "delegation.rb:5:in 
ew_vision"
	 which was called by "delegation.rb:26"

Discussion

Each string in a traceback shows which line of Ruby code made some method call. The first bit of the traceback given above shows that Engineer.do_work was called by Manager.implement_vision on line 11 of the program. The second line shows how Manager.implement_vision was called, and so on.

Remember the stack trace displayed when a Ruby script raises an exception? Its the same one you can get any time by calling Kernel#caller. In fact, if you rescue an exception and assign it to a variable, you can get its traceback as an array of strings the equivalent of calling caller on the line that triggered the exception:

	def raise_exception
	 raise Exception, You wanted me to raise an exception, so…
	end

	begin
	 raise_exception
	rescue Exception => e
	 puts "Backtrace of the exception:
 #{e.backtrace.join("
 ")}"
	end
	# Backtrace of the exception:
	# (irb):2:in 
aise_exception
	# (irb):5:in irb_binding
	# /usr/lib/ruby/1.8/irb/workspace.rb:52:in irb_binding
	# :0

Note the slight differences between a backtrace generated from a Ruby script and one generated during an irb session.

If youve used languages like Python, you might long for "real" backtrace objects. About the best you can do is to parse the strings of a Ruby backtrace with a regular expression. The parse_caller method below extracts the files, lines, and method names from a Ruby backtrace. It works in both Ruby programs and irb sessions.

	CALLER_RE = /(.*):([0-9]+)(:in \(.*))?/
	def parse_caller(l)
	 l.collect do |c|
	 captures = CALLER_RE.match(c)
	 [captures[1], captures[2], captures[4]]
	 end
	end

	begin
	 raise_exception
	rescue Exception => e
	 puts "Exception history:"
	 first = true
	 parse_caller(e.backtrace).each do |file, line, method|
	 puts %{ #{first ? "L" : "because l"}ine #{line} in "#{file}"} +
	 %{ called "#{method}" }
	 first = false
	 end
	end
	# Exception history:
	# Line 2 in "(irb)" called "raise_exception"
	# because line 24 in "(irb)" called "irb_binding"
	# because line 52 in "/usr/lib/ruby/1.8/irb/workspace.rb" called "irb_binding"
	# because line 0 in "" called ""

See Also

  • Recipe 17.3, "Handling an Exception"


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