D. Asyl
D. Asyl

Reputation: 56

Assignment of a return-values of method blocks in ruby

Taking the ruby API documentation explanation for String#each_char, it suggests that one receives a string when invoking this method together with a given block.

each_char {|cstr| block } → str

But when executing this in irb, the output is not as expected and only the string we started out with is returned.

irb(main):001:0> v = "foobar".each_char { |c| c + "." }
=> "foobar"

The problem this causes, is that assigning this method invocation is pretty deceiving, as it doesn't return the expected result, but merely the string we started with:

irb(main):002:0> puts v
foobar
=> nil

Using the break instruction is the only way to return a value from the block during the variable assignment.

irb(main):003:0> v = "foobar".each_char { |c| break c + "." }
=> "f."

Questions:

Why do methods invoked with a block not return the values they calculate? Is this just a special case with this implementation, as I'm sure Array#each does return a new Array. But then again, String#each_byte isn't returning something neither. What is going on here?

What is the most elegant way to assign the processed values from the block? Is monkey patching an option?

Additional infos: I'm using ruby 2.6.3

(Note: I've seen [this question from Ed] but while the conclusion in 2017 was that using the assignment operator leads to syntax errors, ruby clearly doesn't behave like this in the case of Array#each.)

Upvotes: 0

Views: 768

Answers (1)

Oleksandr Holubenko
Oleksandr Holubenko

Reputation: 4440

First of all, #each not return a new array. Each means that it will process each element of an array, but in the end, it will return it's receiver.

To print something from the block you need to use print or puts.

There are a few ways to assign the result of each:

First: using #with_object

=> v = "foobar".each_char.with_object('') { |c, obj| obj << c + '.'  }
=> v
=> "f.o.o.b.a.r."

One more: using #chars and #join

=> v = "foobar".chars.join('.')
=> v
=> "f.o.o.b.a.r"

Upvotes: 1

Related Questions