How does Enumerator.new work with block passed? - ruby-on-rails

I struggle a little bit with understanding how the Enumerator.new method works.
Assuming example from documentation:
fib = Enumerator.new do |y|
a = b = 1
loop do
y << a
a, b = b, a + b
end
end
p fib.take(10) # => [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
Where's the loop break condition, how does it know how many times loop should to iterate (as it doesn't have any explicit break condition and looks like infinite loop) ?

Enumerator uses Fibers internally. Your example is equivalent to:
require 'fiber'
fiber = Fiber.new do
a = b = 1
loop do
Fiber.yield a
a, b = b, a + b
end
end
10.times.map { fiber.resume }
#=> [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

Edit I think I understand your question now, I will still keep my original answer below.
y << a is an alias for y.yield(a), which is basically a sleep with return value. Each time a value is requested from the enumerator with next, the execution is continued until another value is yielded.
Enumerators do not need to enumerate a finite number of elements, so they are infinite. For example, fib.to_a will never terminate, because it tries to build an array with an infinite number of elements.
As such, enumerators are great as a representation of infinite series such as the natural numbers, or in your case, the fibonacci numbers. The user of the enumerator can decide how many values it needs, so in your example take(10) determines the break condition if you will.
The break condition itself is in the implementation of Enumerator#take. For demonstration purposes, we can make our own implementation called my_take:
class Enumerator
def my_take(n)
result = []
n.times do
result << self.next
end
result
end
end
Where you could of course "mentally substitute" your n.times loop with your classical C style for (i=0; i<n; i++). There's your break condition. self.next is the method to get the next value of the enumerator, which you can also use outside of the class:
fib.next
#=> 1
fib.next
#=> 1
fib.next
#=> 2
fib.next
#=> 3
That said, you can of course build an enumerator that enumerates a finite number of values, such as the natural numbers in a given range, but that's not the case here. Then, the Enumerator will raise a StopIteration error when you try to call next, but all values already have been enumerated. In that case, you have two break conditions, so to speak; the one that breaks earlier will then win. take actually handles that by rescuing from the error, so the following code is a bit closer to the real implementation (however, take is in fact implemented in C).
class Enumerator
def my_take(n)
result = []
n.times do
result << self.next
end
result
rescue StopIteration
# enumerator stopped early
result
end
end

Related

Can someone help me understand this one line of code?

I'm doing a lab using each and yield
I've almost finished the lab and understand it somewhat just need help full grasping this one line.
yield(collection[i])
def my_collect(array)
i = 0
collect = []
while i < array.length
collect << yield(array[i])
i+=1
end
collect
end
The yield keyword — in association with a block — allows to pass a set of additional instructions during a method invocation.
This mechanism allows you to customise a method depending on your needs.
What’s a block ?
A block is part of the Ruby method syntax.
This means that when a block is recognised by the Ruby parser then it’ll be associated to the invoked method and literally replaces the yields in the method.
I also advise you to replace your while loop with .each
def my_collect(array)
collect = []
array.each { |a| collect << yield(a) }
collect
end
my_collect([1, 2, 3]) { |n| n + 1 } produces -> [2, 3, 4]

what happens when *args is passed to yield in ruby

what happens when *args passed to yield in ruby, in capture_helper.rb of rails I saw a statement where *args is passed to yield statement, what actually happens when we do so.
buffer = with_output_buffer { value = yield(*args) }
where first parameter is builder object and second parameter is the block passed
With the * operator (splat operator) prefixing a variable (which must be an array or hash), the values of the array are extracted:
ary = [1, 2, 3]
def foo(a, b, c)
a + b + c
end
foo(ary)
# => ArgumentError: wrong number of arguments (given 1, expected 3)
foo(*ary)
# 6
It's just the same with yield, except that the values are passed to the block:
def bar
ary2 = [5, 6]
yield(*ary2)
end
bar do |x, y|
puts x + y
end
# 11
Splats have many uses in ruby. When you use a splat in a method call it turns an array into a list of arguments.
def test(*args)
args
end
Consider these examples:
a = [1,2,3]
test(a)
# => [[1, 2, 3]]
test(1,2,3)
# => [1, 2, 3]
test(*a)
# => [1, 2, 3]
In the first example the array is treated as the first argument so the result is an array in an array. While *[1,2,3] de-structures the array so that we get the desired result.
This makes it extremely useful for calling methods that take a variable number of arguments. yield works just like any other method in this regard, as using a splat will de-structure the array in args and call the passed block with a list of arguments.

Ruby (Monkey Patching Array)

