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.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/lib/ruby-progressbar.rb +8 -3
  4. data/lib/ruby-progressbar/base.rb +121 -177
  5. data/lib/ruby-progressbar/calculators/length.rb +75 -0
  6. data/lib/ruby-progressbar/calculators/length_spec.rb +9 -0
  7. data/lib/ruby-progressbar/calculators/running_average.rb +9 -0
  8. data/lib/ruby-progressbar/components.rb +3 -5
  9. data/lib/ruby-progressbar/components/bar.rb +79 -43
  10. data/lib/ruby-progressbar/components/percentage.rb +29 -0
  11. data/lib/ruby-progressbar/components/rate.rb +34 -62
  12. data/lib/ruby-progressbar/components/time.rb +103 -0
  13. data/lib/ruby-progressbar/components/title.rb +13 -0
  14. data/lib/ruby-progressbar/format.rb +2 -1
  15. data/lib/ruby-progressbar/format/formatter.rb +27 -0
  16. data/lib/ruby-progressbar/format/molecule.rb +55 -37
  17. data/lib/ruby-progressbar/format/string.rb +36 -0
  18. data/lib/ruby-progressbar/output.rb +61 -0
  19. data/lib/ruby-progressbar/outputs/non_tty.rb +47 -0
  20. data/lib/ruby-progressbar/outputs/tty.rb +32 -0
  21. data/lib/ruby-progressbar/progress.rb +110 -0
  22. data/lib/ruby-progressbar/throttle.rb +25 -0
  23. data/lib/ruby-progressbar/time.rb +20 -17
  24. data/lib/ruby-progressbar/timer.rb +72 -0
  25. data/lib/ruby-progressbar/version.rb +2 -2
  26. data/spec/fixtures/benchmark.rb +21 -4
  27. data/spec/{lib/ruby-progressbar → ruby-progressbar}/base_spec.rb +55 -62
  28. data/spec/ruby-progressbar/calculators/running_average_spec.rb +19 -0
  29. data/spec/ruby-progressbar/components/bar_spec.rb +234 -0
  30. data/spec/ruby-progressbar/components/percentage_spec.rb +9 -0
  31. data/spec/ruby-progressbar/components/rate_spec.rb +9 -0
  32. data/spec/ruby-progressbar/components/throttle_spec.rb +157 -0
  33. data/spec/ruby-progressbar/components/time_spec.rb +308 -0
  34. data/spec/ruby-progressbar/components/title_spec.rb +12 -0
  35. data/spec/ruby-progressbar/format/formatter_spec.rb +9 -0
  36. data/spec/ruby-progressbar/format/molecule_spec.rb +30 -0
  37. data/spec/ruby-progressbar/format/string_spec.rb +9 -0
  38. data/spec/ruby-progressbar/output_spec.rb +7 -0
  39. data/spec/ruby-progressbar/outputs/non_tty_spec.rb +9 -0
  40. data/spec/ruby-progressbar/outputs/tty_spec.rb +9 -0
  41. data/spec/ruby-progressbar/progress_spec.rb +150 -0
  42. data/spec/ruby-progressbar/time_spec.rb +37 -0
  43. data/spec/ruby-progressbar/timer_spec.rb +7 -0
  44. data/spec/spec_helper.rb +2 -2
  45. data/spec/support/time.rb +3 -1
  46. metadata +55 -35
  47. data/lib/ruby-progressbar/components/elapsed_timer.rb +0 -25
  48. data/lib/ruby-progressbar/components/estimated_timer.rb +0 -90
  49. data/lib/ruby-progressbar/components/progressable.rb +0 -112
  50. data/lib/ruby-progressbar/components/throttle.rb +0 -21
  51. data/lib/ruby-progressbar/components/timer.rb +0 -69
  52. data/lib/ruby-progressbar/format/base.rb +0 -55
  53. data/lib/ruby-progressbar/formatter.rb +0 -112
  54. data/lib/ruby-progressbar/length_calculator.rb +0 -64
  55. data/lib/ruby-progressbar/running_average_calculator.rb +0 -7
  56. data/spec/lib/ruby-progressbar/components/bar_spec.rb +0 -210
  57. data/spec/lib/ruby-progressbar/components/elapsed_timer_spec.rb +0 -91
  58. data/spec/lib/ruby-progressbar/components/estimated_timer_spec.rb +0 -241
  59. data/spec/lib/ruby-progressbar/components/progressable_spec.rb +0 -47
  60. data/spec/lib/ruby-progressbar/components/throttle_spec.rb +0 -100
  61. data/spec/lib/ruby-progressbar/format/molecule_spec.rb +0 -22
  62. data/spec/lib/ruby-progressbar/running_average_calculator_spec.rb +0 -11
  63. data/spec/lib/ruby-progressbar/time_spec.rb +0 -49
@@ -1,40 +1,58 @@
1
- class ProgressBar
2
- module Format
3
- class Molecule
4
- MOLECULES = {
5
- :t => :title,
6
- :T => :title,
7
- :c => :progress,
8
- :C => :total,
9
- :p => :percentage,
10
- :P => :percentage_with_precision,
11
- :j => :justified_percentage,
12
- :J => :justified_percentage_with_precision,
13
- :a => :elapsed_time,
14
- :e => :estimated_time_with_unknown_oob,
15
- :E => :estimated_time_with_friendly_oob,
16
- :f => :estimated_time_with_no_oob,
17
- :B => :complete_bar,
18
- :b => :bar,
19
- :w => :bar_with_percentage,
20
- :i => :incomplete_space,
21
- :r => :rate_of_change,
22
- :R => :rate_of_change_with_precision,
23
- }
24
-
25
- BAR_MOLECULES = %w{w B b i}
26
-
27
- attr_reader :key
28
- attr_reader :method_name
29
-
30
- def initialize(letter)
31
- @key = letter
32
- @method_name = MOLECULES.fetch(@key.to_sym)
33
- end
34
-
35
- def bar_molecule?
36
- BAR_MOLECULES.include? @key
37
- end
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 ProgressBar
2
- class Time
3
- def self.now(time = ::Time)
4
- @@time = time
1
+ class ProgressBar
2
+ class Time
3
+ def self.now(time = ::Time)
4
+ @time = time
5
5
 
6
- @@time.send unmocked_time_method
7
- end
6
+ @time.send unmocked_time_method
7
+ end
8
8
 
9
- private
10
- def self.unmocked_time_method
11
- time_mocking_library_methods.find { |method| @@time.respond_to? method }
12
- end
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
- def self.time_mocking_library_methods
15
- [
16
- :now_without_mock_time, # Timecop
17
- :now_without_delorean, # Delorean
18
- :now # Actual
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