Skip to content

Commit 2bc31d0

Browse files
committed
Merge branch 'allow-configurable-projectors'
2 parents d7a2a51 + c914747 commit 2bc31d0

File tree

16 files changed

+680
-313
lines changed

16 files changed

+680
-313
lines changed

lib/ruby-progressbar/base.rb

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,29 @@
1010
require 'ruby-progressbar/outputs/non_tty'
1111
require 'ruby-progressbar/outputs/tty'
1212
require 'ruby-progressbar/progress'
13+
require 'ruby-progressbar/projector'
1314
require 'ruby-progressbar/timer'
1415

1516
class ProgressBar
1617
class Base
1718
extend Forwardable
1819

20+
# rubocop:disable Layout/HeredocIndentation
21+
SMOOTHING_DEPRECATION_WARNING = <<-HEREDOC.tr("\n", ' ')
22+
WARNING: Passing the 'smoothing' option is deprecated and will be removed
23+
in version 2.0. Please pass { projector: { type: 'smoothing', strength: 0.x }}.
24+
For more information on why this change is happening, visit
25+
https://github.com/jfelchner/ruby-progressbar/wiki/Upgrading
26+
HEREDOC
27+
28+
RUNNING_AVERAGE_RATE_DEPRECATION_WARNING = <<-HEREDOC.tr("\n", ' ')
29+
WARNING: Passing the 'running_average_rate' option is deprecated and will be removed
30+
in version 2.0. Please pass { projector: { type: 'smoothing', strength: 0.x }}.
31+
For more information on why this change is happening, visit
32+
https://github.com/jfelchner/ruby-progressbar/wiki/Upgrading
33+
HEREDOC
34+
# rubocop:enable Layout/HeredocIndentation
35+
1936
def_delegators :output,
2037
:clear,
2138
:log,
@@ -26,15 +43,34 @@ class Base
2643
:total
2744

2845
def initialize(options = {}) # rubocop:disable Metrics/AbcSize
46+
options[:projector] ||= {}
47+
2948
self.autostart = options.fetch(:autostart, true)
3049
self.autofinish = options.fetch(:autofinish, true)
3150
self.finished = false
3251

3352
self.timer = Timer.new(options)
53+
projector_opts = if options[:projector].any?
54+
options[:projector]
55+
elsif options[:smoothing]
56+
warn SMOOTHING_DEPRECATION_WARNING
57+
58+
{ :strength => options[:smoothing] }
59+
elsif options[:running_average_rate]
60+
warn RUNNING_AVERAGE_RATE_DEPRECATION_WARNING
61+
62+
{ :strength => options[:smoothing] }
63+
else
64+
{}
65+
end
66+
self.projector = Projector.
67+
from_type(options[:projector][:type]).
68+
new(projector_opts)
3469
self.progressable = Progress.new(options)
3570

36-
options = options.merge(:progress => progressable,
37-
:timer => timer)
71+
options = options.merge(:progress => progressable,
72+
:projector => projector,
73+
:timer => timer)
3874

3975
self.title_component = Components::Title.new(options)
4076
self.bar_component = Components::Bar.new(options)
@@ -79,6 +115,7 @@ def reset
79115
output.with_refresh do
80116
self.finished = false
81117
progressable.reset
118+
projector.reset
82119
timer.reset
83120
end
84121
end
@@ -174,6 +211,7 @@ def format=(other)
174211
protected
175212

176213
attr_accessor :output,
214+
:projector,
177215
:timer,
178216
:progressable,
179217
:title_component,
@@ -188,6 +226,7 @@ def format=(other)
188226
def update_progress(*args)
189227
output.with_refresh do
190228
progressable.__send__(*args)
229+
projector.__send__(*args)
191230
timer.stop if finished?
192231
end
193232
end

lib/ruby-progressbar/calculators/smoothed_average.rb

Lines changed: 0 additions & 9 deletions
This file was deleted.

lib/ruby-progressbar/components/time.rb

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ class Time
1919
}.freeze
2020

