class Timeloop

Execute a block of code periodically. The runtime of the block is taken in to account so a delay in one run does not impact the start times of future runs.

Constants

NULL_LOGGER

Useful to avoid conditionals in logging code.

VERSION

Attributes

logger[R]
max[R]
period[R]

Public Class Methods

new(opts) click to toggle source

Initialize a new Timeloop object.

Options

period  - seconds or name of time period (eg, 'second', 'hour')
          between iterations
max     - the maximum number of executions of the block. Default:
          INFINITY
maximum - synonym of `max`
logger  - logger to which debugging info should be sent. Default:
          no logging
# File lib/timeloop.rb, line 47
def initialize(opts)
  @period = parse_frequency(opts.fetch(:period))
  @max    = parse_maximum_value(opts.fetch(:maximum){opts.fetch(:max, Float::INFINITY)})
  @logger = opts.fetch(:logger) { NULL_LOGGER }
end

Public Instance Methods

loop() { |i| ... } click to toggle source

Runs provided block periodically.

Yields Integer index of the iteration to the provide block every `period`.

Calls superclass method
# File lib/timeloop.rb, line 11
def loop
  i = -1
  super() do
    run_started_at = Time.now
    i += 1
    logger.debug("#{to_s}: starting #{i}th run")
    yield(i) if block_given?

    break if i+1 >= max

    sleep til_next_start_time(Time.now - run_started_at)
           .tap{|s| logger.debug "#{to_s}: sleeping #{s} seconds until next run" }
  end
end
to_s() click to toggle source

Returns string representation of self,

# File lib/timeloop.rb, line 27
def to_s
  ["#<Timeloop period=#{period}",
   max < Float::INFINITY ? ", max=#{max}" : "",
   ">"].join
end

Protected Instance Methods

parse_frequency(frequency) click to toggle source
# File lib/timeloop.rb, line 68
def parse_frequency(frequency)
  case frequency
  when Numeric
    frequency
  when :second, 'second'
    1.second
  when :minute, 'minute'
    1.minute
  when :hour, 'hour'
    1.hour
  when :day, 'day'
    1.day
  when :month, 'month'
    1.month
  when :year, 'year'
    1.year
  else
    fail ArgumentError.new('wrong type of argument (should be a Numeric, Symbol or String)')
  end
end
parse_maximum_value(maximum) click to toggle source
# File lib/timeloop.rb, line 57
def parse_maximum_value(maximum)
  case maximum
  when Enumerator
    maximum.count
  when Integer, Float::INFINITY
    maximum
  else
    fail ArgumentError.new('wrong type of argument (should be an Enumerator or Integer)')
  end
end
til_next_start_time(current_run_duration) click to toggle source
# File lib/timeloop.rb, line 53
def til_next_start_time(current_run_duration)
  [0, period - current_run_duration].max
end