Evaluate code with access to context of passed in block - ruby

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.

Related

Rescue on parent method an exception raised in child

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.

What is use of ||= begin....end block in Ruby?

What is the difference between these snippets?
def config
#config ||= begin
if config_exists?
#config = return some value
else
{}
end
end
end
def config
#config ||= method
end
def method
if config_exists?
return some value
else
{}
end
end
I'm confused with the "begin ... end" block. Does it make any difference in the output? If not, then what is the use of the begin ... end block here?
First of all, you need to be aware that a defined method inherently includes the functionality of a begin ... end block.
In the context of exception handling, def method_name ... end is functionally equivalent to begin ... end. Both can include rescue statements for example.
The two blocks of code you have shared are actually identical, and there is no benefit in one over the other ... unless your method is needed in more than one place. In that case, you DRY up your code by putting the logic into a single method and calling it from multiple other places.
In your case, you can even omit the begin ... end block:
#config ||=
if config_exists?
return_some_value
else
{}
end
or, using the ternary if:
#config ||= config_exists? ? return_some_value : {}
Does it make any difference in output?
It could make a difference, because unlike def ... end, an begin ... end block doesn't create a new variable scope.
Here's a contrived example:
def foo
a = 456 # doesn't affect the other a
end
a = 123
b = foo
p a: a, b: b #=> {:a=>123, :b=>456}
Versus:
a = 123
b = begin
a = 456 # overwrites a
end
p a: a, b: b #=> {:a=>456, :b=>456}
Using ||= begin...end allows you to memoize the result of whatever is run in the begin...end. This is useful for caching the result of resource-intensive computation.
The only thing that will happen differently is if an exception is raised. For instance, let's say there is a problem in the config_exists? method call. If it raises an exception in the first example your #config var will be set to {}. In the second example if the same thing happens your program will crash.
As a side note, there is no need for the return keyword here. In fact the example should read as follows. This is assuming that I understand the intent.
def config
#config ||=
begin
if config_exists?
some_value
else
{}
end
rescue
{}
end
end
and
def config
#config ||= method
end
def method
if config_exists?
some_value
else
{}
end
end
Both examples are exactly the same, except if an exception is raised #config will still be set to = some_value in the first example.
Also, it should be noted that nothing will happen if #config already has a value. The ||= operators is the same as:
#config = some_value if #config.nil?
Only set the variable to this value if it is currently nil.
Hope this is helpful and that I am understanding your question correctly.

Yielding a block to a proc (or creating a method that accepts a block from a proc that yields)

I'm currently working on an interface that allows me to wrap arbitrary method calls with a chain of procs. Without going into too much detail, I currently have an interface that accepts something like this:
class Spy
def initialize
#procs = []
end
def wrap(&block)
#procs << block
end
def execute
original_proc = Proc.new { call_original }
#procs.reduce(original_proc) do |memo, p|
Proc.new { p.call &memo }
end.call
end
def call_original
puts 'in the middle'
end
end
spy = Spy.new
spy.wrap do |&block|
puts 'hello'
block.call
end
spy.wrap do |&block|
block.call
puts 'goodbye'
end
spy.execute
What I'd like to do though is remove the |&block| and block.call from my API and use yield instead.
spy.wrap do
puts 'hello'
yield
end
This didn't work and raised a LocalJumpError: no block given (yield) error.
I've also tried creating methods by passing the proc the define_singleton_method in the reduce, but I haven't had any luck.
def execute
original_proc = Proc.new { call_original }
#procs.reduce(original_proc) do |memo, p|
define_singleton_method :hello, &p
Proc.new { singleton_method(:hello).call(&memo) }
end.call
end
Is there another approach I can use? Is there anyway to yield from a Proc or use the Proc to initialize something that can be yielded to?
Using yield in your wrap block does not make much sense unless you passed a block to the caller itself:
def foo
spy.wrap do
puts "executed in wrap from foo"
yield
end
end
If you call foo without a block it will raise the exception since yield can't find a block to execute. But if you pass a block to foo method then it will be invoked:
foo do
puts "foo block"
end
Will output
executed in wrap from foo
foo block
In conclusion I think you misunderstood how yield works and I don't think it is what you want to achieve here.

How to print exception and then keep sequential executing rather than jump to rescue section

I'm practicing the Ruby
I often put the wrong code in my file intentionally
e.g.Abc.hi
And the program will raise error then exit.
So I have to wrapped it with begin with block.
How could I let the wrong code only show the exceptions on the console,
and keep doing the following code without wrapping with begin with block.
Thanks
require 'pry'
module Test
def hi
p "hihi"
end
end
def Test.hello
p "hello"
end
class Abc
include Test
end
abc = Abc.new
begin
Abc.hi
rescue Exception => e
p e
end
binding.pry
You can't do that, because that is the point of exceptions - they break the flow.
If you simply want to see the stack trace at that point, use caller
def a
puts caller
end
def b
a
end
def c
b
end
c()
#=> prog:2:in `a'
#=> prog:5:in `b'
#=> prog:8:in `c'
#=> prog:10:in `<main>'

Why doesn't `block_given?` work in this dynamically-defined method?

When I write methods that take an optional block, I typically use something like
block.call if block_given?
However, in method defined dynamically like the one below, block_given? doesn't seem to work.
class Foo
%w[bar baz].each do |method_name|
define_singleton_method(method_name) do |&block|
puts "Was #{method_name} given a block? #{block_given?}"
puts block.call
end
end
end
Foo.bar { puts 'I am a block' }
The block is called as expected, but block_given? returns false.
Why is this?
Blocks are closures, so they remember local variables (eg method_name). They also remember blocks: yield and block_given? are looking for the block that was active at the time that define_method was called, not the block passed to bar. There wasn't one, so block given returns false.
A better illustration of this is
def create_method
define_singleton_method('foo') do |&block|
puts "Was given a block? #{block_given?}"
puts yield
puts block.call
end
end
create_method {'block passed to create_method'}
foo {'block passed to the created method'}
which outputs
Was given a block? true
block passed to create_method
block passed to the created method

Resources