You could define a module that when included defines a method_added hook that wraps all new methods inside a begin..rescue block:
require 'set' module ExceptionHandler def self.included(klass) super klass.send(:extend, ClassMethods) end module ClassMethods def exception_handler(&block) @__exception_handler = block.to_proc end def handle_exception(exception) defined?(@__exception_handler) ? @__exception_handler.call(exception) : super end def handle_method_exceptions(method_name) old_method = instance_method(method_name) return if (@__hooked_methods ||= Set.new).include?(method_name) @__ignoring_added_methods = true # avoid infinite define_method/method_added loop define_method method_name do |*args, &block| begin old_method.bind(self).(*args, &block) rescue => ex self.class.handle_exception(ex) end end @__ignoring_added_methods = false @__hooked_methods << method_name end def method_added(method_name) super unless @__ignoring_added_methods handle_method_exceptions(method_name) end end end end
This would be used like:
class Foo include ExceptionHandler exception_handler do |exception| puts "Catched an exception:" puts "---------------------" puts "Exception class: #{exception.class}" puts "Message: #{exception.message}" puts "Backtrace:" puts exception.backtrace.join("\n ") puts puts "reraising.." puts raise exception end def this_raises raise "somebody set up us the bomb" end end Foo.new.this_raises
This would output:
Catched an exception: --------------------- Exception class: RuntimeError Message: somebody set up us the bomb Backtrace: errorhandler.rb:62:in `this_raises' errorhandler.rb:26:in `call' errorhandler.rb:26:in `block in handle_exceptions' errorhandler.rb:67:in `<main>' reraising..
I'm not sure if it is a good idea.
You could take out the method_added part and it would look something like:
class Foo with_rescue def foofoo(arg) puts arg.inspect end end
(You can just rename the handle_method_exceptions to with_rescue and remove all the @__ignoring_added_methods trickery and the method_added method and it should work as described).
fail "Trying to instantiate abstract class" if self.class == FooAbstractin FooAbstract#initialize.__callin ruby; the closest is probablymethod_missing. (And likewise, there's no direct equivalent tomethod_missingin PHP, but as far as I know__callis probably the closest.) But as Stefan says, what are you actually trying to achieve here? I can't really advise how to structure the code without knowing what problem you're trying to solve.rescue_fromso that you don't have to copy-paste the samerescueblock to every method.hiwill not invoke__callin any way. What was__callsupposed to do, add exception handling for all methods of child classes?