From: Jan Roslind on 11 Feb 2010 03:18 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 11 Feb 2010 14:55 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 12 Feb 2010 04:35 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 13 Feb 2010 09:45 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 15 Feb 2010 01:13
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. |