From: Andrew Wagner on
[Note: parts of this message were removed to make it a legal post.]

So if the do_stuff is in a format like this:

def do_something
From: Martin Hansen on
Andrew Wagner wrote:

> Then when you could do is have a module which overrides Ruby's method
> that
> gets called when you define a method. You can alias the method being
> created
> to something else, then define a new method which calls that one, but
> wraps
> it in whatever error-handling code you want.

Sorry, I have no idea how to do that - it sounds terribly complicated.
Is there no simple solution? Could you perhaps give a small example?


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

From: Andrew Wagner on
[Note: parts of this message were removed to make it a legal post.]

Ok, so here's something fairly simple to try. There are better ways to do
this, but this should work. In your error-handling file, put this:

module ErrorHandling
def self.included(cls)
def cls.method_added(method)
return if @_adding_a_method
@_adding_a_method = true

original_method = "original #{method}"
alias_method original_method, method

define_method(method) do |*args|
begin
puts "gonna try something dangerous"
send original_method, *args
rescue Exception
ensure
puts "My last will and testament..."
end
end

@_adding_a_method = false
end
end
end

The idea is, when you include this module, then it watches for any new
methods you define. When you define one, it immediately hides it away, and
creates a new method, which calls the original one, but inside a
begin/rescue/ensure block. The @_adding_a_method flag is just to keep from
infinite recursion when you create the new method (because it will also
trigger method_added.

Now in your main class, do something like this:

include ErrorHandling

def do_something
puts "do something dangerous"
end

do_something

On Thu, Aug 5, 2010 at 1:37 PM, Martin Hansen <mail(a)maasha.dk> wrote:

> Andrew Wagner wrote:
>
> > Then when you could do is have a module which overrides Ruby's method
> > that
> > gets called when you define a method. You can alias the method being
> > created
> > to something else, then define a new method which calls that one, but
> > wraps
> > it in whatever error-handling code you want.
>
> Sorry, I have no idea how to do that - it sounds terribly complicated.
> Is there no simple solution? Could you perhaps give a small example?
>
>
> Martin
> --
> Posted via http://www.ruby-forum.com/.
>
>

From: Andrew Wagner on
[Note: parts of this message were removed to make it a legal post.]

For a somewhat more robust ErrorHandling module, which requires 1.9, try the
code below. I should also give credit to the ruby metaprogramming
screencast<http://pragprog.com/screencasts/v-dtrubyom/the-ruby-object-model-and-metaprogramming>
for
inspiration for this code. It's practically ripped straight out of there,
except theirs does tracing, as opposed to just error-handling.

module ErrorHandling
def self.included(klass)
klass.instance_methods(false).each do |existing_method|
wrap(klass, existing_method)
end

def klass.method_added(method)
unless @watch_calls_internal
@watch_calls_internal = true
ErrorHandling.wrap(self, method)
@watch_calls_internal = false
end
end
end

def self.wrap(klass, method)
klass.class_eval do
name = method.to_s
original_method = instance_method(name)

define_method(name) do |*args, &block|
begin
puts "attempting..."
result = original_method.bind(self).call(*args, &block)
rescue Exception
ensure
puts "last will..."
end
result
end
end
end
end

On Thu, Aug 5, 2010 at 5:13 PM, Andrew Wagner <wagner.andrew(a)gmail.com>wrote:

> Ok, so here's something fairly simple to try. There are better ways to do
> this, but this should work. In your error-handling file, put this:
>
> module ErrorHandling
> def self.included(cls)
> def cls.method_added(method)
> return if @_adding_a_method
> @_adding_a_method = true
>
> original_method = "original #{method}"
> alias_method original_method, method
>
> define_method(method) do |*args|
> begin
> puts "gonna try something dangerous"
> send original_method, *args
> rescue Exception
> ensure
> puts "My last will and testament..."
> end
> end
>
> @_adding_a_method = false
> end
> end
> end
>
> The idea is, when you include this module, then it watches for any new
> methods you define. When you define one, it immediately hides it away, and
> creates a new method, which calls the original one, but inside a
> begin/rescue/ensure block. The @_adding_a_method flag is just to keep from
> infinite recursion when you create the new method (because it will also
> trigger method_added.
>
> Now in your main class, do something like this:
>
> include ErrorHandling
>
> def do_something
> puts "do something dangerous"
> end
>
> do_something
>
> On Thu, Aug 5, 2010 at 1:37 PM, Martin Hansen <mail(a)maasha.dk> wrote:
>
> > Andrew Wagner wrote:
> >
> > > Then when you could do is have a module which overrides Ruby's method
> > > that
> > > gets called when you define a method. You can alias the method being
> > > created
> > > to something else, then define a new method which calls that one, but
> > > wraps
> > > it in whatever error-handling code you want.
> >
> > Sorry, I have no idea how to do that - it sounds terribly complicated.
> > Is there no simple solution? Could you perhaps give a small example?
> >
> >
> > Martin
> > --
> > Posted via http://www.ruby-forum.com/.
> >
> >
>

From: Martin Hansen on
I have been looking at your suggestions and done a few tests. However, I
wonder if there is not a more simple way - and especially since these
suggestions depends on methods being defined in order to invoke error
handling. Here is a real life example of the type of minimalistic
scripts I want to write:

#!/usr/bin/env ruby

require 'biopieces'

casts = []
casts <<
{:long=>'compress',:short=>'Z',:type=>'flag',:mandatory=>false,:default=>nil,:allowed=>nil,:disallowed=>nil}

bp = Biopieces.new

options = bp.parse(ARGV,casts)

bp.mktmpdir # create an optional temporary directory that is auto
deleted.

bp.each_record do |record|
# do something to each record (possibly according to the options).
e.g.:
record["SEQ"].upcase! if record.has_key? "SEQ"
bp.puts record
raise # Debug test of invokation of error handling
end



Now, I would like error handling to be invoked, if possible from
biopieces.rb, in the case some exception is raised (either by raise or
ctrl-c, etc), but I am not defining any methods and thus the suggested
meta-programming approaches seem to fall short.


Cheers,


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