From: Paul Brannan Date: 2003-01-23T06:32:31+09:00 Subject: Re: iterating in a test On Wed, Jan 22, 2003 at 03:31:01PM +0900, nathaniel@NOSPAMtalbott.ws wrote: > def performing_action(message) # Not tested > @message_stack ||= [] > @message_stack.push(message) > begin > yield > rescue Exception > raise $!, [$!.message, *@message_stack].join("\n"), $!.backtrace > ensure > @message_stack.pop > end > end This works well in Ruby 1.7/1.8. In Ruby 1.6 this doesn't work as well, though: class Exc < Exception def initialize(a, b, c) super("Exception: #{a}, #{b}, #{c}") end end performing_action('playing with Ruby') do performing_action('doing some silly things') do raise Exc.new(1, 2, 3) end end [pbrannan@zaphod tmp]$ ruby -v ruby 1.6.8 (2002-12-24) [i686-linux] [pbrannan@zaphod tmp]$ ruby test.rb test.rb:7:in `initialize': wrong # of arguments(1 for 3) (ArgumentError) playing with Ruby from test.rb:7:in `exception' from test.rb:7:in `raise' from test.rb:7:in `performing_action' from test.rb:32 from test.rb:31:in `performing_action' from test.rb:31 So instead I have: def performing_action(action) begin yield ensure $!.message.replace($!.message + "\n\twhile " + action) if $! end end [pbrannan@zaphod tmp]$ ruby test.rb test.rb:32: Exception: 1, 2, 3 (Exc) while doing some silly things while playing with Ruby from test.rb:31:in `performing_action' from test.rb:31 from test.rb:30:in `performing_action' from test.rb:30 Or alternately: module ExceptionActions attr_reader :actions def self.extend_object(obj) super(obj) obj.instance_eval { @actions = [] } end def to_s return super + @actions.map { |a| "\n\twhile #{a}" }.join end alias_method :message, :to_s alias_method :to_str, :to_s end def performing_action(action) begin yield ensure if $! then if not ExceptionActions === exc then $!.extend(ExceptionActions) end $!.actions.push(action) end end end The latter solution is a little more verbose but also a little more robust (it still works even if $!.message is not a string). > It's seems overly complex for me to want to use it, though; if the > simpler solution I gave above wouldn't work, I'd probably start looking > to refactor my tests. Just my $0.02. Refactoring my tests is what brought this about. I had many tests doing very similar things, but varying by only a few parameters. My solution was to consolidate those tests into a few small tests. Perhaps there's a better solution that I'm not aware of. Paul