Reputation: 97
The prompt:
Extend the Array class to include a method named my_each
that takes a block, calls the block on every element of the array, and then returns the original array.
class Array
def my_each(&prc)
if block_given?
proc.call(self)
else
for i in (0..self.length-1)
puts self[i]
end
end
self
end
end
This is what I put together and I don't have a good understanding of how Blocks/Procs work within this context, but somehow I magically wrote the code that passed 3 of the 4 RSPEC tests.
describe "#my_each" do
it "calls the block passed to it" do
expect do |block|
["test array"].my_each(&block)
end.to yield_control.once
end
it "yields each element to the block" do
expect do |block|
["el1", "el2"].my_each(&block)
end.to yield_successive_args("el1", "el2")
end
it "does NOT call the built-in #each method" do
original_array = ["original array"]
expect(original_array).not_to receive(:each)
original_array.my_each {}
end
it "is chainable and returns the original array" do
original_array = ["original array"]
expect(original_array.my_each {}).to eq(original_array)
end
end
All of the above RSPEC tests passes with the exception of the second one, where my code returns [["el1", "el2"]] when ["el1", "el2"] is expected. Can someone please give me an explanation of how or why I am receiving a nested array here?
Can someone also give me an explanation of how the code is running as a block is passing through this method? I'm not sure if my "else" condition is actually even necessary in the context of the RSPEC tests. I'm generally confused by the concept of passing blocks through self-written methods and how they interact with the method itself.
Thanks in advance!
Upvotes: 0
Views: 172
Reputation: 23327
In the first part of your condition, you pass the whole array to the block:
if block_given?
proc.call(self)
else
# ...
E.g. for an array of ["el1", "el2"]
you do proc.call(["el1", "el2"])
. What you expect in the test are two consecutive calls:
proc.call("el1")
proc.call("el2")
To do that you need to use a loop also in the first part of the condition and pass there an array element, not the whole array:
if block_given?
for i in (0..self.length-1)
proc.call(self[i])
end
else
for i in (0..self.length-1)
puts self[i]
end
end
Upvotes: 3
Reputation: 80065
proc.call(self)
is the culprit. self
is the whole array.
Extend the Array class to include a method named my_each
class Array
def my_each
end
end
that takes a block,
#every method in ruby accepts a block, it is just ignored when not used (yielded to). Do nothing.
calls the block on every element of the array,
class Array
def my_each
for element in self
yield element
end
end
end
and then returns the original array.
# "for" loops do this. Do nothing. It should pass.
Upvotes: 0