ruby-progressbar 1.6.1 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/lib/ruby-progressbar.rb +8 -3
- data/lib/ruby-progressbar/base.rb +121 -177
- data/lib/ruby-progressbar/calculators/length.rb +75 -0
- data/lib/ruby-progressbar/calculators/length_spec.rb +9 -0
- data/lib/ruby-progressbar/calculators/running_average.rb +9 -0
- data/lib/ruby-progressbar/components.rb +3 -5
- data/lib/ruby-progressbar/components/bar.rb +79 -43
- data/lib/ruby-progressbar/components/percentage.rb +29 -0
- data/lib/ruby-progressbar/components/rate.rb +34 -62
- data/lib/ruby-progressbar/components/time.rb +103 -0
- data/lib/ruby-progressbar/components/title.rb +13 -0
- data/lib/ruby-progressbar/format.rb +2 -1
- data/lib/ruby-progressbar/format/formatter.rb +27 -0
- data/lib/ruby-progressbar/format/molecule.rb +55 -37
- data/lib/ruby-progressbar/format/string.rb +36 -0
- data/lib/ruby-progressbar/output.rb +61 -0
- data/lib/ruby-progressbar/outputs/non_tty.rb +47 -0
- data/lib/ruby-progressbar/outputs/tty.rb +32 -0
- data/lib/ruby-progressbar/progress.rb +110 -0
- data/lib/ruby-progressbar/throttle.rb +25 -0
- data/lib/ruby-progressbar/time.rb +20 -17
- data/lib/ruby-progressbar/timer.rb +72 -0
- data/lib/ruby-progressbar/version.rb +2 -2
- data/spec/fixtures/benchmark.rb +21 -4
- data/spec/{lib/ruby-progressbar → ruby-progressbar}/base_spec.rb +55 -62
- data/spec/ruby-progressbar/calculators/running_average_spec.rb +19 -0
- data/spec/ruby-progressbar/components/bar_spec.rb +234 -0
- data/spec/ruby-progressbar/components/percentage_spec.rb +9 -0
- data/spec/ruby-progressbar/components/rate_spec.rb +9 -0
- data/spec/ruby-progressbar/components/throttle_spec.rb +157 -0
- data/spec/ruby-progressbar/components/time_spec.rb +308 -0
- data/spec/ruby-progressbar/components/title_spec.rb +12 -0
- data/spec/ruby-progressbar/format/formatter_spec.rb +9 -0
- data/spec/ruby-progressbar/format/molecule_spec.rb +30 -0
- data/spec/ruby-progressbar/format/string_spec.rb +9 -0
- data/spec/ruby-progressbar/output_spec.rb +7 -0
- data/spec/ruby-progressbar/outputs/non_tty_spec.rb +9 -0
- data/spec/ruby-progressbar/outputs/tty_spec.rb +9 -0
- data/spec/ruby-progressbar/progress_spec.rb +150 -0
- data/spec/ruby-progressbar/time_spec.rb +37 -0
- data/spec/ruby-progressbar/timer_spec.rb +7 -0
- data/spec/spec_helper.rb +2 -2
- data/spec/support/time.rb +3 -1
- metadata +55 -35
- data/lib/ruby-progressbar/components/elapsed_timer.rb +0 -25
- data/lib/ruby-progressbar/components/estimated_timer.rb +0 -90
- data/lib/ruby-progressbar/components/progressable.rb +0 -112
- data/lib/ruby-progressbar/components/throttle.rb +0 -21
- data/lib/ruby-progressbar/components/timer.rb +0 -69
- data/lib/ruby-progressbar/format/base.rb +0 -55
- data/lib/ruby-progressbar/formatter.rb +0 -112
- data/lib/ruby-progressbar/length_calculator.rb +0 -64
- data/lib/ruby-progressbar/running_average_calculator.rb +0 -7
- data/spec/lib/ruby-progressbar/components/bar_spec.rb +0 -210
- data/spec/lib/ruby-progressbar/components/elapsed_timer_spec.rb +0 -91
- data/spec/lib/ruby-progressbar/components/estimated_timer_spec.rb +0 -241
- data/spec/lib/ruby-progressbar/components/progressable_spec.rb +0 -47
- data/spec/lib/ruby-progressbar/components/throttle_spec.rb +0 -100
- data/spec/lib/ruby-progressbar/format/molecule_spec.rb +0 -22
- data/spec/lib/ruby-progressbar/running_average_calculator_spec.rb +0 -11
- data/spec/lib/ruby-progressbar/time_spec.rb +0 -49
@@ -1,40 +1,58 @@
|
|
1
|
-
class
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
1
|
+
class ProgressBar
|
2
|
+
module Format
|
3
|
+
class Molecule
|
4
|
+
MOLECULES = {
|
5
|
+
:t => [:title_comp, :title],
|
6
|
+
:T => [:title_comp, :title],
|
7
|
+
:c => [:progressable, :progress],
|
8
|
+
:C => [:progressable, :total],
|
9
|
+
:p => [:percentage, :percentage],
|
10
|
+
:P => [:percentage, :percentage_with_precision],
|
11
|
+
:j => [:percentage, :justified_percentage],
|
12
|
+
:J => [:percentage, :justified_percentage_with_precision],
|
13
|
+
:a => [:time, :elapsed_with_label],
|
14
|
+
:e => [:time, :estimated_with_unknown_oob],
|
15
|
+
:E => [:time, :estimated_with_friendly_oob],
|
16
|
+
:f => [:time, :estimated_with_no_oob],
|
17
|
+
:B => [:bar, :complete_bar],
|
18
|
+
:b => [:bar, :bar],
|
19
|
+
:w => [:bar, :bar_with_percentage],
|
20
|
+
:i => [:bar, :incomplete_space],
|
21
|
+
:r => [:rate, :rate_of_change],
|
22
|
+
:R => [:rate, :rate_of_change_with_precision],
|
23
|
+
}
|
24
|
+
|
25
|
+
BAR_MOLECULES = %w{w B b i}
|
26
|
+
|
27
|
+
attr_accessor :key,
|
28
|
+
:method_name
|
29
|
+
|
30
|
+
def initialize(letter)
|
31
|
+
self.key = letter
|
32
|
+
self.method_name = MOLECULES.fetch(key.to_sym)
|
33
|
+
end
|
34
|
+
|
35
|
+
def bar_molecule?
|
36
|
+
BAR_MOLECULES.include? key
|
37
|
+
end
|
38
|
+
|
39
|
+
def non_bar_molecule?
|
40
|
+
!bar_molecule?
|
41
|
+
end
|
42
|
+
|
43
|
+
def full_key
|
44
|
+
"%#{key}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def lookup_value(environment, length = 0)
|
48
|
+
component = environment.send(method_name[0])
|
49
|
+
|
50
|
+
if bar_molecule?
|
51
|
+
component.send(method_name[1], length).to_s
|
52
|
+
else
|
53
|
+
component.send(method_name[1]).to_s
|
38
54
|
end
|
39
55
|
end
|
40
56
|
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
class ProgressBar
|
2
|
+
module Format
|
3
|
+
class String < ::String
|
4
|
+
MOLECULE_PATTERN = /%[a-zA-Z]/
|
5
|
+
ANSI_SGR_PATTERN = /\e\[[\d;]+m/
|
6
|
+
|
7
|
+
def displayable_length
|
8
|
+
gsub(ANSI_SGR_PATTERN, '').length
|
9
|
+
end
|
10
|
+
|
11
|
+
def bar_molecule_placeholder_length
|
12
|
+
@bar_molecule_placeholder_length ||= bar_molecules.size * 2
|
13
|
+
end
|
14
|
+
|
15
|
+
def non_bar_molecules
|
16
|
+
@non_bar_molecules ||= molecules.select(&:non_bar_molecule?)
|
17
|
+
end
|
18
|
+
|
19
|
+
def bar_molecules
|
20
|
+
@bar_molecules ||= molecules.select(&:bar_molecule?)
|
21
|
+
end
|
22
|
+
|
23
|
+
def molecules
|
24
|
+
@molecules ||= begin
|
25
|
+
molecules = []
|
26
|
+
|
27
|
+
scan(MOLECULE_PATTERN) do |match|
|
28
|
+
molecules << Molecule.new(match[1, 1])
|
29
|
+
end
|
30
|
+
|
31
|
+
molecules
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
class ProgressBar
|
2
|
+
class Output
|
3
|
+
DEFAULT_OUTPUT_STREAM = $stdout
|
4
|
+
|
5
|
+
attr_accessor :stream
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
self.bar = options[:bar]
|
9
|
+
self.stream = options[:output] || DEFAULT_OUTPUT_STREAM
|
10
|
+
self.length_calculator = Calculators::Length.new(options)
|
11
|
+
self.throttle = Throttle.new(options)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.detect(options = {})
|
15
|
+
if (options[:output] || DEFAULT_OUTPUT_STREAM).tty?
|
16
|
+
Outputs::Tty.new(options)
|
17
|
+
else
|
18
|
+
Outputs::NonTty.new(options)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def log(string)
|
23
|
+
clear
|
24
|
+
stream.puts string
|
25
|
+
|
26
|
+
refresh(:force => true) unless bar.stopped?
|
27
|
+
end
|
28
|
+
|
29
|
+
def clear_string
|
30
|
+
' ' * length_calculator.length
|
31
|
+
end
|
32
|
+
|
33
|
+
def length
|
34
|
+
length_calculator.length
|
35
|
+
end
|
36
|
+
|
37
|
+
def with_refresh
|
38
|
+
yield
|
39
|
+
refresh
|
40
|
+
end
|
41
|
+
|
42
|
+
def refresh(options = {})
|
43
|
+
throttle.choke(:force_update_if => (bar.stopped? || options[:force])) do
|
44
|
+
clear if length_calculator.length_changed?
|
45
|
+
|
46
|
+
print_and_flush
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def print_and_flush
|
51
|
+
stream.print bar_update_string + eol
|
52
|
+
stream.flush
|
53
|
+
end
|
54
|
+
|
55
|
+
protected
|
56
|
+
|
57
|
+
attr_accessor :length_calculator,
|
58
|
+
:throttle,
|
59
|
+
:bar
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'ruby-progressbar/output'
|
2
|
+
|
3
|
+
class ProgressBar
|
4
|
+
module Outputs
|
5
|
+
class NonTty < Output
|
6
|
+
DEFAULT_FORMAT_STRING = '%t: |%b|'
|
7
|
+
|
8
|
+
def clear
|
9
|
+
self.last_update_length = 0
|
10
|
+
|
11
|
+
stream.print "\n"
|
12
|
+
end
|
13
|
+
|
14
|
+
def last_update_length
|
15
|
+
@last_update_length ||= 0
|
16
|
+
end
|
17
|
+
|
18
|
+
def bar_update_string
|
19
|
+
formatted_string = bar.to_s
|
20
|
+
formatted_string = formatted_string[0...-1] unless bar.finished?
|
21
|
+
|
22
|
+
output_string = formatted_string[last_update_length..-1]
|
23
|
+
self.last_update_length = formatted_string.length
|
24
|
+
|
25
|
+
output_string
|
26
|
+
end
|
27
|
+
|
28
|
+
def default_format
|
29
|
+
DEFAULT_FORMAT_STRING
|
30
|
+
end
|
31
|
+
|
32
|
+
def resolve_format(*)
|
33
|
+
default_format
|
34
|
+
end
|
35
|
+
|
36
|
+
def refresh_with_format_change(*); end
|
37
|
+
|
38
|
+
def eol
|
39
|
+
bar.stopped? ? "\n" : ''
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
attr_accessor :last_update_length
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'ruby-progressbar/output'
|
2
|
+
|
3
|
+
class ProgressBar
|
4
|
+
module Outputs
|
5
|
+
class Tty < Output
|
6
|
+
DEFAULT_FORMAT_STRING = '%t: |%B|'
|
7
|
+
|
8
|
+
alias_method :refresh_with_format_change, :with_refresh
|
9
|
+
|
10
|
+
def clear
|
11
|
+
stream.print clear_string
|
12
|
+
stream.print "\r"
|
13
|
+
end
|
14
|
+
|
15
|
+
def bar_update_string
|
16
|
+
bar.to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
def default_format
|
20
|
+
DEFAULT_FORMAT_STRING
|
21
|
+
end
|
22
|
+
|
23
|
+
def resolve_format(other_format)
|
24
|
+
other_format || default_format
|
25
|
+
end
|
26
|
+
|
27
|
+
def eol
|
28
|
+
bar.stopped? ? "\n" : "\r"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'ruby-progressbar/errors/invalid_progress_error'
|
2
|
+
|
3
|
+
class ProgressBar
|
4
|
+
class Progress
|
5
|
+
DEFAULT_TOTAL = 100
|
6
|
+
DEFAULT_BEGINNING_POSITION = 0
|
7
|
+
DEFAULT_SMOOTHING = 0.1
|
8
|
+
|
9
|
+
attr_accessor :total,
|
10
|
+
:progress,
|
11
|
+
:starting_position,
|
12
|
+
:running_average,
|
13
|
+
:smoothing
|
14
|
+
|
15
|
+
def initialize(options = {})
|
16
|
+
self.total = options.fetch(:total, DEFAULT_TOTAL)
|
17
|
+
self.smoothing = options[:smoothing] || DEFAULT_SMOOTHING
|
18
|
+
|
19
|
+
start :at => DEFAULT_BEGINNING_POSITION
|
20
|
+
end
|
21
|
+
|
22
|
+
def start(options = {})
|
23
|
+
self.running_average = 0
|
24
|
+
self.progress = \
|
25
|
+
self.starting_position = options[:at] || progress
|
26
|
+
end
|
27
|
+
|
28
|
+
def finish
|
29
|
+
self.progress = total
|
30
|
+
end
|
31
|
+
|
32
|
+
def finished?
|
33
|
+
@progress == @total
|
34
|
+
end
|
35
|
+
|
36
|
+
def increment
|
37
|
+
warn "WARNING: Your progress bar is currently at #{progress} out of #{total} " \
|
38
|
+
'and cannot be incremented. In v2.0.0 this will become a ' \
|
39
|
+
'ProgressBar::InvalidProgressError.' if progress == total
|
40
|
+
|
41
|
+
self.progress += 1 unless progress == total
|
42
|
+
end
|
43
|
+
|
44
|
+
def decrement
|
45
|
+
warn "WARNING: Your progress bar is currently at #{progress} out of #{total} " \
|
46
|
+
'and cannot be decremented. In v2.0.0 this will become a ' \
|
47
|
+
'ProgressBar::InvalidProgressError.' if progress == 0
|
48
|
+
|
49
|
+
self.progress -= 1 unless progress == 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def reset
|
53
|
+
start :at => starting_position
|
54
|
+
end
|
55
|
+
|
56
|
+
def progress=(new_progress)
|
57
|
+
fail ProgressBar::InvalidProgressError,
|
58
|
+
"You can't set the item's current value to be greater than the total." \
|
59
|
+
if total &&
|
60
|
+
new_progress > total
|
61
|
+
|
62
|
+
@progress = new_progress
|
63
|
+
|
64
|
+
self.running_average = Calculators::RunningAverage.calculate(running_average,
|
65
|
+
absolute,
|
66
|
+
smoothing)
|
67
|
+
end
|
68
|
+
|
69
|
+
def total=(new_total)
|
70
|
+
fail ProgressBar::InvalidProgressError,
|
71
|
+
"You can't set the item's total value to less than the current progress." \
|
72
|
+
unless progress.nil? ||
|
73
|
+
new_total.nil? ||
|
74
|
+
new_total >= progress
|
75
|
+
|
76
|
+
@total = new_total
|
77
|
+
end
|
78
|
+
|
79
|
+
def percentage_completed
|
80
|
+
return 0 if total.nil?
|
81
|
+
return 100 if total.zero?
|
82
|
+
|
83
|
+
# progress / total * 100
|
84
|
+
#
|
85
|
+
# Doing this way so we can avoid converting each
|
86
|
+
# number to a float and then back to an integer.
|
87
|
+
#
|
88
|
+
(progress * 100 / total).to_i
|
89
|
+
end
|
90
|
+
|
91
|
+
def none?
|
92
|
+
progress.zero?
|
93
|
+
end
|
94
|
+
|
95
|
+
def unknown?
|
96
|
+
progress.nil? || total.nil?
|
97
|
+
end
|
98
|
+
|
99
|
+
def percentage_completed_with_precision
|
100
|
+
return 100.0 if total == 0
|
101
|
+
return 0.0 if total.nil?
|
102
|
+
|
103
|
+
format('%5.2f', (progress.to_f * 100.0 / total * 100.0).floor / 100.0)
|
104
|
+
end
|
105
|
+
|
106
|
+
def absolute
|
107
|
+
progress - starting_position
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class ProgressBar
|
2
|
+
class Throttle
|
3
|
+
attr_accessor :rate,
|
4
|
+
:started_at,
|
5
|
+
:stopped_at,
|
6
|
+
:timer
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
self.rate = options[:throttle_rate] || 0.01
|
10
|
+
self.started_at = nil
|
11
|
+
self.stopped_at = nil
|
12
|
+
self.timer = options.fetch(:throttle_timer, Timer.new)
|
13
|
+
end
|
14
|
+
|
15
|
+
def choke(options = {})
|
16
|
+
return unless !timer.started? ||
|
17
|
+
options.fetch(:force_update_if, false) ||
|
18
|
+
timer.elapsed_seconds >= rate
|
19
|
+
|
20
|
+
timer.restart
|
21
|
+
|
22
|
+
yield
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,22 +1,25 @@
|
|
1
|
-
class
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
class ProgressBar
|
2
|
+
class Time
|
3
|
+
def self.now(time = ::Time)
|
4
|
+
@time = time
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
@time.send unmocked_time_method
|
7
|
+
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
def self.unmocked_time_method
|
10
|
+
@unmocked_time_method ||= begin
|
11
|
+
time_mocking_library_methods.find do |method|
|
12
|
+
@time.respond_to? method
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
13
16
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
17
|
+
def self.time_mocking_library_methods
|
18
|
+
[
|
19
|
+
:now_without_mock_time, # Timecop
|
20
|
+
:now_without_delorean, # Delorean
|
21
|
+
:now # Actual
|
22
|
+
]
|
21
23
|
end
|
22
24
|
end
|
25
|
+
end
|