Back for more help on my coursework at Bloc. Decided to bring you guys in on a problem I'm having with Monkey Patching the Array Class. This assignment had 8 specs to be met and I'm stuck now with one left and I'm not sure what to do.
I'm only going to give you the RSpecs and written requirements for the part that I'm having trouble w/ since everything else seems to be passing. Also I'll include the starter scaffolding that they gave me to begin with so there's no confusion or useless additions to the code.
Here are the written requirements for the Array Class Monkey Patch:
Write a new new_map method that is called on an instance of the Array class. It should use the array it's called on as an implicit (self) argument, but otherwise behave identically. (INCOMPLETE)
Write a new_select! method that behaves like the select, but mutates the array on which it's called. It can use Ruby's built-in collection select method. (COMPLETE)
Here are the RSpecs that need to be met regarding the Array class:
Note: "returns an array with updated values" Is the only Spec not passing.
describe Array do
describe '#new_map' do
it "returns an array with updated values" do
array = [1,2,3,4]
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
expect( array.new_map{ |e| e + 2 } ).to eq( [3, 4, 5, 6] )
end
it "does not call #map" do
array = [1,2,3,4]
array.stub(:map) { '' }
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
end
it "does not change the original array" do
array = [1,2,3,4]
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
expect( array ).to eq([1,2,3,4])
end
end
describe '#new_select!' do
it "selects according to the block instructions" do
expect( [1,2,3,4].new_select!{ |e| e > 2 } ).to eq( [3,4] )
expect( [1,2,3,4].new_select!{ |e| e < 2 } ).to eq( [1] )
end
it "mutates the original collection" do
array = [1,2,3,4]
array.new_select!(&:even?)
expect(array).to eq([2,4])
end
end
end
Here is the scaffolding they started me with:
class Array
def new_map
end
def new_select!(&block)
end
end
Lastly, here is my code:
class Array
def new_map
new_array = []
self.each do |num|
new_array << num.to_s
end
new_array
end
def new_select!(&block)
self.select!(&block)
end
end
Ruby Array Class:
map { |item| block } → new_ary
A block is like a method, and you specify a block after a method call, for example:
[1, 2, 3].map() {|x| x*2} #<---block
^
|
method call(usually written without the trailing parentheses)
The block is implicitly sent to the method, and inside the method you can call the block with yield.
yield -> calls the block specified after a method call. In ruby, yield is equivalent to yield(), which is conceptually equivalent to calling the block like this: block().
yield(x) -> calls the block specified after a method call sending it the argument x, which is conceptually equivalent to calling the block like this: block(x).
So, here is how you can implement new_map():
class Array
def new_map
result = []
each do |item|
result << yield(item)
end
result
end
end
arr = [1, 2, 3].new_map {|x| x*2}
p arr
--output:--
[2, 4, 6]
This comment is a bit advanced, but you don't actually have to write self.each() to call the each() method inside new_map(). All methods are called by some object, i.e. the object to the left of the dot, which is called the receiver. For instance, when you write:
self.each {....}
self is the receiver of the method call each().
If you do not specify a receiver and just write:
each {....}
...then for the receiver ruby uses whatever object is assigned to the self variable at that moment. Inside new_map() above, ruby will assign the Array that calls the new_map() method to self, so each() will step through the items in that Array.
You have to be a little bit careful with the self variable because ruby constantly changes the value of the self variable without telling you. So, you have to know what ruby has assigned to the self variable at any particular point in your code--which comes with experience. Although, if you ever want to know what object ruby has assigned to self at some particular point in your code, you can simply write:
puts self
Experienced rubyists will crow and cluck their tongues if they see you write self.each {...} inside new_map(), but in my opinion code clarity trumps code trickiness, and because it makes more sense to beginners to write self there, go ahead and do it. When you get a little more experience and want to show off, then you can eliminate explicit receivers when they aren't required. It's sort of the same situation with explicit returns:
def some_method
...
return result
end
and implicit returns:
def some_method
...
result
end
Note that you could write new_map() like this:
class Array
def new_map(&my_block) #capture the block in a variable
result = []
each do |item|
result << my_block.call(item) #call the block
end
result
end
end
arr = [1, 2, 3].new_map {|x| x*2}
p arr
--output:--
[2, 4, 6]
Compare that to the example that uses yield(). When you use yield(), it's as if ruby creates a parameter variable named yield for you in order to capture the block. However, with yield you use a different syntax to call the block, namely (), or if their are no arguments for the block, you can eliminate the parentheses--just like you can when you call a method. On the other hand, when you create your own parameter variable to capture a block, e.g. def new_map(&my_block), you have to use a different syntax to call the block:
my_block.call(arg1, ...)
or:
myblock[arg1, ...]
Note that #2 is just like the syntax for calling a method--except that you substitute [] in place of ().
Once again, experienced rubyists will use yield to call the block instead of capturing the block in a parameter variable. However, there are situations where you will need to capture the block in a parameter variable, e.g. if you want to pass the block to yet another method.
Looking at the spec here:
it "returns an array with updated values" do
array = [1,2,3,4]
expect( array.new_map(&:to_s) ).to eq( %w{1 2 3 4} )
expect( array.new_map{ |e| e + 2 } ).to eq( [3, 4, 5, 6] )
end
It looks like they just want you to re-write Array.map so that it will work with any given block. In your implementation you are telling the method to work in a very specific way, namely to call .to_s on all of the array elements. But you don't want it to always stringify the array elements. You want it to do to each element whatever block is provided when the method is called. Try this:
class Array
def new_map
new_array = []
each do |num|
new_array << yield(num)
end
new_array
end
end
Notice in my example that the method definition doesn't specify any particular operation to be performed on each element of self. It simply loops over each element of the array, yields the element (num) to whatever block was passed when .new_map was called, and shovels the result into the new_array variable.
With that implementation of .new_map and given array = [1,2,3,4], you can call either array.new_map(&:to_s) (the block is where the arbitrary operation to be performed on each element of the array is specified) and get ["1","2","3","4"] or you can call array.new_map { |e| e + 2 } and get [3,4,5,6].
I would like to say a few words about new_select!.
select vs select!
You have:
class Array
def new_select!(&block)
self.select!(&block)
end
end
which you could instead write:
class Array
def new_select!
self.select! { |e| yield(e) }
end
end
This uses the method Array#select!. You said Array#select could be used, but made no mention of select!. If you cannot use select!, you must do something like this:
class Array
def new_select!(&block)
replace(select(&block))
end
end
Let's try it:
a = [1,2,3,4,5]
a.new_select! { |n| n.odd? }
#=> [1, 3, 5]
a #=> [1, 3, 5]
Explicit vs implicit receivers
Notice that I have written this without any explicit receivers for the methods Array#replace and Array#select. When there is no explicit receiver, Ruby assumes that it is self, which is the a. Therefore, Ruby evaluates replace(select(&block)) as though it were written with explicit receivers:
self.replace(self.select(&block))
It's up to you to decide if you want to include self.. Some Rubiests do, some don't. You'll notice that self. is not included in Ruby built-in methods implemented in Ruby. One other thing: self. is required in some situations to avoid ambiguity. For example, if taco= is the setter for an instance variable #taco, you must write self.taco = 7 to tell Ruby you are referring to the setter method. If you write taco = 7, Ruby will assume you want to create a local variable taco and set its value to 7.
Two forms of select!
Is your method new_select! a direct replacement for select!? That is, are the two methods functionally equivalent? If you look at the docs for Array#select!, you will see it has two forms, the one you have mimicked, and another that you have not implemented.
If select! is not given a block, it returns an enumerator. Now why would you want to do that? Suppose you wish to write:
a = [1,2,3,4,5]
a.select!.with_index { |n,i| i < 2 }
#=> [1, 2]
Has select! been given a block? No, so it must return an enumerator, which becomes the receiver of the method Enumerator#with_index.
Let's try it:
enum0 = a.select!
#=> #<Enumerator: [1, 2, 3, 4, 5]:select!>
Now:
enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: [1, 2, 3, 4, 5]:select!>:with_index>
You can think of enum1 as a "compound enumerator". Look carefully at the description (above) of the object Ruby returns when you define enum1.
We can see the elements of the enumerator by converting it to an array:
enum1.to_a
# => [[1, 0], [2, 1], [3, 2], [4, 3], [5, 4]]
Each of these five elements is passed to the block and assigned to the block variables by Enumerator#each (which calls Array#each).
Enough of that, but the point is that having methods return enumerators when no block is given is what allows us to chain methods.
You do not have a test that ensures new_select! returns an enumerator when no block is given, so maybe that's not expected, but why not give it a go?
class Array
def new_select!(&block)
if block_given?
replace(select(&block))
else
to_enum(:new_select!)
end
end
end
Try it:
a = [1,2,3,4,5]
a.new_select! { |n| n.odd? }
#=> [1, 3, 5]
a #=> [1, 3, 5]
a = [1,2,3,4,5]
enum2 = a.new_select!
#=> #<Enumerator: [1, 2, 3, 4, 5]:new_select!>
enum2.each { |n| n.odd? }
#=> [1, 3, 5]
a #=> [1, 3, 5]
a = [1,2,3,4,5]
enum2 = a.new_select!
#=> #<Enumerator: [1, 2, 3, 4, 5]:new_select!>
enum2.with_index.each { |n,i| i>2 }
#=> [4, 5]
a #=> [4, 5]

