Ruby Koans: blocks and arguments (test_blocks_can_take_arguments) - ruby

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?

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.

Is argument or assert_equal... the block?
No, neither argument nor assert_equal is a block, argument is the variable and anything between do and end is the block. assert_equal is a normal method call.
What is yield doing given that method_with_block_arguments returns "Jim" without yield?
Yield is what makes it special. It calls the block (ie. everything between do and end) and executes it. "Jim" is the argument to the block.
Here is a gist that I copied from Paul while I was learning ruby. That should help in learning about closures in ruby.

Related

What is this Rspec syntax exactly asking for?

TL;DR I am going to a bootcamp next year and one their assessments to get in is learning ruby. I have a background in JS and am very new to ruby. I have this assessment in which case I am not familiar with what the test wants me to do. Below is the test case(Rspec) and right below that is my answer.
describe "some silly block functions" do
describe "reverser" do
it "reverses the string returned by the default block" do
result = reverser do
"hello"
end
expect(result).to eq("olleh")
end
it "reverses each word in the string returned by the default block" do
result = reverser do
"hello dolly"
end
expect(result).to eq("olleh yllod")
end
end
This is my answer code:
def reverser sentence
words = sentence.split(" ")
result = []
words.length.times do |i|
result.push(yield(words[i]))
end
result.join(" ")
end
reverser("hello dolly") {|n| n.reverse} #=> 'olleh yllod'
As I mentioned above I am new to ruby and the idea of yielding is like a callback function for JS. I am having a hard time figuring out what expected code the test case wants me to write. It says that 'it reverses each word in the string returned by the default block' from the statement I just created a block outside of the function where the words are being reversed. I appreciate the help and guidance from whoever can give advice.
This is really more about TDD than about Ruby. The approach would be much the same in any other language as well.
The point of TDD is to write the simplest test that could possibly fail, and then write the simplest code that could possibly change the error message. Step #1 is already provided to you in this example, so this is really about step #2: write the simplest code that could possibly change the message.
Let's run the tests! The message says:
NoMethodError:
undefined method `reverser' …
What's the simplest code that could possibly change a message that says a method doesn't exist? Well, make the method exist, of course!
def reverser; end
Now, the message is:
expected: "olleh"
got: nil
Okay, so it expected us to return the string 'olleh', but we actually returned nil. That's easy:
def reverser; 'olleh' end
Great! The first test passes. But the second still fails. It says:
expected: "olleh yllod"
got: "olleh"
Hmm … apparently, it is not enough to just return something statically. We have to return something different every time. The obvious source would be an argument, but our method doesn't have any parameters. Or does it? Yes! In Ruby, all methods have an implicit block parameter! You can evaluate it using the yield keyword, so let's try that:
def reverser; yield end
Damn! We're back to two errors! That was a step backwards. Or was it? Let's look at the first error message:
expected: "olleh"
got: "hello"
Do you notice something? The expected value is exactly the reverse of the value we are currently returning. So, all we need to do is reverse the return value:
def reverser; yield.reverse end
Hooray! We're back to 1 error:
expected: "olleh yllod"
got: "yllod olleh"
Again, can you spot what is happening? The order of the words is reversed! We need to separate the words and then reverse them, then put them back together:
def reverser; yield.reverse.split.reverse.join end
So close!
expected: "olleh yllod"
got: "ollehyllod"
We just need to put the space back in:
def reverser; yield.reverse.split.reverse.join(' ') end
Yippieh!
2 examples, 0 failures
The important thing is: at no point did we actually have to think. Every step of the way, the tests told us what to do, what to do next, and when we were done. That's what TDD is about: the tests drive the development.
I think the point of the question should be to explain about RSpec and TDD if you're going on a bootcamp. I think giving you the answer to the problem is only part of what you need to know in this case. So...
One of the principles of TDD is to write the least amount of code to get the tests to pass. If I go back to the start.
You have written a reverser method that takes sentence as an argument:
def reverser sentence
'olleh'
end
Run the test and the test should fail with an error: wrong number of arguments. Remove the argument and try that and run RSpec again:
def reverser
'olleh'
end
The first test should pass, but it will fail the second test as we've hard coded the return value of olleh. Clearly it's no good returning a hard coded value — it just helped the test to pass — so I need to figure out how to yield a return value.
def reverser
yield.reverse
end
And this perhaps will get the second test to pass...
This is the guiding principle of TDD, take small steps and get your code to pass. Once it's passing then go back and refactor and improve your code.
As you probably know already TDD is invaluable for writing good quality code - it makes writing code fun, it helps with refactoring.
I found a page with some resources and I would recommend codeschool but they've retired their course which is a pity but there is a PluralSight TDD course that might be useful and also there is a Udemy course on TDD that might be useful too in giving you a head start.
yield means "execute the code inside the block and give me the result". Your reverser method can be simply written like this:
def reverser
yield.split.map(&:reverse).join(' ') if block_given?
end
result = reverser do
'hello world'
end
puts result
# => olleh dlrow
Ruby automatically returns the last thing called as the return value, so the return value of the block given to reverser is hello world which is what will be assigned to yield.
You could check the documentation for block_given? here. Take a look at this answer for deeper explanation of blocks

Turning Procs into Block confusion

I understand that we use the ampersand in front of the method's argument in order to avoid using yield, which would output an error if it doesn't find a block in its way.
However, I've seen that sometimes we use the & in front of the argumenent when we call a method, in order to transform the proc back into a block. It eventually happens that there are 2 ampersands, one for turning blocks into procs, and the second for the opposite.
How's that?! When do we need to put the ampersand to getting back a block from a proc, and why?
I hope I've been clear, beacause not being english mother tongue could make harsh to pose difficult questions for me.
Example
I took this example from the slides of CodeSchool, which can be found on http://courseware.codeschool.com/ruby_bits_2/ruby_bits_2_level_1.pdf.
class Timeline
attr_accessor :tweets
def each(&block)
tweets.each(&block)
end
end
I understand that we use the ampersand in front of the method's
argument in order to avoid using yield, which would output an error if
it doesn't find a block in its way.
Your understanding is wrong.
You use &block as the last argument to capture the block into a Proc, in particular to store it and use it later on. When calling a method, &block does the reverse, i.e. specifies that the block corresponds to the given block. This is the same idea as def foo(*args) and foo(*args).
The example you gave is basically equivalent to:
def each
tweets.each{|t| yield y}
end
As Yehuda Katz explains at the end of this talk, you should think of a "block" as a Proc with a special argument position and a dedicated syntax to specify it.
It's common to use them together. This is the case because blocks can't be used as parameters, while procs can. So if you need to use the block as a parameter within the method's body, you must turn it into a proc.
Within that method, you might want to pass the proc to another method that only accepts a block, so you have to do the conversion once again.
For example:
def each(&block) # block to proc
posts.each(&block) # proc to block
end

DSL block without argument in ruby

I'm writing a simple dsl in ruby. Few weeks ago I stumbled upon some blog post, which show how to transform code like:
some_method argument do |book|
book.some_method_on_book
book.some_other_method_on_book :with => argument
end
into cleaner code:
some_method argument do
some_method_on_book
some_other_method_on_book :with => argument
end
I can't remember how to do this and I'm not sure about downsides but cleaner syntax is tempting. Does anyone have a clue about this transformation?
def some_method argument, &blk
#...
book.instance_eval &blk
#...
end
UPDATE: However, that omits book but don't let you use the argument. To use it transparently you must transport it someway. I suggest to do it on book itself:
class Book
attr_accessor :argument
end
def some_method argument, &blk
#...
book.argument = argument
book.instance_eval &blk
#...
end
some_method 'argument' do
some_method_on_book
some_other_method_on_book argument
end
Take a look at this article http://www.dan-manges.com/blog/ruby-dsls-instance-eval-with-delegation — there is an overview of the method (specifically stated in the context of its downsides and possible solution to them), plus there're several useful links for further reading.
Basically, it's about using instance_eval to execute the block in the desirable context.
Speaking about downside of this technique:
So what's the problem with it? Well, the problem is that blocks are
generally closures. And you expect them to actually be full closures.
And it's not obvious from the point where you write the block that
that block might not be a full closure. That's what happens when you
use instance_eval: you reset the self of that block into something
else - this means that the block is still a closure over all local
variables outside the block, but NOT for method calls. I don't even
know if constant lookup is changed or not.
Using instance_eval changes the rules for the language in a way that
is not obvious when reading a block. You need to think an extra step
to figure out exactly why a method call that you can lexically see
around the block can actually not be called from inside of the block.
Check out the docile gem. It takes care of all the sharp edges, making this very easy for you.

When does Ruby know that a method exists?

One question that ran through my mind was how does the Ruby interpreter know that a method exists on a object if the definition is yet to be interpreted? Like, wouldn't it matter whether you define the method first than use it, rather than use it then define it?
It doesn't know, and it doesn't care - until execution. When a method call statement is executed, the interpreter looks to see if the class (object, not code!) has the named function. If it does not, it looks up the ancestor tree. If it does not find any, it calls the method_missing method. If that is not defined, you get your error.
If your function call does not get executed, you will not get any errors.
The interpreter doesn't know about undefined methods ahead of time, for example:
o = Object.new
o.foo # => Raises NoMethodError.
class Object
def foo
puts "Foo!"
end
end
o.foo # => prints "Foo!", since the method is defined.
However, Ruby has a neat feature called method_missing which let's the receiver of a method call take the method name and arguments as separate arguments and handle accordingly as long as no defined method already handles the call.
def o.method_missing(sym, *args)
puts "OK: #{sym}(#{args.inspect})"
# Do something depending on the value of 'sym' and args...
end
o.bar(1, 2, 3) #=> OK: bar(1, 2, 3)
"Method missing" is used by things like active record find methods and other places where it could make sense to have "dynamically defined" functions.
The problem is, the interpreter tried to find it when you use it, and since it won't be there, it may fail.
In ( some ) compiled languages, it doesn't matter, because while compiling, the compiler may say "I'll look for this on a second pass" but I don't think this is the case with Ruby.

Ruby's yield feature in relation to computer science

I recently discovered Ruby's blocks and yielding features, and I was wondering: where does this fit in terms of computer science theory? Is it a functional programming technique, or something more specific?
Ruby's yield is not an iterator like in C# and Python. yield itself is actually a really simple concept once you understand how blocks work in Ruby.
Yes, blocks are a functional programming feature, even though Ruby is not properly a functional language. In fact, Ruby uses the method lambda to create block objects, which is borrowed from Lisp's syntax for creating anonymous functions — which is what blocks are. From a computer science standpoint, Ruby's blocks (and Lisp's lambda functions) are closures. In Ruby, methods usually take only one block. (You can pass more, but it's awkward.)
The yield keyword in Ruby is just a way of calling a block that's been given to a method. These two examples are equivalent:
def with_log
output = yield # We're calling our block here with yield
puts "Returned value is #{output}"
end
def with_log(&stuff_to_do) # the & tells Ruby to convert into
# an object without calling lambda
output = stuff_to_do.call # We're explicitly calling the block here
puts "Returned value is #{output}"
end
In the first case, we're just assuming there's a block and say to call it. In the other, Ruby wraps the block in an object and passes it as an argument. The first is more efficient and readable, but they're effectively the same. You'd call either one like this:
with_log do
a = 5
other_num = gets.to_i
#my_var = a + other_num
end
And it would print the value that wound up getting assigned to #my_var. (OK, so that's a completely stupid function, but I think you get the idea.)
Blocks are used for a lot of things in Ruby. Almost every place you'd use a loop in a language like Java, it's replaced in Ruby with methods that take blocks. For example,
[1,2,3].each {|value| print value} # prints "123"
[1,2,3].map {|value| 2**value} # returns [2, 4, 8]
[1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]
As Andrew noted, it's also commonly used for opening files and many other places. Basically anytime you have a standard function that could use some custom logic (like sorting an array or processing a file), you'll use a block. There are other uses too, but this answer is already so long I'm afraid it will cause heart attacks in readers with weaker constitutions. Hopefully this clears up the confusion on this topic.
There's more to yield and blocks than mere looping.
The series Enumerating enumerable has a series of things you can do with enumerations, such as asking if a statement is true for any member of a group, or if it's true for all the members, or searching for any or all members meeting a certain condition.
Blocks are also useful for variable scope. Rather than merely being convenient, it can help with good design. For example, the code
File.open("filename", "w") do |f|
f.puts "text"
end
ensures that the file stream is closed when you're finished with it, even if an exception occurs, and that the variable is out of scope once you're finished with it.
A casual google didn't come up with a good blog post about blocks and yields in ruby. I don't know why.
Response to comment:
I suspect it gets closed because of the block ending, not because the variable goes out of scope.
My understanding is that nothing special happens when the last variable pointing to an object goes out of scope, apart from that object being eligible for garbage collection. I don't know how to confirm this, though.
I can show that the file object gets closed before it gets garbage collected, which usually doesn't happen immediately. In the following example, you can see that a file object is closed in the second puts statement, but it hasn't been garbage collected.
g = nil
File.open("/dev/null") do |f|
puts f.inspect # #<File:/dev/null>
puts f.object_id # Some number like 70233884832420
g = f
end
puts g.inspect # #<File:/dev/null (closed)>
puts g.object_id # The exact same number as the one printed out above,
# indicating that g points to the exact same object that f pointed to
I think the yield statement originated from the CLU language. I always wonder if the character from Tron was named after CLU too....
I think 'coroutine' is the keyword you're looking for.
E.g. http://en.wikipedia.org/wiki/Yield
Yield in computing and information science:
in computer science, a point of return (and re-entry) of a coroutine

Resources