diff --git a/lib/ruby-progressbar/calculators/smoothed_average.rb b/lib/ruby-progressbar/calculators/smoothed_average.rb index b8a3652..d6357f2 100644 --- a/lib/ruby-progressbar/calculators/smoothed_average.rb +++ b/lib/ruby-progressbar/calculators/smoothed_average.rb @@ -19,7 +19,10 @@ def decrement; end def increment; end def progress=(_new_progress); end def total=(_new_total); end - def reset; end + + def reset + start + end def calculate(new_value) self.projection = \ @@ -30,6 +33,10 @@ def calculate(new_value) ) end + def none? + projection.zero? + end + def self.calculate(current_projection, new_value, rate) (new_value * (1.0 - rate)) + (current_projection * rate) end diff --git a/lib/ruby-progressbar/components/time.rb b/lib/ruby-progressbar/components/time.rb index 98751f5..9eb0652 100644 --- a/lib/ruby-progressbar/components/time.rb +++ b/lib/ruby-progressbar/components/time.rb @@ -19,8 +19,9 @@ class Time }.freeze def initialize(options = {}) - self.timer = options[:timer] - self.progress = options[:progress] + self.timer = options[:timer] + self.progress = options[:progress] + self.projector = options[:projector] end def estimated_with_label(out_of_bounds_time_format = nil) @@ -57,7 +58,8 @@ def estimated_wall_clock protected attr_accessor :timer, - :progress + :progress, + :projector private @@ -90,9 +92,9 @@ def estimated_with_elapsed_fallback(out_of_bounds_time_format) end def estimated_seconds_remaining - return if progress.unknown? || progress.none? || timer.stopped? || timer.reset? + return if progress.unknown? || projector.none? || progress.none? || timer.stopped? || timer.reset? - (timer.elapsed_seconds * ((progress.total / progress.running_average) - 1)).round + (timer.elapsed_seconds * ((progress.total / projector.projection) - 1)).round end end end diff --git a/lib/ruby-progressbar/progress.rb b/lib/ruby-progressbar/progress.rb index 79f5fff..5478bf9 100644 --- a/lib/ruby-progressbar/progress.rb +++ b/lib/ruby-progressbar/progress.rb @@ -92,7 +92,7 @@ def percentage_completed end def none? - running_average.zero? || progress.zero? + progress.zero? end def unknown? diff --git a/spec/lib/ruby-progressbar/calculators/smoothed_average_spec.rb b/spec/lib/ruby-progressbar/calculators/smoothed_average_spec.rb index b04a794..cccdbfa 100644 --- a/spec/lib/ruby-progressbar/calculators/smoothed_average_spec.rb +++ b/spec/lib/ruby-progressbar/calculators/smoothed_average_spec.rb @@ -29,6 +29,20 @@ module Calculators end end + describe '#reset' do + it 'resets the projection' do + projector = SmoothedAverage.new + projector.start + projector.calculate(10) + + expect(projector.projection).not_to be_zero + + projector.reset + + expect(projector.projection).to be 0.0 + end + end + describe '#strength' do it 'allows the default strength to be overridden' do projector = SmoothedAverage.new(:strength => 0.3) diff --git a/spec/lib/ruby-progressbar/components/time_spec.rb b/spec/lib/ruby-progressbar/components/time_spec.rb index ad49c98..54c7bd5 100644 --- a/spec/lib/ruby-progressbar/components/time_spec.rb +++ b/spec/lib/ruby-progressbar/components/time_spec.rb @@ -9,8 +9,9 @@ module Components timer = Timer.new projector = Calculators::SmoothedAverage.new progress = Progress.new(:projector => projector) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) expect(time.elapsed_with_label).to eql 'Time: --:--:--' end @@ -19,10 +20,12 @@ module Components timer = Timer.new projector = Calculators::SmoothedAverage.new progress = Progress.new(:projector => projector) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) timer.start + projector.start expect(time.elapsed_with_label).to eql 'Time: 00:00:00' end @@ -31,12 +34,14 @@ module Components timer = Timer.new projector = Calculators::SmoothedAverage.new progress = Progress.new(:projector => projector) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-16_093) timer.start + projector.start Timecop.return @@ -47,12 +52,14 @@ module Components timer = Timer.new projector = Calculators::SmoothedAverage.new progress = Progress.new(:projector => projector) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-16_093) timer.start + projector.start Timecop.return Timecop.freeze(-32) @@ -68,12 +75,14 @@ module Components timer = Timer.new projector = Calculators::SmoothedAverage.new progress = Progress.new(:projector => projector) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-16_093) timer.start + projector.start Timecop.return @@ -89,13 +98,18 @@ module Components projector = Calculators::SmoothedAverage.new(:strength => 0.0) progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-13_332) timer.start - 50.times { progress.increment } + projector.start + 50.times do + progress.increment + projector.increment + end Timecop.return @@ -107,10 +121,12 @@ module Components timer = Timer.new projector = Calculators::SmoothedAverage.new progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) timer.start + projector.start expect(time.estimated_with_unknown_oob).to eql ' ETA: ??:??:??' end @@ -120,13 +136,18 @@ module Components timer = Timer.new projector = Calculators::SmoothedAverage.new progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-13_332) timer.start - 50.times { progress.increment } + projector.start + 50.times do + progress.increment + projector.increment + end Timecop.return @@ -135,6 +156,31 @@ module Components expect(time.estimated_with_unknown_oob).to eql ' ETA: ??:??:??' end + it 'displays unknown time remaining when progress has been made and then rate ' \ + 'is reset' do + timer = Timer.new + projector = Calculators::SmoothedAverage.new + progress = Progress.new(:projector => projector, :total => 100) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) + + Timecop.freeze(-13_332) + + timer.start + projector.start + 50.times do + progress.increment + projector.increment + end + + Timecop.return + + projector.reset + + expect(time.estimated_with_unknown_oob).to eql ' ETA: ??:??:??' + end + it 'displays estimated time of "??:??:??" when estimated time is out of bounds ' \ 'and the out of bounds format is set to "unknown"' do timer = Timer.new @@ -143,12 +189,17 @@ module Components :total => 100) time = Time.new(:out_of_bounds_time_format => :unknown, :timer => timer, - :progress => progress) + :progress => progress, + :projector => projector) Timecop.freeze(-120_000) timer.start - 25.times { progress.increment } + projector.start + 25.times do + progress.increment + projector.increment + end Timecop.return @@ -161,13 +212,18 @@ module Components projector = Calculators::SmoothedAverage.new(:strength => 0.5) progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-13_332) timer.start - 50.times { progress.increment } + projector.start + 50.times do + progress.increment + projector.increment + end Timecop.return @@ -183,13 +239,18 @@ module Components projector = Calculators::SmoothedAverage.new(:strength => 0.0) progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-13_332) timer.start - 50.times { progress.increment } + projector.start + 50.times do + progress.increment + projector.increment + end Timecop.return @@ -204,12 +265,17 @@ module Components :total => 100) time = Time.new(:out_of_bounds_time_format => :friendly, :timer => timer, - :progress => progress) + :progress => progress, + :projector => projector) Timecop.freeze(-120_000) timer.start - 25.times { progress.increment } + projector.start + 25.times do + progress.increment + projector.increment + end Timecop.return @@ -223,13 +289,18 @@ module Components projector = Calculators::SmoothedAverage.new(:strength => 0.0) progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-13_332) timer.start - 50.times { progress.increment } + projector.start + 50.times do + progress.increment + projector.increment + end Timecop.return @@ -244,12 +315,17 @@ module Components :total => 100) time = Time.new(:out_of_bounds_time_format => nil, :timer => timer, - :progress => progress) + :progress => progress, + :projector => projector) Timecop.freeze(-120_000) timer.start - 25.times { progress.increment } + projector.start + 25.times do + progress.increment + projector.increment + end Timecop.return @@ -264,11 +340,14 @@ module Components projector = Calculators::SmoothedAverage.new progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) timer.start + projector.start progress.increment + projector.increment expect(time.estimated_with_label).to eql ' ETA: 00:00:00' end @@ -278,13 +357,18 @@ module Components projector = Calculators::SmoothedAverage.new(:strength => 0.0) progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-13_332) timer.start - 50.times { progress.increment } + projector.start + 50.times do + progress.increment + projector.increment + end Timecop.return @@ -297,17 +381,25 @@ module Components projector = Calculators::SmoothedAverage.new(:strength => 0.0) progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-13_332) timer.start - 50.times { progress.increment } + projector.start + 50.times do + progress.increment + projector.increment + end Timecop.return - 20.times { progress.decrement } + 20.times do + progress.decrement + projector.decrement + end expect(time.estimated_with_label).to eql ' ETA: 08:38:28' end @@ -318,33 +410,46 @@ module Components projector = Calculators::SmoothedAverage.new(:strength => 0.5) progress = Progress.new(:projector => projector, :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-13_332) timer.start - 50.times { progress.increment } + projector.start + 50.times do + progress.increment + projector.increment + end Timecop.return - 20.times { progress.decrement } + 20.times do + progress.decrement + projector.decrement + end expect(time.estimated_with_label).to eql ' ETA: 08:14:34' end it 'displays smoothed estimated time after progress has been made' do - timer = Timer.new - projector = Calculators::SmoothedAverage.new(:strength => 0.5) - progress = Progress.new(:projector => projector, - :total => 100) - time = Time.new(:timer => timer, - :progress => progress) + timer = Timer.new + projector = Calculators::SmoothedAverage.new(:strength => 0.5) + progress = Progress.new(:projector => projector, + :total => 100) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-13_332) timer.start - 50.times { progress.increment } + projector.start + 50.times do + progress.increment + projector.increment + end Timecop.return @@ -353,12 +458,13 @@ module Components it 'displays the estimated time remaining properly even for progress increments ' \ 'very short intervals' do - timer = Timer.new - projector = Calculators::SmoothedAverage.new(:strength => 0.1) - progress = Progress.new(:projector => projector, - :total => 10) - time = Time.new(:timer => timer, - :progress => progress) + timer = Timer.new + projector = Calculators::SmoothedAverage.new(:strength => 0.1) + progress = Progress.new(:projector => projector, + :total => 10) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) estimated_time_results = [] now = ::Time.now @@ -366,10 +472,12 @@ module Components Timecop.freeze(now) timer.start + projector.start 10.times do Timecop.freeze(now += 0.5) progress.increment + projector.increment estimated_time_results << time.estimated_with_label end @@ -396,15 +504,17 @@ module Components describe '#estimated_wall_clock' do it 'displays the wall clock time as unknown when the timer has been reset' do - timer = Timer.new - projector = Calculators::SmoothedAverage.new - progress = Progress.new(:projector => projector) - time = Time.new(:timer => timer, - :progress => progress) + timer = Timer.new + projector = Calculators::SmoothedAverage.new + progress = Progress.new(:projector => projector) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-16_093) timer.start + projector.start Timecop.return @@ -414,15 +524,17 @@ module Components end it 'displays the wall clock time as unknown when the progress has not begun' do - timer = Timer.new - projector = Calculators::SmoothedAverage.new - progress = Progress.new(:projector => projector) - time = Time.new(:timer => timer, - :progress => progress) + timer = Timer.new + projector = Calculators::SmoothedAverage.new + progress = Progress.new(:projector => projector) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(-16_093) timer.start + projector.start Timecop.return @@ -430,15 +542,17 @@ module Components end it 'displays the completed wall clock time if the progress is finished' do - timer = Timer.new - projector = Calculators::SmoothedAverage.new - progress = Progress.new(:projector => projector) - time = Time.new(:timer => timer, - :progress => progress) + timer = Timer.new + projector = Calculators::SmoothedAverage.new + progress = Progress.new(:projector => projector) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(::Time.utc(2020, 1, 1, 0, 0, 0)) timer.start + projector.start Timecop.freeze(::Time.utc(2020, 1, 1, 0, 30, 0)) @@ -451,16 +565,19 @@ module Components end it 'displays the estimated wall clock time if the progress is ongoing' do - timer = Timer.new - projector = Calculators::SmoothedAverage.new(:strength => 0.0) - progress = Progress.new(:projector => projector) - time = Time.new(:timer => timer, - :progress => progress) + timer = Timer.new + projector = Calculators::SmoothedAverage.new(:strength => 0.0) + progress = Progress.new(:projector => projector) + time = Time.new(:timer => timer, + :progress => progress, + :projector => projector) Timecop.freeze(::Time.utc(2020, 1, 1, 0, 0, 0)) timer.start - progress.progress = 50 + projector.start + progress.progress = 50 + projector.progress = 50 Timecop.freeze(::Time.utc(2020, 1, 1, 0, 15, 0))