Skip to content

Commit

Permalink
Refactor: The Progress No Longer Needs The Projector
Browse files Browse the repository at this point in the history
Why This Change Is Necessary
========================================================================

We've removed all usages of the projector from the `Progress` object and
therefore it is no longer needed to do its job.

What These Changes Do To Address the Issue
========================================================================

Remove all usages of the projector from `Progress` and update test setup
to reflect that.

Side Effects Caused By This Change
========================================================================

None expected.
jfelchner committed Mar 4, 2023
1 parent 993bcf3 commit 616a7b3
Showing 5 changed files with 90 additions and 119 deletions.
2 changes: 1 addition & 1 deletion lib/ruby-progressbar/base.rb
Original file line number Diff line number Diff line change
@@ -62,7 +62,7 @@ def initialize(options = {}) # rubocop:disable Metrics/AbcSize
{}
end
self.projector = Calculators::SmoothedAverage.new(projector_opts)
self.progressable = Progress.new(options.merge(:projector => projector))
self.progressable = Progress.new(options)

options = options.merge(:progress => progressable,
:projector => projector,
11 changes: 2 additions & 9 deletions lib/ruby-progressbar/progress.rb
Original file line number Diff line number Diff line change
@@ -7,13 +7,10 @@ class Progress

attr_reader :total,
:progress

attr_accessor :starting_position,
:running_average_calculator
attr_accessor :starting_position

def initialize(options = {})
self.total = options.fetch(:total, DEFAULT_TOTAL)
self.running_average_calculator = options[:projector]
self.total = options.fetch(:total, DEFAULT_TOTAL)

start(:at => DEFAULT_BEGINNING_POSITION)
end
@@ -64,10 +61,6 @@ def progress=(new_progress)
@progress = new_progress
end

def running_average
running_average_calculator.projection
end

def total=(new_total)
unless progress.nil? || new_total.nil? || new_total >= progress
fail ProgressBar::InvalidProgressError,
53 changes: 46 additions & 7 deletions spec/lib/ruby-progressbar/calculators/smoothed_average_spec.rb
Original file line number Diff line number Diff line change
@@ -4,15 +4,54 @@
class ProgressBar
module Calculators
describe SmoothedAverage do
it 'can properly calculate a projection' do
first_projection = SmoothedAverage.calculate(4.5, 12, 0.1)
expect(first_projection).to be_within(0.001).of 11.25
describe '.calculate' do
it 'can properly calculate a projection' do
first_projection = SmoothedAverage.calculate(4.5, 12, 0.1)
expect(first_projection).to be_within(0.001).of 11.25

second_projection = SmoothedAverage.calculate(8.2, 51, 0.7)
expect(second_projection).to be_within(0.001).of 21.04
second_projection = SmoothedAverage.calculate(8.2, 51, 0.7)
expect(second_projection).to be_within(0.001).of 21.04

third_projection = SmoothedAverage.calculate(41.8, 100, 0.59)
expect(third_projection).to be_within(0.001).of 65.662
third_projection = SmoothedAverage.calculate(41.8, 100, 0.59)
expect(third_projection).to be_within(0.001).of 65.662
end
end

describe '#projection' do
it 'can properly calculate a running average' do
projector = SmoothedAverage.new(:strength => 0.1)
projector.start
projector.progress = 5
projector.progress = 12

expect(projector.projection).to be_within(0.001).of 11.25
end

it 'knows the running average even when progress has been made' do
projector = SmoothedAverage.new(:total => 50)

projector.instance_variable_set(:@projection, 10)
projector.start :at => 0

expect(projector.projection).to be_zero

projector.progress += 40

expect(projector.projection).to be 36.0
end

it 'knows the running average is reset even after progress is started' do
projector = SmoothedAverage.new(:total => 50)

projector.instance_variable_set(:@projection, 10)
projector.start :at => 0

expect(projector.projection).to be_zero

projector.start :at => 40

expect(projector.projection).to be 0.0
end
end

describe '#start' do
63 changes: 25 additions & 38 deletions spec/lib/ruby-progressbar/components/time_spec.rb
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ module Components
it 'displays unknown elapsed time when the timer has not been started' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -19,7 +19,7 @@ module Components
it 'displays elapsed time when the timer has just been started' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -33,7 +33,7 @@ module Components
it 'displays elapsed time if it was previously started' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -51,7 +51,7 @@ module Components
it 'displays elapsed time frozen to a specific time if it was previously stopped' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -74,7 +74,7 @@ module Components
it 'displays unknown elapsed time after reset has been called' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -96,8 +96,7 @@ module Components
it 'displays estimated time if it is known' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.0)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -120,7 +119,7 @@ module Components
'but no progress has been made' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector, :total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -135,7 +134,7 @@ module Components
'is reset' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector, :total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -160,7 +159,7 @@ module Components
'is reset' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector, :total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -185,8 +184,7 @@ module Components
'and the out of bounds format is set to "unknown"' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.0)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:out_of_bounds_time_format => :unknown,
:timer => timer,
:progress => progress,
@@ -210,8 +208,7 @@ module Components
'is made' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.5)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -237,8 +234,7 @@ module Components
it 'displays estimated time if it is known' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.0)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -261,8 +257,7 @@ module Components
'and the out of bounds format is set to "friendly"' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.0)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:out_of_bounds_time_format => :friendly,
:timer => timer,
:progress => progress,
@@ -287,8 +282,7 @@ module Components
it 'displays estimated time if it is known' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.0)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -311,8 +305,7 @@ module Components
'out of bounds format is unset' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.0)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:out_of_bounds_time_format => nil,
:timer => timer,
:progress => progress,
@@ -338,8 +331,7 @@ module Components
'it is incremented' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -355,8 +347,7 @@ module Components
it 'displays unsmoothed time remaining when progress has been made' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.0)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -379,8 +370,7 @@ module Components
'bar is decremented' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.0)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -408,8 +398,7 @@ module Components
'account' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.5)
progress = Progress.new(:projector => projector,
:total => 100)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -436,8 +425,7 @@ module Components
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)
progress = Progress.new(:total => 100)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -460,8 +448,7 @@ module Components
'very short intervals' do
timer = Timer.new
projector = Calculators::SmoothedAverage.new(:strength => 0.1)
progress = Progress.new(:projector => projector,
:total => 10)
progress = Progress.new(:total => 10)
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -506,7 +493,7 @@ module Components
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)
progress = Progress.new
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -526,7 +513,7 @@ module Components
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)
progress = Progress.new
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -544,7 +531,7 @@ module Components
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)
progress = Progress.new
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
@@ -567,7 +554,7 @@ module Components
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)
progress = Progress.new
time = Time.new(:timer => timer,
:progress => progress,
:projector => projector)
80 changes: 16 additions & 64 deletions spec/lib/ruby-progressbar/progress_spec.rb
Original file line number Diff line number Diff line change
@@ -4,26 +4,23 @@
class ProgressBar
describe Progress do
it 'knows the default total when no parameters are passed' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new