How to use next with inject in ruby

I was writing some code like following:
[1,2,3,4,5].inject([]) do |res, a|
res << a*a and next if a == 2
res << a
end
It gives following error:
NoMethodError: undefined method `<<' for nil:NilClass
As by next it makes res variable as nil, How to work around this problem?
I tried various ways but couldn't get next to work with ruby, I know this snippet I have provided can be done without next(a == 4 ? res << a*a : res << a), but in my actual use-case I have some complex logic and can't be done that simply.
Replace the
res << a*a and next if a == 2
with
next res << a*a if a == 2
Now, it will work.
Example :-
#!/usr/bin/env ruby
ar = [1,2,3,4,5].inject([]) do |res, a|
next res << a*a if a == 2
res << a
end
p ar
# >> [1, 4, 3, 4, 5]
Read the documentation of next
next can take a value, which will be the value returned for the current iteration of the block....
Ugh. Don't use a trailing conditional for this. Instead it is easily done using a standard if/else:
[1,2,3,4,5].inject([]) do |res, a|
if a == 2
res << a*a
else
res << a
end
end
# => [1, 4, 3, 4, 5]
Any time you feel like you're coding yourself into a corner, don't look for a way out, instead, back up and look at what you're trying to accomplish to see if there is a more straightforward way there.
I'd probably tweak the code a bit more though, for readability. Long term maintenance relies on quickly understanding what is going on, and code that is convoluted or not obvious can take its toll later:
[1,2,3,4,5].inject([]) do |res, a|
if a == 2
res << a*a
else
res << a
end
res # return it for clarity in what the block is returning
end
# => [1, 4, 3, 4, 5]
inject is similar to each_with_object, only it relies on the accumulator being returned at the end of the block, which is why I would add the res at the end of the block for clarity, due to the if block. Switching to each_with_object removes that reliance on the return value of the block, allowing the following code to be more logically clear:
[1,2,3,4,5].each_with_object([]) do |a, ary|
if a == 2
ary << a*a
else
ary << a
end
end
# => [1, 4, 3, 4, 5]
Of course, at that point, the whole thing can be reduced further, and could take advantage of the ternary version using:
[1,2,3,4,5].each_with_object([]) do |a, ary|
a2 = (a == 2) ? a * a : a
ary << a2
end
# => [1, 4, 3, 4, 5]
Which of the above two are more readable is somewhat up to the person coding it and the person responsible for maintaining it. I'd lean toward the non-ternary version because it's more easily extended/expanded and doesn't have the line noise of the ternary ?: chain.
Since it was asked in the comments, map reduces some noise, and is how we should transform an array:
[1,2,3,4,5].map { |a|
(a == 2) ? a * a : a
}
That's untested but it looks correct.

How to do lazy evaluation of Ruby arguments

I have a code to do a check of nil in ruby. So what I want to achieve is this:
for example, if I call get_score_value(nil,(nil-1)). I want ruby to delay the evaluation of nil-1 till it reaches the get_score_value function, instead of evaluate it before it got passed in the function. In another word, I want to pass a mathematical expression as an argument into a method.
What is the most elegant way to do this in ruby? Thanks very much
def get_score_value(value,value2)
value.nil? ? "NULL" : value2.round(2)
end
UPDATE:
I just realized this question is actually related to the topic of lazy and strict evaluation. ( the following is from this great site:
http://www.khelll.com/blog/ruby/ruby-and-functional-programming/
Strict versus lazy evaluation
Strict evaluation always fully evaluates function arguments before invoking the function. Lazy evaluation does not evaluate function arguments unless their values are required to be evaluated. One use of Lazy evaluation is the performance increases due to avoiding unnecessary calculations.
However as the following example shows, Ruby use Strict evaluation strategy:
print length([2+1, 3*2, 1/0, 5-4])
=>ZeroDivisionError: divided by 0
The third parameter of the passed array contains a division by zero operation and as Ruby is doing strict evaluation, the above snippet of code will raise an exception.
You might be interested in using a Proc...
func = Proc.new {|n| n -1 }
def get_score_value(value, proc)
if value.nil?
return proc.call(0)
end
end
p get_score_value(nil, func)
Your proc is like a normal method, it can still test for nil and things like that.
Or, it allows you to provide separate functions to handle those situations:
func1 = Proc.new {|n| n -1 }
func2 = Proc.new { "was nil" }
def check_for_nil(value, funcNil, funcNotNil)
if value.nil?
return funcNil.call()
else
return funcNotNil.call(value)
end
end
p check_for_nil(nil, func2, func1)
p check_for_nil(1, func2, func1)
Also note the potential use of the or keyword in cases when you simply want to convert it to an empty or default type of the input (i.e. use 0 for numbers, [] for arrays, etc.)
def get_score_value(value)
(value or 0).round(2)
end
The Ruby-ish way to do this is to put your expression in your method's block and have the method execute a conditional yield.
def f x
yield if x
end
x = nil
f x do
x - 1
end
You can use a block:
def get_score_value value
value.nil? ? "NULL" : yield
end
x = 1
puts get_score_value(x) { x-1 } #=> 0
x = nil
puts get_score_value(x) { x-1 } #=> "NULL"

Resources