Rescue on parent method an exception raised in child - ruby

Is there any way in Ruby to have a standard rescue strategy based in inheritance?
I'd like to have something like:
class Parent
def method
rescue StandardError => e
#handle error
end
end
class Child < Parent
def method
raise StandardError.new("ERROR") if error_present
#do some stuff
super
end
def error_present
#checks for errors
end
end
and the result I expect is that when the StandardError is raised in the child's method it will be rescued from the parent's method definition.
If that's not possible, is there any other way I could achieve this behaviour?

I am afraid this is not possible - one method's rescue can only rescue errors raised within its body.
One way to deal with this would be to offer another method to override in subclasses:
class Parent
# This is the public interface of the class, it is not supposed to be overriden
def execute!
perform
rescue => e
# do_sth_with_error
end
private
# Private implementation detail, override at will
def perform
end
end
class Child < Parent
private
def perform
raise "Something" if something?
# do some more things
super
end
end
Child.new.execute!
That being said - please do not rescue StandardError. It will make your future debugging a nightmare. Create your own error subclass instead.

You can have such a strategy, but it depends how exactly it should work and how your code is organized. This pattern can be extended. For your particular case you can organize your code as follows:
class Parent
def my_method(arg1, arg2)
yield if block_given?
# some code that should be run by Parent#my_method
rescue StandardError => e
# handle the error
end
end
class Child < Parent
def my_method(arg1, arg2)
super do
# code that should be run by Child#my_method
raise StandardError.new('error message') if error?
# maybe more code that should be run by Child#my_method
end
end
def error?
true
end
end
With this strategy you have to inject all your code from the child method as a block passed to you parent method through a super call that is the only statement (well, basically it's a closure passed up in the inheritance chain). Of course, this strategy assumes that your method doesn't use a block to implement its normal logic and you can use this feature specifically for this execution injection.
If you want to have more than two levels of inheritance using this strategy, you'll have to to the same trick with every next method:
class C
def m1
yield if block_given?
# ...
rescue SomeError
# ...
end
end
class B < C
def m1
super do
yield if block_given?
# ...
end
end
end
class A < B
def m1
super do
raise SomeError if condition
# ...
end
end
end
Most probably you can remove the if block_given? parts if you apply this strategy.

Related

How to call any instance method in ruby object without instantiating it?

I am creating a helper module to initialize the object before calling its methods
module Initialized
extend ActiveSupport::Concern
class_methods do
def run(*args)
new(*args).run
end
def call(*args)
new(*args).call
end
def execute(*args)
new(*args).create
end
end
end
So instead of defining run, call, and execute in my helper module I need to receive any method name and check if it exists on the main class after initializing it, then call the requested instance method if exists in the main class or raise an error if not
I would say my targeted code would be something like this
module Initialized
extend ActiveSupport::Concern
class_methods do
def _(*args, methodname)
new(*args).try(:send, "#{methodname}") || raise 'Method not exist'
end
end
end
Sample usage would be
class MyClass
include Initialized
def initialize(param1)
#param1 = param1
end
def call
puts "call '#{#param1}'"
end
end
then calling
MyClass.call('method param')
I found these links but couldn't find my answer yet:
meta-dynamic-generic-programming-in-ruby
ruby-module-that-delegates-methods-to-an-object
template-methods-in-ruby
Despite the fact method_missing would do the job, I'd probably avoid it in this case in favor of a more explicit delegation. Simple and dirty example:
module InstanceDelegator
def delegate_to_instance(*methods)
methods.each do |method_name|
define_singleton_method method_name do |*args|
new(*args).public_send(method_name)
end
end
end
end
class Foo
extend InstanceDelegator
delegate_to_instance :bar # <- define explicitly which instance methods
# should be mirrored by the class ones
def bar
puts "bar is called"
end
def baz
puts "baz is called"
end
end
# and then
Foo.bar # => bar is called
Foo.baz # NoMethodError ...
# reopening works too
class Foo
delegate_to_instance :baz
end
Foo.baz # baz is called
Pros:
you don't need to redefine method_missing (less magic -> less pain when you debug the code)
you control precisely which instance methods to be wrapped with the class level "shorthand" (fewer chances to delegate something you don't want to - more robust code)
(minor) no need to raise NoMethodError explicitly - you can fully rely on the core dispatching as it is...
I found another solution instead of using a module,
I can use the class method self.method_missing
def self.method_missing(method_name, *args, &block)
obj = new(*args)
raise NoMethodError, "undefined method `#{method_name}' for #{self}:Class" unless obj.respond_to?(method_name)
obj.send(method_name, &block)
end
But the limitation is that I have to copy it into every class whenever I need to use this feature

Evaluate code with access to context of passed in block

I want to be able to do something like this:
def do_stuff(parameter)
raise StandardError
end
def foo(parameter)
rescuer { do_stuff(parameter) }
end
def rescuer
begin
yield # evaluate passed block
rescue StandardError
puts parameter # evaluate this with having access to `parameter` from block
end
end
foo('bar')
#=> bar
What's the least hacky way of achieving this?
There's a kind of messy way to do this that's highly situational, but this works in this narrow case:
def rescuer(&block)
begin
yield
rescue StandardError
p block.binding.local_variable_get(:parameter)
end
end
The binding on the block gives you access to any/all local variables that happen to be defined.

How could I implement something like Rails' before_initialize/before_new in plain Ruby?

In Rails we can define a class like:
class Test < ActiveRecord::Base
before_initialize :method
end
and when calling Test.new, method() will be called on the instance. I'm trying to learn more about Ruby and class methods like this, but I'm having trouble trying to implement this in plain Ruby.
Here's what I have so far:
class LameAR
def self.before_initialize(*args, &block)
# somehow store the symbols or block to be called on init
end
def new(*args)
## Call methods/blocks here
super(*args)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end
I'm trying to figure out where to store the blocks in self.before_initialize. I originally tried an instance variable like #before_init_methods, but that instance variable wouldn't exist in memory at that point, so I couldn't store or retrieve from it. I'm not sure how/where could I store these blocks/procs/symbols during the class definition, to later be called inside of new.
How could I implement this? (Either having before_initialize take a block/proc/list of symbols, I don't mind at this point, just trying to understand the concept)
For a comprehensive description, you can always check the Rails source; it is itself implemented in 'plain Ruby', after all. (But it handles lots of edge cases, so it's not great for getting a quick overview.)
The quick version is:
module MyCallbacks
def self.included(klass)
klass.extend(ClassMethods) # we don't have ActiveSupport::Concern either
end
module ClassMethods
def initialize_callbacks
#callbacks ||= []
end
def before_initialize(&block)
initialize_callbacks << block
end
end
def initialize(*)
self.class.initialize_callbacks.each do |callback|
instance_eval(&callback)
end
super
end
end
class Tester
include MyCallbacks
before_initialize { puts "hello world" }
end
Tester.new
Left to the reader:
arguments
calling methods by name
inheritance
callbacks aborting a call and supplying the return value
"around" callbacks that wrap the original invocation
conditional callbacks (:if / :unless)
subclasses selectively overriding/skipping callbacks
inserting new callbacks elsewhere in the sequence
... but eliding all of those is what [hopefully] makes this implementation more approachable.
One way would be by overriding Class#new:
class LameAR
def self.before_initialize(*symbols_or_callables, &block)
#before_init_methods ||= []
#before_init_methods.concat(symbols_or_callables)
#before_init_methods << block if block
nil
end
def self.new(*args, &block)
obj = allocate
#before_init_methods.each do |symbol_or_callable|
if symbol_or_callable.is_a?(Symbol)
obj.public_send(symbol_or_callable)
else
symbol_or_callable.(obj)
end
end
obj.__send__(:initialize, *args, &block)
end
end
class Tester < LameAR
before_initialize :do_stuff
def do_stuff
puts "DOING STUFF!!"
end
end

I created a DSL to define factories in ruby. Is there a better way to do it?

I have ruby application and I want to implement a DSL to define Factories. Factories are classes that instantiates some object, execute some logic in the process, perform some validations and execute some callbacks depending on the results (succeeded or failed):
f = Factory.new
f.create(foo: :bar) do |on|
on.success { puts 'hey from success action callback' }
on.failure { puts 'hey from failure action callback' }
end
Ok, this is not that hard to do, but I also want to stop the create method right after the method fails or succeeds, something like:
def create(options = {})
# some logic
failed! # this method stops execution and yields the callback object
puts "you'll never see this"
end
What I came up with is this: https://gist.github.com/esdras/631a04769f24856c6d7f
See a partial version below:
require 'fiber'
class Factory
class Callbacks
# omitted some code here, this class is basically a container for
# success and failure callbacks
end
def failed!
#callbacks.failed!
resume_context
end
def succeeded!
#callbacks.succeeded!
resume_context
end
def resume_context ; Fiber.yield ; end
def self.handle(name, &method_body)
define_method "__original_#{name}__", &method_body
define_method name do |*args, &block|
#callbacks = Callbacks.new(self, block)
Fiber.new { send("__original_#{name}__", *args) }.resume
#callbacks
end
end
handle :create do |options = {}|
puts options.inspect
puts "in create"
succeeded!
puts 'after succeeded, never reached here'
end
end
As you can see the class method handle defines two methods: __original_create__ and create which wraps __original_create__ in a Fiber to make it possible to stop execution immediately and execute the callbacks. My question is: Is there a better way to do this? Without creating that __original_create__ method or even without using Fibers?
I already tried this:
def self.handle(name, &method_body)
define_method name do |*args, &block|
#callbacks = Callbacks.new(self, block)
Fiber.new { method_body.call *args }.resume
# above method_body is evaluated in the context of the class.
#callbacks
end
end
but method_body is evaluated in the context of the class, not the instance:
I also tried to instance_eval the method_body like this:
def self.handle(name, &method_body)
define_method name do |*args, &block|
#callbacks = Callbacks.new(self, block)
Fiber.new { instance_eval &method_body }.resume
# above we lost the parameters defined by the handle method
#callbacks
end
end
but I lost the reference to the parameters defined by:
handle :create do |param1, param2|
# method body
end
The only way I found is defining a method with the block passed to the handle method and after defining a wrapper method that calls the original method, like I did above with __original_create__. I'm not ok with defining an extra method, there got to be another way to do this. :(
Any insights would be appreciated.
I'm not sure what you need the Fiber for, so I will leave it, but you need is instance_exec
def self.handle(name, &method_body)
define_method name do |*args, &block|
#callbacks = Callbacks.new(self, block)
Fiber.new { instance_exec *args, &method_body }.resume
# above we lost the parameters defined by the handle method
#callbacks
end
end
One way to do it is to use throw and catch.
def create(options = {})
case catch(:result) do
throw :result, :success if ...
throw :result, :error if ...
end
when :success then ...
when :error then ...
end
end

calling another method in super class in ruby

class A
def a
puts 'in #a'
end
end
class B < A
def a
b()
end
def b
# here i want to call A#a.
end
end
class B < A
alias :super_a :a
def a
b()
end
def b
super_a()
end
end
There's no nice way to do it, but you can do A.instance_method(:a).bind(self).call, which will work, but is ugly.
You could even define your own method in Object to act like super in java:
class SuperProxy
def initialize(obj)
#obj = obj
end
def method_missing(meth, *args, &blk)
#obj.class.superclass.instance_method(meth).bind(#obj).call(*args, &blk)
end
end
class Object
private
def sup
SuperProxy.new(self)
end
end
class A
def a
puts "In A#a"
end
end
class B<A
def a
end
def b
sup.a
end
end
B.new.b # Prints in A#a
If you don't explicitly need to call A#a from B#b, but rather need to call A#a from B#a, which is effectively what you're doing by way of B#b (unless you're example isn't complete enough to demonstrate why you're calling from B#b, you can just call super from within B#a, just like is sometimes done in initialize methods. I know this is kind of obvious, I just wanted to clarify for any Ruby new-comers that you don't have to alias (specifically this is sometimes called an "around alias") in every case.
class A
def a
# do stuff for A
end
end
class B < A
def a
# do some stuff specific to B
super
# or use super() if you don't want super to pass on any args that method a might have had
# super/super() can also be called first
# it should be noted that some design patterns call for avoiding this construct
# as it creates a tight coupling between the classes. If you control both
# classes, it's not as big a deal, but if the superclass is outside your control
# it could change, w/o you knowing. This is pretty much composition vs inheritance
end
end

Resources