expect(progress.total).to eql Progress::DEFAULT_TOTAL
end

it 'knows the default beginning progress when no parameters are passed and ' \
'the progress has not been started' do

projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new

expect(progress.progress).to be_zero
end

it 'knows the default starting value when no parameters are passed and the ' \
'progress has been started' do

projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new

progress.start

@@ -33,43 +30,37 @@ class ProgressBar
it 'knows the given starting value when no parameters are passed and the ' \
'progress is started with a starting value' do

projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new

progress.start :at => 10

expect(progress.progress).to be 10
end

it 'knows how to finish itself even if the total is unknown' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:total => nil, :projector => projector)
progress = Progress.new :total => nil

expect(progress.finish).to be(nil)
end

it 'knows the overridden total when the total is passed in' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector,
:total => 12,
:progress_mark => 'x',
:remainder_mark => '.')
progress = Progress.new(:total => 12,
:progress_mark => 'x',
:remainder_mark => '.')

expect(progress.total).to be 12
end

it 'knows the percentage completed when begun with no progress' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new

progress.start

expect(progress.percentage_completed).to be 0
end

it 'knows the progress after it has been incremented' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:projector => projector)
progress = Progress.new

progress.start
progress.increment
@@ -78,8 +69,7 @@ class ProgressBar
end

it 'knows the percentage completed after it has been incremented' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:total => 50, :projector => projector)
progress = Progress.new(:total => 50)

progress.start
progress.increment
@@ -88,17 +78,15 @@ class ProgressBar
end

it 'knows to always round down the percentage completed' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:total => 200, :projector => projector)
progress = Progress.new(:total => 200)

progress.start :at => 1

expect(progress.percentage_completed).to be 0
end

it 'cannot increment past the total' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:total => 50, :projector => projector)
progress = Progress.new(:total => 50)

progress.start :at => 50
progress.increment
@@ -108,8 +96,7 @@ class ProgressBar
end

it 'allow progress to be decremented once it is finished' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:total => 50, :projector => projector)
progress = Progress.new(:total => 50)

progress.start :at => 50
progress.decrement
@@ -118,49 +105,14 @@ class ProgressBar
expect(progress.percentage_completed).to be 98
end

# rubocop:disable RSpec/BeEql
it 'knows the running average even when progress has been made' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:total => 50, :projector => projector)

projector.__send__(:projection=, 10)
projector.start
progress.start :at => 0

expect(progress.running_average).to be_zero

projector.progress += 40
progress.progress += 40

expect(progress.running_average).to eql 36.0
end

it 'knows the running average is reset even after progress is started' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:total => 50, :projector => projector)

projector.__send__(:projection=, 10)
projector.start
progress.start :at => 0

expect(progress.running_average).to be_zero

progress.start :at => 40

expect(progress.running_average).to eql 0.0
end
# rubocop:enable RSpec/BeEql

it 'knows the percentage completed is 100% if the total is zero' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:total => 0, :projector => projector)
progress = Progress.new(:total => 0)

expect(progress.percentage_completed).to be 100
end

it 'raises an error when passed a number larger than the total' do
projector = Calculators::SmoothedAverage.new
progress = Progress.new(:total => 100, :projector => projector)
progress = Progress.new(:total => 100)

expect { progress.progress = 101 }.
to \

0 comments on commit 616a7b3

Please sign in to comment.