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?

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

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

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

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

On Thu, 11 Feb 2010 17:18:26 +0900
Jan R. [email protected] 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

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 16:27:02 +0900
Jan R. [email protected] wrote:

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

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

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

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:intest1’test.rb:55:in
test2'test.rb:67 Variable dump: variable_stack/0: caller = test.rb:42:intest1’
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

On 2/13/10, Jan R. [email protected] 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?

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.