Class: RubynCode::CLI::LoopRunner
- Inherits:
-
Object
- Object
- RubynCode::CLI::LoopRunner
- Defined in:
- lib/rubyn_code/cli/loop_runner.rb
Overview
Drives a repeating execution of a payload (a prompt or slash command).
Pure orchestration with injected dependencies so it can be unit-tested without a REPL: the caller supplies a ‘runner` callable that performs one iteration and a `sleeper` for the wait between iterations.
Two modes:
- interval mode (interval is a positive number of seconds): run, wait,
run, ... until max_iterations or stopped.
- self-paced mode (interval is nil): run back-to-back until the runner
returns :stop, emits the DONE_SENTINEL, or max_iterations is hit.
Constant Summary collapse
- DEFAULT_MAX_ITERATIONS =
50- DONE_SENTINEL =
'LOOP_DONE'- UNITS =
{ 's' => 1, 'm' => 60, 'h' => 3600 }.freeze
Class Method Summary collapse
-
.parse_interval(token) ⇒ Integer?
Parse an interval token like “30s”, “5m”, “2h”, or a bare “45” (seconds).
Instance Method Summary collapse
-
#initialize(runner:, interval: nil, max_iterations: DEFAULT_MAX_ITERATIONS, sleeper: nil, on_iteration: nil) ⇒ LoopRunner
constructor
A new instance of LoopRunner.
-
#run ⇒ Integer
Run the loop.
-
#stop! ⇒ void
Request the loop to stop after the current iteration.
- #stopped? ⇒ Boolean
Constructor Details
#initialize(runner:, interval: nil, max_iterations: DEFAULT_MAX_ITERATIONS, sleeper: nil, on_iteration: nil) ⇒ LoopRunner
Returns a new instance of LoopRunner.
43 44 45 46 47 48 49 50 51 |
# File 'lib/rubyn_code/cli/loop_runner.rb', line 43 def initialize(runner:, interval: nil, max_iterations: DEFAULT_MAX_ITERATIONS, sleeper: nil, on_iteration: nil) @interval = interval @runner = runner @max_iterations = max_iterations @sleeper = sleeper || ->(seconds) { sleep(seconds) } @on_iteration = on_iteration @stopped = false end |
Class Method Details
.parse_interval(token) ⇒ Integer?
Parse an interval token like “30s”, “5m”, “2h”, or a bare “45” (seconds). Returns nil when the token is not a valid interval.
26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/rubyn_code/cli/loop_runner.rb', line 26 def self.parse_interval(token) return nil if token.nil? match = token.strip.match(/\A(\d+)\s*([smh]?)\z/i) return nil unless match amount = match[1].to_i return nil if amount <= 0 amount * UNITS.fetch(match[2].downcase, 1) end |
Instance Method Details
#run ⇒ Integer
Run the loop.
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/rubyn_code/cli/loop_runner.rb', line 65 def run completed = 0 @max_iterations.times do |index| break if @stopped @on_iteration&.call(index + 1, @max_iterations) result = @runner.call(index) completed += 1 break if @stopped || done?(result) wait_before_next(index) end completed rescue Interrupt completed end |
#stop! ⇒ void
This method returns an undefined value.
Request the loop to stop after the current iteration.
55 56 57 |
# File 'lib/rubyn_code/cli/loop_runner.rb', line 55 def stop! @stopped = true end |
#stopped? ⇒ Boolean
60 |
# File 'lib/rubyn_code/cli/loop_runner.rb', line 60 def stopped? = @stopped |