Reputation: 56
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
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