Class: Musa::Clock::DummyClock

Inherits:
Clock show all
Defined in:
lib/musa-dsl/transport/dummy-clock.rb

Overview

Simple clock for testing with fixed tick count or custom condition.

DummyClock is designed for testing and batch processing where automatic execution without external dependencies is desired.

Activation Model

IMPORTANT: Unlike TimerClock, InputMidiClock, and ExternalTickClock, DummyClock activates automatically when transport.start is called. It immediately begins generating ticks without waiting for external signals.

This activation model is appropriate for:

  • Unit testing: No external dependencies, deterministic execution
  • Batch processing: Generate music as fast as possible
  • Fast-forward simulations: Skip real-time delays
  • Deterministic debugging: Predictable tick counts

Modes of Operation

  1. Fixed tick count: Runs for exactly N ticks then stops
  2. Custom condition: Runs while a block returns true

Differences from Other Clocks

DummyClock is the only clock that starts generating ticks immediately upon transport.start. It uses Thread.pass instead of sleep, making execution as fast as possible without real-time constraints.

Examples:

Fixed tick count (automatic activation)

clock = DummyClock.new(100)  # Exactly 100 ticks
transport = Transport.new(clock)
transport.start  # Immediately runs 100 ticks, then stops

Custom condition (automatic activation)

continue = true
clock = DummyClock.new { continue }
transport = Transport.new(clock)

transport.sequencer.at(10) { continue = false }
transport.start  # Immediately begins, stops at tick 10

Testing specific sequences

ticks = 0
clock = DummyClock.new { ticks < 50 || some_condition }
transport.sequencer.every(1) { ticks += 1 }
transport.start  # Immediately runs minimum 50 ticks

See Also:

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ticks = nil, do_log: nil) { ... } ⇒ DummyClock

Note:

Only one of ticks or block should be provided

Creates a new dummy clock with tick limit or condition.

Parameters:

  • ticks (Integer, nil) (defaults to: nil)

    number of ticks to generate (mutually exclusive with block)

  • do_log (Boolean, nil) (defaults to: nil)

    enable logging

Yields:

  • Condition block called each iteration; runs while truthy

Raises:

  • (ArgumentError)

    if both ticks and block are provided



66
67
68
69
70
71
72
73
74
75
76
# File 'lib/musa-dsl/transport/dummy-clock.rb', line 66

def initialize(ticks = nil, do_log: nil, &block)
  do_log ||= false

  super()

  raise ArgumentError, 'Cannot initialize with ticks and block. You can only use one of the parameters.' if ticks && block

  @ticks = ticks
  @do_log = do_log
  @block = block
end

Instance Attribute Details

#blockProc?

Condition block for continuing (can be changed dynamically).

Returns:

  • (Proc, nil)

    the condition block



81
82
83
# File 'lib/musa-dsl/transport/dummy-clock.rb', line 81

def block
  @block
end

#ticksInteger?

Number of ticks remaining (can be changed dynamically).

Returns:

  • (Integer, nil)

    ticks remaining



86
87
88
# File 'lib/musa-dsl/transport/dummy-clock.rb', line 86

def ticks
  @ticks
end

Instance Method Details

#run { ... } ⇒ void

Note:

No real-time delays; runs as fast as possible

This method returns an undefined value.

Runs the clock loop, yielding for each tick.

Calls on_start callbacks, then yields while the condition is true. Uses Thread.pass instead of sleep for fast operation. Calls on_stop callbacks when done.

Yields:

  • Called once per tick



98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/musa-dsl/transport/dummy-clock.rb', line 98

def run
  @on_start.each(&:call)
  @run = true

  while @run && eval_condition
    yield if block_given?

    Thread.pass  # Cooperate with other threads
  end

  @on_stop.each(&:call)
end

#terminatevoid

This method returns an undefined value.

Terminates the clock loop.



114
115
116
# File 'lib/musa-dsl/transport/dummy-clock.rb', line 114

def terminate
  @run = false
end