Class: Progressor::LimitedSequence
- Inherits:
-
Object
- Object
- Progressor::LimitedSequence
- Includes:
- Formatting
- Defined in:
- lib/progressor/limited_sequence.rb
Instance Attribute Summary collapse
-
#current ⇒ Object
readonly
The current loop index, starts at 1.
-
#max_samples ⇒ Object
readonly
Returns the value of attribute max_samples.
-
#min_samples ⇒ Object
readonly
Returns the value of attribute min_samples.
-
#start_time ⇒ Object
readonly
The time the object was created.
-
#total_count ⇒ Object
readonly
Returns the value of attribute total_count.
Instance Method Summary collapse
-
#elapsed_time ⇒ Object
Returns the time since the object was instantiated, formatted like all the other durations.
-
#eta ⇒ Object
Returns an estimation for the Estimated Time of Arrival (time until done).
-
#initialize(total_count:, min_samples: 1, max_samples: 100, formatter: nil) ⇒ LimitedSequence
constructor
Creates a new LimitedSequence with the given parameters:.
-
#per_iteration ⇒ Object
Returns an estimation for the time per single iteration.
-
#push(duration) ⇒ Object
Adds a duration in seconds to the internal storage of samples.
-
#skip(n) ⇒ Object
Skips an iteration, updating the total count and ETA.
-
#to_s ⇒ Object
Outputs a textual representation of the current state of the LimitedSequence.
Methods included from Formatting
#format_float, #format_int, #format_time
Constructor Details
permalink #initialize(total_count:, min_samples: 1, max_samples: 100, formatter: nil) ⇒ LimitedSequence
Creates a new LimitedSequence with the given parameters:
-
total_count: The expected number of loops.
-
min_samples: The number of samples to collect before attempting to calculate a time per iteration. Default: 1
-
max_samples: The maximum number of measurements to collect and average. Default: 100.
-
formatter: A callable that accepts the sequence object and returns a custom formatted string.
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/progressor/limited_sequence.rb', line 26 def initialize(total_count:, min_samples: 1, max_samples: 100, formatter: nil) @total_count = total_count @min_samples = min_samples @max_samples = [max_samples, total_count].min @formatter = formatter raise Error.new("min_samples needs to be a positive number") if min_samples <= 0 raise Error.new("max_samples needs to be larger than min_samples") if max_samples <= min_samples @start_time = Time.now @total_count_digits = total_count.to_s.length @current = 0 @measurements = [] @averages = [] end |
Instance Attribute Details
permalink #current ⇒ Object (readonly)
The current loop index, starts at 1
8 9 10 |
# File 'lib/progressor/limited_sequence.rb', line 8 def current @current end |
permalink #max_samples ⇒ Object (readonly)
Returns the value of attribute max_samples.
5 6 7 |
# File 'lib/progressor/limited_sequence.rb', line 5 def max_samples @max_samples end |
permalink #min_samples ⇒ Object (readonly)
Returns the value of attribute min_samples.
5 6 7 |
# File 'lib/progressor/limited_sequence.rb', line 5 def min_samples @min_samples end |
permalink #start_time ⇒ Object (readonly)
The time the object was created
11 12 13 |
# File 'lib/progressor/limited_sequence.rb', line 11 def start_time @start_time end |
permalink #total_count ⇒ Object (readonly)
Returns the value of attribute total_count.
5 6 7 |
# File 'lib/progressor/limited_sequence.rb', line 5 def total_count @total_count end |
Instance Method Details
permalink #elapsed_time ⇒ Object
Returns the time since the object was instantiated, formatted like all the other durations. Useful for a final message to compare initial estimation to actual elapsed time.
124 125 126 |
# File 'lib/progressor/limited_sequence.rb', line 124 def elapsed_time format_time(Time.now - @start_time) end |
permalink #eta ⇒ Object
Returns an estimation for the Estimated Time of Arrival (time until done).
Calculated by multiplying the average time per iteration with the remaining number of loops.
113 114 115 116 117 118 |
# File 'lib/progressor/limited_sequence.rb', line 113 def eta return nil if @measurements.count < min_samples remaining_time = per_iteration * (@total_count - @current) remaining_time.round(2) end |
permalink #per_iteration ⇒ Object
Returns an estimation for the time per single iteration. Implemented as an average of averages to provide a smoother gradient from loop to loop.
Returns nil if not enough samples have been collected yet.
102 103 104 105 |
# File 'lib/progressor/limited_sequence.rb', line 102 def per_iteration return nil if @measurements.count < min_samples average(@averages) end |
permalink #push(duration) ⇒ Object
Adds a duration in seconds to the internal storage of samples. Updates averages accordingly.
45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/progressor/limited_sequence.rb', line 45 def push(duration) @current += 1 @measurements << duration # only keep last `max_samples` @measurements.shift if @measurements.count > max_samples @averages << average(@measurements) @averages = @averages.compact # only keep last `max_samples` @averages.shift if @averages.count > max_samples end |
permalink #skip(n) ⇒ Object
Skips an iteration, updating the total count and ETA
59 60 61 |
# File 'lib/progressor/limited_sequence.rb', line 59 def skip(n) @total_count -= n end |
permalink #to_s ⇒ Object
Outputs a textual representation of the current state of the LimitedSequence. Shows:
-
the current number of iterations and the total count
-
completion level in percentage
-
how long a single iteration takes
-
estimated time of arrival (ETA) – time until it’s done
A custom ‘formatter` provided at construction time overrides this default output.
If the “current” number of iterations goes over the total count, an ETA can’t be shown anymore, so it’ll just be the current number over the expected one, and the time per iteration.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/progressor/limited_sequence.rb', line 78 def to_s return @formatter.call(self).to_s if @formatter if @current > @total_count return [ "#{@current} (expected #{@total_count})", "t/i: #{format_time(per_iteration)}", "ETA: ???", ].join(', ') end [ "#{@current.to_s.rjust(@total_count_digits, '0')}/#{@total_count}", "#{((@current / @total_count.to_f) * 100).round.to_s.rjust(3, '0')}%", "t/i: #{format_time(per_iteration)}", "ETA: #{format_time(eta)}", ].join(', ') end |