Class: Philiprehberger::Stopwatch
- Inherits:
-
Object
- Object
- Philiprehberger::Stopwatch
- Defined in:
- lib/philiprehberger/stopwatch.rb,
lib/philiprehberger/stopwatch/version.rb
Defined Under Namespace
Classes: Error
Constant Summary collapse
- VERSION =
'0.6.0'
Class Method Summary collapse
-
.format_duration(seconds) ⇒ String
Format a duration in seconds as a human-readable string.
-
.measure { ... } ⇒ Array
Measure execution time of a block.
-
.measure_formatted { ... } ⇒ String
Measure execution time and return formatted string.
Instance Method Summary collapse
-
#checkpoint(name) ⇒ self
Record a named checkpoint at the current cumulative elapsed time.
-
#checkpoints ⇒ Hash
Return a copy of all recorded checkpoints.
-
#elapsed ⇒ Float
Get total elapsed time in seconds.
-
#elapsed_at(name) ⇒ Float
Return the cumulative elapsed time recorded at a named checkpoint.
-
#elapsed_ms ⇒ Float
Get total elapsed time in milliseconds.
-
#elapsed_us ⇒ Float
Get total elapsed time in microseconds.
-
#formatted_elapsed ⇒ String
Format elapsed time as a human-readable string.
-
#formatted_laps ⇒ Array<Hash>
Get formatted lap data.
-
#initialize ⇒ Stopwatch
constructor
A new instance of Stopwatch.
-
#lap(name = nil) ⇒ Hash
Record a lap.
-
#lap_stats ⇒ Hash
Get aggregate statistics across all recorded laps.
-
#laps ⇒ Array<Hash>
Get all recorded laps.
-
#paused? ⇒ Boolean
Check if the stopwatch is paused.
-
#reset ⇒ self
Reset the stopwatch.
-
#restart ⇒ self
Reset and start the stopwatch in one call.
-
#running? ⇒ Boolean
Check if the stopwatch is running (and not paused).
-
#since(name) ⇒ Float
Return the elapsed time since a named checkpoint was recorded.
-
#start ⇒ self
(also: #resume)
Start the stopwatch.
-
#stop ⇒ self
(also: #pause)
Stop (pause) the stopwatch.
-
#tick ⇒ Float
Record an unnamed tick and return the seconds since the previous tick.
-
#to_h ⇒ Hash
Serialize the stopwatch state to a hash.
Constructor Details
#initialize ⇒ Stopwatch
Returns a new instance of Stopwatch.
9 10 11 12 13 14 15 16 17 18 |
# File 'lib/philiprehberger/stopwatch.rb', line 9 def initialize @laps = [] @checkpoints = {} @running = false @paused = false @start_time = nil @elapsed_before_pause = 0.0 @lap_start = nil @last_tick = nil end |
Class Method Details
.format_duration(seconds) ⇒ String
Format a duration in seconds as a human-readable string
276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/philiprehberger/stopwatch.rb', line 276 def self.format_duration(seconds) if seconds < 0.001 format('%.2fus', seconds * 1_000_000) elsif seconds < 1.0 format('%.2fms', seconds * 1_000) elsif seconds < 60.0 format('%.3fs', seconds) elsif seconds < 3600.0 minutes = (seconds / 60).to_i secs = (seconds % 60).to_i "#{minutes}m #{secs}s" else hours = (seconds / 3600).to_i minutes = ((seconds % 3600) / 60).to_i secs = (seconds % 60).to_i "#{hours}h #{minutes}m #{secs}s" end end |
.measure { ... } ⇒ Array
Measure execution time of a block
256 257 258 259 260 261 |
# File 'lib/philiprehberger/stopwatch.rb', line 256 def self.measure start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) result = yield elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time [result, elapsed] end |
.measure_formatted { ... } ⇒ String
Measure execution time and return formatted string
267 268 269 270 |
# File 'lib/philiprehberger/stopwatch.rb', line 267 def self.measure_formatted(&) _, elapsed = measure(&) format_duration(elapsed) end |
Instance Method Details
#checkpoint(name) ⇒ self
Record a named checkpoint at the current cumulative elapsed time
147 148 149 150 151 152 153 154 |
# File 'lib/philiprehberger/stopwatch.rb', line 147 def checkpoint(name) raise Error, 'stopwatch is not running' unless @running current = now split = @elapsed_before_pause + (current - @start_time) @checkpoints[name] = split self end |
#checkpoints ⇒ Hash
Return a copy of all recorded checkpoints
179 180 181 |
# File 'lib/philiprehberger/stopwatch.rb', line 179 def checkpoints @checkpoints.dup end |
#elapsed ⇒ Float
Get total elapsed time in seconds
128 129 130 131 132 133 134 |
# File 'lib/philiprehberger/stopwatch.rb', line 128 def elapsed if @running && !@paused @elapsed_before_pause + (now - @start_time) else @elapsed_before_pause end end |
#elapsed_at(name) ⇒ Float
Return the cumulative elapsed time recorded at a named checkpoint
160 161 162 163 164 |
# File 'lib/philiprehberger/stopwatch.rb', line 160 def elapsed_at(name) raise Error, "checkpoint '#{name}' not found" unless @checkpoints.key?(name) @checkpoints[name] end |
#elapsed_ms ⇒ Float
Get total elapsed time in milliseconds
114 115 116 |
# File 'lib/philiprehberger/stopwatch.rb', line 114 def elapsed_ms elapsed * 1000.0 end |
#elapsed_us ⇒ Float
Get total elapsed time in microseconds
121 122 123 |
# File 'lib/philiprehberger/stopwatch.rb', line 121 def elapsed_us elapsed * 1_000_000.0 end |
#formatted_elapsed ⇒ String
Format elapsed time as a human-readable string
205 206 207 |
# File 'lib/philiprehberger/stopwatch.rb', line 205 def formatted_elapsed self.class.format_duration(elapsed) end |
#formatted_laps ⇒ Array<Hash>
Get formatted lap data
212 213 214 215 216 217 218 219 220 221 222 |
# File 'lib/philiprehberger/stopwatch.rb', line 212 def formatted_laps @laps.map do |lap| { name: lap[:name], elapsed: lap[:elapsed], split: lap[:split], formatted: self.class.format_duration(lap[:elapsed]), formatted_split: self.class.format_duration(lap[:split]) } end end |
#lap(name = nil) ⇒ Hash
Record a lap
80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/philiprehberger/stopwatch.rb', line 80 def lap(name = nil) raise Error, 'stopwatch is not running' unless @running current = now lap_elapsed = current - @lap_start split = @elapsed_before_pause + (current - @start_time) lap_data = { name: name, elapsed: lap_elapsed, split: split } @laps << lap_data @lap_start = current lap_data end |
#lap_stats ⇒ Hash
Get aggregate statistics across all recorded laps
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/philiprehberger/stopwatch.rb', line 186 def lap_stats if @laps.empty? return { count: 0, total: 0.0, avg: 0.0, min: 0.0, max: 0.0 } end times = @laps.map { |l| l[:elapsed] } total = times.sum { count: times.length, total: total, avg: total / times.length, min: times.min, max: times.max } end |
#laps ⇒ Array<Hash>
Get all recorded laps
139 140 141 |
# File 'lib/philiprehberger/stopwatch.rb', line 139 def laps @laps.dup end |
#paused? ⇒ Boolean
Check if the stopwatch is paused
241 242 243 |
# File 'lib/philiprehberger/stopwatch.rb', line 241 def paused? @paused end |
#reset ⇒ self
Reset the stopwatch
53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/philiprehberger/stopwatch.rb', line 53 def reset @laps = [] @checkpoints = {} @running = false @paused = false @start_time = nil @elapsed_before_pause = 0.0 @lap_start = nil @last_tick = nil self end |
#restart ⇒ self
Reset and start the stopwatch in one call
68 69 70 71 |
# File 'lib/philiprehberger/stopwatch.rb', line 68 def restart reset start end |
#running? ⇒ Boolean
Check if the stopwatch is running (and not paused)
248 249 250 |
# File 'lib/philiprehberger/stopwatch.rb', line 248 def running? @running && !@paused end |
#since(name) ⇒ Float
Return the elapsed time since a named checkpoint was recorded
170 171 172 173 174 |
# File 'lib/philiprehberger/stopwatch.rb', line 170 def since(name) raise Error, "checkpoint '#{name}' not found" unless @checkpoints.key?(name) elapsed - @checkpoints[name] end |
#start ⇒ self Also known as: resume
Start the stopwatch
23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/philiprehberger/stopwatch.rb', line 23 def start raise Error, 'stopwatch is already running' if @running && !@paused @start_time = now if @paused @paused = false else @elapsed_before_pause = 0.0 @lap_start = @start_time @laps = [] end @running = true self end |
#stop ⇒ self Also known as: pause
Stop (pause) the stopwatch
41 42 43 44 45 46 47 48 |
# File 'lib/philiprehberger/stopwatch.rb', line 41 def stop raise Error, 'stopwatch is not running' unless @running raise Error, 'stopwatch is already paused' if @paused @elapsed_before_pause += now - @start_time @paused = true self end |
#tick ⇒ Float
Record an unnamed tick and return the seconds since the previous tick
On the first call after start, returns the seconds elapsed since the
stopwatch began. Subsequent calls return the seconds since the previous
tick. Useful for sequential timing in loops where naming each lap is
noise — a thinner lap for ad-hoc measurement.
101 102 103 104 105 106 107 108 109 |
# File 'lib/philiprehberger/stopwatch.rb', line 101 def tick raise Error, 'stopwatch is not running' unless running? current = now previous = @last_tick || @start_time delta = current - previous @last_tick = current delta end |
#to_h ⇒ Hash
Serialize the stopwatch state to a hash
227 228 229 230 231 232 233 234 235 236 |
# File 'lib/philiprehberger/stopwatch.rb', line 227 def to_h { running: running?, paused: paused?, elapsed: elapsed, formatted_elapsed: formatted_elapsed, laps: laps, lap_stats: lap_stats } end |