Block Repeater

A way to repeat a block of code until either a given condition is met or a timeout has been reached

Installation

Add this line to your application's Gemfile:

gem 'block_repeater'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install block_repeater

Usage

Add the repeater and it's methods into a project

include BlockRepeater

In order to maintain parity with existing Repeater implementations you may also need to expose the repeater class itself

Repeater = BlockRepeater::Repeater

Repeat method

This is the preferred way to use the repeater. It requires two blocks, the one to be executed and the one which sets the exit condition. As these are ordinary ruby blocks they can be defined using either { } or do end syntax.

  repeater{ call_database_method }.until{ |result| result.count.positive? }
  repeater do
    call_database_method
  end.until do |result| 
    result.count.positive? 
  end

The repeater also takes two parameters:

  • delay: is how long in seconds the repeater will wait between attempts (defaults to 0.2 seconds)
  • times: is how many attempts the repeater will make before giving up (defaults to 25) ruby repeater(delay: 0.5, times: 10){ call_database_method }.until{ |result| result.count.positive? }

RSpec functionality

An RSpec expectation can be used in the block for the until method. The expectation will be attempted each try, but the exception will only be raised if it has still failed once the number or attempts has been reached.

  repeater do
    call_database_method
  end.until do |result| 
    expect(result.count).to be_positive, raise 'No result returned from databased'
  end

Non predefined condition methods

Very simple conditions can be utilised without using a block. This expects either one or two method names which will be called against the result of repeating the main block. The required format is until_<method name> or until_<method name>_becomes_<method name>.

  repeat{ a_method_which_returns_a_number }.until_positive?
  #Attempts to call the :positive? method on the result of the method call

  repeat{ a_method_which_returns_an_array }.until_count_becomes_positive?
  #Attempts to call :count on the result of the method call, then :positive? on that result

This supports two consecutive method calls, anything more complex should be written out in full in the standard manner.

Direct class usage

It's also possible to directly access the Repeater class which has been left available as to not break existing functionality. It's not recommended to combine this with the non predefined condition method pattern described above.

  Repeater = BlockRepeater::Repeater

  Repeater.new do
    call_database_method
  end.until do |result| 
    expect(result.count).to be_positive, raise 'No result returned from databased'
  end.repeat(delay: 1, times: 5)

In this case any optional arguments (times or delay) must be sent to the method called repeat, which is called after the second block. The repeat method is mandatory to run the repeater when using it in this manner.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.