Move History

Fork Selected
  • Description

    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)
    
    Code
    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
    Test Cases
    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