Global rescue - DRY (don't repeat yourself)

I am trying to implement report to a bug management system in rails.
Want to report error stack, local and instance variables for every
method and has come to following "global" rescue clause:

def xxx
  begin
    ...
    ...
  rescue => e
    SomeClass.some_method binding, self # appends variable info to a
class variable
    raise
  end
end # xxx

The problem it is not wery DRY to repeat the above rescue for every
method in my application.

Have tried with:

def xxxx
  begin
    ...
    ...
  load 'global_rescue.rb' # rescue => e ; SomeClass.some_method binding,
self ; raise
end # xxx

without success. No errors message but also no capture of variable
information for xxx. Can't use include. Works only for models :=(

Any suggestions?

···

--
Posted via http://www.ruby-forum.com/.

Hi,

lib_error.rb:

class Library
  def self.error
    puts "Oops. something went wrong"
  end
end

original_code.rb:

# require the file first line of code instead of calling in mid of
programs

require 'lib_error.rb'

begin
  puts fg
rescue
   Library.error
end

begin
  puts fdg
rescue
  Library.error
end

Run the code:

Oops. something went wrong
Oops. something went wrong

I hope it clears ur doubt. If need more details then update here asap.

Thanks,
P.Raveendran

···

--
Posted via http://www.ruby-forum.com/.

Hi,

You can use the first line as,

require 'lib_error'

OR

load 'lib_error.rb'

OR

require 'lib_error.rb'

Thanks,
P.Raveendran
http://raveendran.wordpress.com

···

--
Posted via http://www.ruby-forum.com/.

Thanks P.Raveendran
Will give it a try :=)

···

--
Posted via http://www.ruby-forum.com/.

Raveendran .P wrote:

....
begin
  puts fdg
rescue
  Library.error
end
.....

Sorry, but I ends up adding

rescue
  Library.error binding, self

to every methods. Not wery DRY. Problem if I want to change rescue
clause later (add a argument)

Regards
Jan

···

--
Posted via http://www.ruby-forum.com/\.

Hmm.. what about:

class Code
  def self.try(&block)
    begin
      block.call
    rescue
      puts "Errors: #{$!}"
    end
  end
end
     
Code.try do
  a = 1123
  bad_code
end
   
Cheers,
Martin

···

On Thu, 11 Feb 2010 16:27:02 +0900 Jan Roslind <jan@jan-roslind.dk> wrote:

Raveendran .P wrote:
> ....
> begin
> puts fdg
> rescue
> Library.error
> end
> .....

Sorry, but I ends up adding

rescue
  Library.error binding, self

to every methods. Not wery DRY. Problem if I want to change rescue
clause later (add a argument)

Regards
Jan

Martin Boese wrote:
....

Hmm.. what about:

class Code
  def self.try(&block)
    begin
      block.call
    rescue
      puts "Errors: #{$!}"
    end
  end
end

Code.try do
  a = 1123
  bad_code
end

Hi Martin.
Thanks for your suggestion. It Works.
But how do I access bindings (to find local variables) and self (to find
instance variables) from Code.try method.
Regards Jan

···

--
Posted via http://www.ruby-forum.com/\.

Local and instance variables probably work as you expect:

local = 'test'
@instance = 'instance'

Code.try do
  "#{local} #{@instance} #{self.class.name}"
end
=> "test instance Object"

···

On Thu, 11 Feb 2010 17:18:26 +0900 Jan Roslind <jan@jan-roslind.dk> wrote:

Hi Martin.
Thanks for your suggestion. It Works.
But how do I access bindings (to find local variables) and self (to
find instance variables) from Code.try method.
Regards Jan

--
Internet Technologies Angola / MAXNET
Tel: +244 (227) 286 000 / (924) 770 290 / (924) 770 291
Mobile: +244 (927) 986 444
Mail: martin@internet.ao

Sorry - my fault - I should have included a running demo:

class VariableStack

  @@variables =

  def self.save_variables (xbinding, xself)
    @@variables << [ caller[0], xbinding, xself ]
  end # self.save_variables

  def self.get_instance_variables (xself)
    xself.instance_variables.collect do |name|
      value = xself.instance_variable_get(name)
      "#{name}=#{value}"
    end
  end # self.get_instance_variables

  def self.dump_variables
    puts "Variable dump:"
    lng = @@variables.size
    0.upto(lng-1) do |i|
      xcaller, xbinding, xself = @@variables[i]
      xlocal_variables = eval("local_variables", xbinding).collect {

a> "#{a}=#{eval(a, xbinding)}" }.join(', ')

      xinstance_variables =
