Module: Frequency

Extended by:
Frequency
Included in:
Frequency
Defined in:
lib/frequency.rb

Overview

A small DSL to execute blocks with controlled probability.

require "frequency"

# Module-function style:
Frequency.sometimes { puts "maybe" }
Frequency.rarely(with_probability: 0.01) { log_sample(event) }
Frequency.normally(with_probability: "24%") { do_thing }

# Or mixin style:
include Frequency
sometimes { puts "maybe" }

Constant Summary collapse

VERSION =
"0.2.0"
Error =

Base error class. Catch this to handle any Frequency-raised error.

Class.new(StandardError)
InvalidProbabilityError =

Raised when the probability value is not a number/string in [0, 1].

Class.new(Error)
DEFAULTS =
{
  normally: 0.75,
  sometimes: 0.50,
  rarely: 0.25
}.freeze
PERCENT_PATTERN =
/\A-?\d+(?:\.\d+)?%\z/

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Class Attribute Details

.randomObject



71
72
73
# File 'lib/frequency.rb', line 71

def random
  @random ||= Random.new
end

Class Method Details

.__run(probability, &block) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



86
87
88
89
90
91
92
93
94
95
# File 'lib/frequency.rb', line 86

def __run(probability, &block)
  return nil unless block

  rate = __coerce(probability)
  unless (0.0..1.0).cover?(rate)
    raise InvalidProbabilityError, "probability must be in [0, 1], got #{rate}"
  end

  block.call if random.rand < rate
end

.with_seed(seed) ⇒ Object

Run a block with a temporarily-seeded RNG, then restore the previous one.

Frequency.with_seed(42) { sometimes { ... } }


77
78
79
80
81
82
83
# File 'lib/frequency.rb', line 77

def with_seed(seed)
  previous = @random
  @random = Random.new(seed)
  yield
ensure
  @random = previous
end

Instance Method Details

#alwaysObject

Always run the block. Returns the block’s value, or nil if no block.



33
34
35
# File 'lib/frequency.rb', line 33

def always
  yield if block_given?
end

#neverObject

Never run the block. Returns nil. Ignores any arguments/block.



38
39
40
# File 'lib/frequency.rb', line 38

def never(*)
  nil
end

#normally(with_probability: DEFAULTS[:normally], &block) ⇒ Object

Run the block ~75% of the time by default.



43
44
45
# File 'lib/frequency.rb', line 43

def normally(with_probability: DEFAULTS[:normally], &block)
  Frequency.__run(with_probability, &block)
end

#rarely(with_probability: DEFAULTS[:rarely], &block) ⇒ Object

Run the block ~25% of the time by default.



56
57
58
# File 'lib/frequency.rb', line 56

def rarely(with_probability: DEFAULTS[:rarely], &block)
  Frequency.__run(with_probability, &block)
end

#sometimes(with_probability: DEFAULTS[:sometimes], &block) ⇒ Object Also known as: maybe

Run the block ~50% of the time by default.



48
49
50
# File 'lib/frequency.rb', line 48

def sometimes(with_probability: DEFAULTS[:sometimes], &block)
  Frequency.__run(with_probability, &block)
end