How can I set a block to nil for the super
call?
class A
def foo
if block_given?
result = yield
# do stuff with the yield result
end
# some more code
end
end
class B < A
def foo
block_result = yield
# process block results and store it
# ...
super
end
end
B.new.foo { puts "block called" }
# => block called
# => block called
I don't want to yield the block twice. Is it somehow possible that block_given?
in class A
returns false?
Background is that I don't own the A
class and I can't change it's foo
method but I want to avoid calling my block twice. I also don't want to pass a dummy / empty block to super, because the behaviour of A
's foo
method changes when a block is given.
When you call super with no arguments, Ruby sends a message to the parent of the current object, asking it to invoke a method with the same name as where you called super from, along with the arguments that were passed to that method. On the other hand, when called with super() , it sends no arguments to the parent.
Ruby uses the super keyword to call the superclass implementation of the current method. Within the body of a method, calls to super acts just like a call to that original method. The search for a method body starts in the superclass of the object that was found to contain the original method.
The function super is used to invoke the original method, searching of the method body starts in the super class of the object that was found to contain the original method.
Blocks are syntactic structures in Ruby; they are not objects, and cannot be manipulated as objects. It is possible, however, to create an object that represents a block. Depending on how the object is created, it is called a proc or a lambda.
It's actually not that obvious. From the documentation we know that:
super
passes all argumentssuper()
passes no argumentsWhat the documentation doesn't say is that this only applies to positional and keyword arguments. super()
still passes a given block!
You have to explicitly unset the block by calling:
super(&nil)
You probably know that you can define a method with an explicit block argument:
def foo(&block)
# ...
end
and that you can pass it as a block to another method: (that other method might be super
)
def foo(&block)
super(&block)
end
Now, if you pass a block when calling the method, the corresponding block
variable will be an instance of Proc
:
def foo(&block)
p block_given: block_given?, block: block
end
foo {}
#=> {:block_given=>true, :block=>#<Proc:0x00007ff4990d0030>}
If you call it without passing block, the block
variable will just be nil
:
foo
#=> {:block_given=>false, :block=>nil}
So if no block is given, block
is nil
and
super(&block)
becomes:
super(&nil)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With