VariableStack.get_instance_variables(xself).join(', ')
      puts "variable_stack/#{i}:"
      puts " caller = #{xcaller}"
      puts " local variables = #{xlocal_variables}"
      puts " instance variables = #{xinstance_variables}"
    end # each variables
    @@variables =
  end # self.dump_variables

end # VariableStack

class SomeClass1

  def self.test1
    begin
      @some_instance_var1 = 1
      some_local_var2 = 0
      some_local_var3 = 3
      division_by_with_zero = @some_instance_var1 / 0
    rescue => e ; VariableStack.save_variables(binding, self) ; raise #
generel rescue clause - used 10.000 times - not wery DRY
    end
  end # self.test1

end # SomeClass1

class SomeClass2

  def self.test2
    begin
      @some_instance_variable4 = 4
      some_local_var5 = 5
      SomeClass1.test1
    rescue => e ; VariableStack.save_variables(binding, self) ; raise #
generel rescue clause - used 10.000 times - not wery DRY
    end
  end # self.test2

end # SomeClass2

# rails session, batch job or demon proces
begin
  @some_instance_variable6 = 6
  some_local_var7 = 7
  SomeClass2.test2
rescue => e
  puts "error = #{e.message.to_s}"
  puts "backtrace = #{e.backtrace}"
  VariableStack.dump_variables
  # to-do: bug management system: save error report in database or send
error report as mail
end

Output:

error = divided by 0
backtrace = test.rb:41:in `/'test.rb:41:in `test1'test.rb:55:in
`test2'test.rb:67
Variable dump:
variable_stack/0:
  caller = test.rb:42:in `test1'
  local variables = some_local_var2=0, some_local_var3=3,
division_by_with_zero=, e=divided by 0
  instance variables = @some_instance_var1=1
variable_stack/1:
  caller = test.rb:56:in `test2'
  local variables = some_local_var5=5, e=divided by 0
  instance variables = @some_instance_variable4=4

My problem is that I don't want to repeat

rescue => e ; VariableStack.save_variables(binding, self) ; raise

for every method in my application. It would be much better with

load 'global_rescue_clause.rb', but that does not work.

Is there a way to include "row" ruby source code in ruby method, or an
more OO way to get a variable stack with local and instance variables?

Regards
Jan

···

--
Posted via http://www.ruby-forum.com/\.

Is there a way to include "raw" ruby source code in ruby method, or an
more OO way to get a variable stack with local and instance variables?

Regards
Jan

···

--
Posted via http://www.ruby-forum.com/.

It seems to me that a macro is the best way to get to almost what you
want. Take a look at this: GitHub - coatl/rubymacros: RubyMacros is a lisp-like macro pre-processor for Ruby. More than just a purely textual substitution scheme, RubyMacros can manipulate and morph Ruby parse trees (in the form of RedParse Nodes) at parse time in just about any way you see fit. and/or
try typing 'gem install rubymacros' in a terminal.

Here's a macro that injects a rescue clause into method definitions:

macro rescuing_vars(method)
  method.body=:(
     begin
        ^method.body
     rescue => e; VariableStack.save_variables(binding, self) ; raise
     end
  )
  return method
end

You would then use it like this:

rescuing def foo
  bar baz, quux
end
#try to think of the 'rescuing' here as a
#declaration modifier, like 'static', 'inline', or 'const' in C++

which the above macro turns into:

def foo
  begin
    bar baz, quux
  rescue => e; VariableStack.save_variables(binding, self) ; raise
  end
end

You still have to go and mark each method in your program with the
rescuing tag, which is why I say it's only almost what you want. On
the plus side, you get control over which methods have their behavior
changed in this way.

You could also accomplish more or less the same thing if you keep your
method bodies in strings which get passed to eval, or blocks which get
passed to instance_eval, but that looks even less like normal ruby
code. On the other hand, you wouldn't need a special library
(rubymacros) that makes strange changes to ruby's syntax...

There may also be a better way to implement your algorithm without all
the metaprogramming magic. Sometimes when you think you need something
really strange that doesn't seem to exist, it's because you're
thinking about the problem in the wrong way.

···

On 2/13/10, Jan Roslind <jan@jan-roslind.dk> wrote:

Is there a way to include "raw" ruby source code in ruby method, or an
more OO way to get a variable stack with local and instance variables?