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 |