From: Jan Roslind on
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/.

From: Martin Boese on
On Thu, 11 Feb 2010 17:18:26 +0900
Jan Roslind <jan(a)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

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"


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

From: Jan Roslind on
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/.

From: Jan Roslind on
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/.

From: Caleb Clausen on
On 2/13/10, Jan Roslind <jan(a)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?

It seems to me that a macro is the best way to get to almost what you
want. Take a look at this: http://github.com/coatl/rubymacros 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.