2121
def initialize(options = {})
22-
self.timer = options[:timer]
23-
self.progress = options[:progress]
22+
self.timer = options[:timer]
23+
self.progress = options[:progress]
24+
self.projector = options[:projector]
2425
end
2526

2627
def estimated_with_label(out_of_bounds_time_format = nil)
@@ -57,7 +58,8 @@ def estimated_wall_clock
5758
protected
5859

5960
attr_accessor :timer,
60-
:progress
61+
:progress,
62+
:projector
6163

6264
private
6365

@@ -90,9 +92,9 @@ def estimated_with_elapsed_fallback(out_of_bounds_time_format)
9092
end
9193

9294
def estimated_seconds_remaining
93-
return if progress.unknown? || progress.none? || timer.stopped? || timer.reset?
95+
return if progress.unknown? || projector.none? || progress.none? || timer.stopped? || timer.reset?
9496

95-
(timer.elapsed_seconds * ((progress.total / progress.running_average) - 1)).round
97+
(timer.elapsed_seconds * ((progress.total / projector.projection) - 1)).round
9698
end
9799
end
98100
end

lib/ruby-progressbar/progress.rb

Lines changed: 9 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,22 @@
11
require 'ruby-progressbar/errors/invalid_progress_error'
2-
require 'ruby-progressbar/calculators/smoothed_average'
32

43
class ProgressBar
54
class Progress
6-
DEFAULT_TOTAL = 100
7-
DEFAULT_BEGINNING_POSITION = 0
8-
DEFAULT_RUNNING_AVERAGE_RATE = 0.1
9-
DEFAULT_RUNNING_AVERAGE_CALCULATOR = ProgressBar::Calculators::SmoothedAverage
10-
11-
RUNNING_AVERAGE_CALCULATOR_MAP = {
12-
'smoothing' => ProgressBar::Calculators::SmoothedAverage
13-
}.freeze
5+
DEFAULT_TOTAL = 100
6+
DEFAULT_BEGINNING_POSITION = 0
147

158
attr_reader :total,
169
:progress
17-
18-
attr_accessor :starting_position,
19-
:running_average,
20-
:running_average_calculator,
21-
:running_average_rate
10+
attr_accessor :starting_position
2211

2312
def initialize(options = {})
24-
self.total = options.fetch(:total, DEFAULT_TOTAL)
25-
self.running_average_rate = options[:smoothing] ||
26-
options[:running_average_rate] ||
27-
DEFAULT_RUNNING_AVERAGE_RATE
28-
self.running_average_calculator = RUNNING_AVERAGE_CALCULATOR_MAP.
29-
fetch(options[:running_average_calculator],
30-
DEFAULT_RUNNING_AVERAGE_CALCULATOR)
31-
32-
start :at => DEFAULT_BEGINNING_POSITION
13+
self.total = options.fetch(:total, DEFAULT_TOTAL)
14+
15+
start(:at => DEFAULT_BEGINNING_POSITION)
3316
end
3417

3518
def start(options = {})
36-
self.running_average = 0
37-
self.progress = \
19+
self.progress = \
3820
self.starting_position = options[:at] || progress
3921
end
4022

@@ -67,7 +49,7 @@ def decrement
6749
end
6850

6951
def reset
70-
start :at => starting_position
52+
start(:at => starting_position)
7153
end
7254

7355
def progress=(new_progress)
@@ -77,10 +59,6 @@ def progress=(new_progress)
7759
end
7860

7961
@progress = new_progress
80-
81-
self.running_average = running_average_calculator.calculate(running_average,
82-
absolute,
83-
running_average_rate)
8462
end
8563

8664
def total=(new_total)
@@ -105,7 +83,7 @@ def percentage_completed
10583
end
10684

10785
def none?
108-
running_average.zero? || progress.zero?
86+
progress.zero?
10987
end
11088

11189
def unknown?

