philiprehberger-stopwatch

Tests Gem Version Last updated

Precision stopwatch with lap timing, pause/resume, and formatted output

Requirements

  • Ruby >= 3.1

Installation

Add to your Gemfile:

gem "philiprehberger-stopwatch"

Or install directly:

gem install philiprehberger-stopwatch

Usage

require "philiprehberger/stopwatch"

sw = Philiprehberger::Stopwatch.new
sw.start
# ... do work ...
sw.lap('phase 1')
# ... do more work ...
sw.lap('phase 2')
sw.stop

sw.elapsed  # => 1.234 (seconds)
sw.laps     # => [{name: "phase 1", elapsed: 0.5, split: 0.5}, {name: "phase 2", elapsed: 0.734, split: 1.234}]

Pause and Resume

sw = Philiprehberger::Stopwatch.new
sw.start
sleep(0.1)
sw.pause      # alias for #stop
sw.resume     # alias for #start
sleep(0.1)
sw.stop
sw.elapsed    # => ~0.2 (paused time not counted)

Restart

sw = Philiprehberger::Stopwatch.new
sw.start
sleep(0.1)
sw.lap('phase 1')
sw.restart    # equivalent to #reset followed by #start
sleep(0.05)
sw.elapsed    # => ~0.05 (prior state cleared)

Formatted Output

sw = Philiprehberger::Stopwatch.new
sw.start
sleep(0.5)
sw.formatted_elapsed  # => "500.12ms"

sleep(65)
sw.formatted_elapsed  # => "1m 5s"

Lap Statistics

sw = Philiprehberger::Stopwatch.new
sw.start
sw.lap('setup')
sw.lap('process')
sw.lap('teardown')

sw.lap_stats
# => { count: 3, total: 0.053, avg: 0.018, min: 0.005, max: 0.031 }

sw.formatted_laps
# => [{ name: "setup", elapsed: 0.005, formatted: "5.00ms" }, ...]

Serialization

sw = Philiprehberger::Stopwatch.new
sw.start
sw.lap('setup')
sw.lap('process')
sw.stop

sw.to_h
# => { running: false, paused: true, elapsed: 0.053,
#      formatted_elapsed: "53.00ms", laps: [...], lap_stats: {...} }

Named Checkpoints

sw = Philiprehberger::Stopwatch.new
sw.start
sleep(0.1)
sw.checkpoint('after_setup')
sleep(0.2)
sw.checkpoint('after_process')

sw.elapsed_at('after_setup')    # => ~0.1 (cumulative split at that moment)
sw.elapsed_at('after_process')  # => ~0.3

sw.since('after_setup')         # => ~0.2 (time elapsed since that checkpoint)
sw.since('after_process')       # => ~0.0

sw.checkpoints
# => { "after_setup" => 0.1003, "after_process" => 0.3007 }

Block Timing

result, elapsed = Philiprehberger::Stopwatch.measure { expensive_operation }
puts "Took #{elapsed} seconds"

formatted = Philiprehberger::Stopwatch.measure_formatted { expensive_operation }
puts "Took #{formatted}"  # => "Took 12.50ms"

API

Method Description
Stopwatch.new Create a new stopwatch
#start Start or resume the stopwatch
#stop Pause the stopwatch
#pause Alias for #stop
#resume Alias for #start (resumes a paused stopwatch)
#reset Reset all state
#restart Reset and start the stopwatch in one call
#lap(name) Record a lap with optional name
#elapsed Total elapsed time in seconds
#elapsed_ms Total elapsed time in milliseconds
#elapsed_us Total elapsed time in microseconds
#laps Array of recorded lap data
#running? Whether the stopwatch is actively running
#paused? Whether the stopwatch is paused
#checkpoint(name) Record a named moment storing the current cumulative split time
#elapsed_at(name) Cumulative split time at the named checkpoint
#since(name) Elapsed time since the named checkpoint was recorded
#checkpoints Hash of all recorded checkpoints
#lap_stats Aggregate lap statistics (count, total, avg, min, max)
#formatted_elapsed Human-readable elapsed time string
#formatted_laps Array of laps with formatted times
#to_h Serialize full stopwatch state to a hash
Stopwatch.measure { block } Measure block execution time
Stopwatch.measure_formatted { block } Measure block and return formatted string

Development

bundle install
bundle exec rspec
bundle exec rubocop

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT