I needed to iterate a block on a value n times and return the value to solve a kata. Getting f(f(..f(x)..)) applying f n times. This is the trivial solution:
n.times do
x = f.call(x)
end
return x
As times returns n rather than anything in the block a separate return x is needed after the block. Also x = modified x is needed. Wouldn't it be nice to have something built in for this purpose? like
x.modify(n, &block)
It turns out that we can achieve something pretty close to this with the built in inject
. As times
without a block returns an Enumerator
, as most Enumerable
functions do, (yielding increasing numbers), with the daisy chaining of Enumerables, using only the accumulator of inject this works fine:
n.times.inject(x) { |x| block.call(x) }
However this doesn't work :( as inject in this case feeds in the index:
n.times.inject(x, &block)
class Object
def modify(n)
return to_enum :modify unless block_given?
case n
when Enumerator then n.each.inject(self) { |acc| yield(acc) }
when Numeric then n.times.inject(self) { |acc| yield(acc) }
end
end
end
p 5.modify 2.times, &:~@ # flipping bits twice
describe "Solution" do
it "should test for something" do
Test.assert_equals(3.times.inject('a') { |x| x * 2 }, 'aaaaaaaa', "duplicating 'a' 3 times")
Test.assert_equals('a'.modify(3) { |x| x * 2 }, 'aaaaaaaa', "duplicating 'a' 3 times")
Test.assert_equals(5.modify(2, &:~@), 5, 'flipping the bits twice returns the same')
# and now the cool DSL bit :
Test.assert_equals((5.modify 2.times, &:~@), 5, 'flipping the bits twice returns the same')
end
end