lib/ruby-progressbar/projector.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
require 'ruby-progressbar/projectors/smoothed_average'
2+
3+
class ProgressBar
4+
class Projector
5+
DEFAULT_PROJECTOR = ProgressBar::Projectors::SmoothedAverage
6+
NAME_TO_PROJECTOR_MAP = {
7+
'smoothed' => ProgressBar::Projectors::SmoothedAverage
8+
}.freeze
9+
10+
def self.from_type(name)
11+
NAME_TO_PROJECTOR_MAP.fetch(name, DEFAULT_PROJECTOR)
12+
end
13+
end
14+
end
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
class ProgressBar
2+
module Projectors
3+
class SmoothedAverage
4+
DEFAULT_STRENGTH = 0.1
5+
DEFAULT_BEGINNING_POSITION = 0
6+
7+
attr_accessor :samples,
8+
:strength
9+
attr_reader :projection
10+
11+
def initialize(options = {})
12+
self.samples = []
13+
self.projection = 0.0
14+
self.strength = options[:strength] || DEFAULT_STRENGTH
15+
16+
start(:at => DEFAULT_BEGINNING_POSITION)
17+
end
18+
19+
def start(options = {})
20+
self.projection = 0.0
21+
self.progress = samples[0] = (options[:at] || progress)
22+
end
23+
24+
def decrement
25+
self.progress -= 1
26+
end
27+
28+
def increment
29+
self.progress += 1
30+
end
31+
32+
def progress
33+
samples[1]
34+
end
35+
36+
def total=(_new_total); end
37+
38+
def reset
39+
start(:at => samples[0])
40+
end
41+
42+
def progress=(new_progress)
43+
samples[1] = new_progress
44+
self.projection = \
45+
self.class.calculate(
46+
@projection,
47+
absolute,
48+
strength
49+
)
50+
end
51+
52+
def none?
53+
projection.zero?
54+
end
55+
56+
def self.calculate(current_projection, new_value, rate)
57+
(new_value * (1.0 - rate)) + (current_projection * rate)
58+
end
59+
60+
protected
61+
62+
attr_writer :projection
63+
64+
private
65+
66+
def absolute
67+
samples[1] - samples[0]
68+
end
69+
end
70+
end
71+
end

spec/lib/ruby-progressbar/base_spec.rb

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ class ProgressBar
232232
Timecop.freeze(::Time.utc(2020, 1, 1, 0, 0, 0))
233233

234234
progressbar = ProgressBar::Base.new(:output => output,
235-
:smoothing => 0.0,
235+
:projector => { :strength => 0.0 },
236236
:total => 100,
237237
:format => '%l')
238238

@@ -251,7 +251,7 @@ class ProgressBar
251251
Timecop.freeze(::Time.utc(2020, 1, 1, 0, 0, 0))
252252

253253
progressbar = ProgressBar::Base.new(:output => output,
254-
:smoothing => 0.0,
254+
:projector => { :strength => 0.0 },
255255
:total => 100,
256256
:format => '%l')
257257

@@ -275,6 +275,32 @@ class ProgressBar
275275
not_to raise_error
276276
end
277277

278+
# rubocop:disable RSpec/AnyInstance
279+
it 'displays a warning if the user passes the deprecated "smoothing" option but ' \
280+
'still processes it' do
281+
expect_any_instance_of(ProgressBar::Base).
282+
to receive(:warn).
283+
with(include("WARNING: Passing the 'smoothing' option is deprecated"))
284+
285+
Timecop.freeze(::Time.utc(2020, 1, 1, 0, 0, 0))
286+
287+
progressbar = ProgressBar::Base.new(:output => output,
288+
:smoothing => 0.0,
289+
:total => 100,
290+
:format => '%l')
291+
292+
progressbar.progress += 50
293+
294+
Timecop.freeze(::Time.utc(2020, 1, 1, 0, 30, 0))
295+
296+
progressbar.finish
297+
298+
Timecop.return
299+
300+
expect(progressbar.to_s).to eql '00:30:00'
301+
end
302+
# rubocop:enable RSpec/AnyInstance
303+
278304
it 'appends proper ending to string for non-TTY devices' do
279305
progressbar = ProgressBar::Base.new(:output => non_tty_output)
280306

spec/lib/ruby-progressbar/calculators/smoothed_average_spec.rb

Lines changed: 0 additions & 19 deletions
This file was deleted.

0 commit comments

Comments
 (0)