Search code examples
rubyloopsyieldblock

How do I run a block of test code more than once?


I'm building the Test-First-Teaching performance_monitor and can get to the fifth test but then it fails.

Why is my block only running once?

This is my code:

require "time"
t = Time.now
def measure x=0
start = Time.now
    yield x 
endt = Time.now - start
    end
measure(4){ |x| x.times do Time.now - t end}

This is the error:

*Error____
Performance Monitor
  takes about 0 seconds to run an empty block
  takes exactly 0 seconds to run an empty block (with stubs)
  takes about 1 second to run a block that sleeps for 1 second
  takes exactly 1 second to run a block that sleeps for 1 second (with stubs)
  runs a block N times (FAILED - 1)

Failures:

  1) Performance Monitor runs a block N times
     Failure/Error: n.should == 4
       expected: 4
            got: 1 (using ==)

Solution

  • Think about it like this: Your measure method is the one that's in charge of making sure the block that gets passed to it is run the correct number of times. So the block you pass to measure should only include the code that should be run in a single iteration.

    For a bare-bones example (theme shamelessly ripped from Gary Bernhardt's "WAT" talk):

    def repeat_x_times(x)
        # This runs the passed block x times:
        x.times do
            yield
        end
    end
    
    repeat_x_times(16) do
        # This is what should happen in a single iteration:
        puts 0.0 / 0.0
    end
    
    puts 'Batman!'
    

    The other cool thing about blocks is that you can always access the variables in the same scope as the block (usually local variables), regardless of where the yield happens:

    i = 3
    4.times {i += 1} # We can still get to i!
    puts i           # Prints "7"
    

    Combining the two concepts for a slightly more involved example:

    array = [3, 6, 9, 12, 15]
    sum = 0
    array.each do |item|
        # In the first iteration, item is 3; in the second it's 6, and so on:
        sum += item
    end
    puts sum
    

    Now, I know I haven't answered your question directly, but it sounds like you're learning Ruby, so hopefully this is more useful than a cut-n-paste... Anyway, just play around with this until you get it, and pretty soon you'll be wishing all languages had such a useful feature!