Search code examples
rubyblockyield

Ruby Koans: blocks and arguments (test_blocks_can_take_arguments)


Ruby Koans has the following exercise in about_blocks.rb:

  def method_with_block_arguments
    yield("Jim")
  end

  def test_blocks_can_take_arguments
    method_with_block_arguments do |argument|
      assert_equal __, argument
    end
  end

I know the answer is assert_equal "Jim", argument, but I'm struggling to understand what is happening. Specifically:

  • Is argument or assert_equal... the block?
  • What is yield doing given that method_with_block_arguments returns "Jim" without yield?

Solution

  • I think some of the above commenters are correct in saying that you currently don't have a very deep understanding of Ruby, but don't let that discourage you. It just takes time to learn. When I was first learning Ruby, the concept of blocks and their syntax did take some time to wrap my head around. Once you get it the syntax is very simple, but you until you reach that point...

    Anywho, this is my attempt to help you out. :)

    argument is a block variable. All the stuff between do and end is the block. assert_equal is just a regular method call, nothing to do with blocks.

    What yield does is the key to understanding how blocks work. What yield does it that it "yields" control to the calling function. You may think of it as a callback. When you say "yield" in the middle of a function, you are essentially saying "in the middle of this function, I want to allow someone else to plug in their code and make decisions about what should happen." If you use yield with no arguments, no data from your method gets passed back to the caller.

    In essence, yield is a way of "yielding" control to somebody else, in this case the caller of your function.

    When you call yield with one or more arguments, you are passing data from the your function back up to the caller. So when you say yield("Jim") you are handing the String "Jim" back to whoever calls method_with_block_arguments.

    Lastly, you have to understand that in Ruby, methods always return the result of whatever was the last expression in a particular method. That's why you usually don't need an explicit return statement.

    For instance, this method will return 42.

    def foo
      42
    end
    

    That's because 42 is a valid expression in Ruby. It's just an identity, but it's valid Ruby, so Ruby just says "okay, you said 42 and that's the last thing in this method declaration. So when people call 'foo' they get 42 back".

    I hope this helps. I think at this point you should assume that you're still pretty early on in terms of your Ruby learning, but you're on the right track investigating blocks. Once you get them you'll understand one of the most powerful parts of Ruby.