Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Don't pass block when calling super

Tags:

ruby

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.

like image 425
23tux Avatar asked Jan 16 '18 10:01

23tux


People also ask

What is the difference between super and super () in Ruby?

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.

What does super mean in Ruby?

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.

What does super mean in rails?

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.

What is proc and lambda in Ruby?

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.


1 Answers

It's actually not that obvious. From the documentation we know that:

  • calling super passes all arguments
  • calling super() passes no arguments

What 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)

How does this work?

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)
like image 61
Stefan Avatar answered Oct 28 '22 05:10

Stefan