progressbar 0.21.0 → 1.8.1

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. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/LICENSE.txt +19 -0
  5. data/README.md +38 -0
  6. data/Rakefile +2 -14
  7. data/lib/progressbar.rb +14 -284
  8. data/lib/ruby-progressbar/base.rb +161 -0
  9. data/lib/ruby-progressbar/calculators/length.rb +88 -0
  10. data/lib/ruby-progressbar/calculators/length_spec.rb +9 -0
  11. data/lib/ruby-progressbar/calculators/running_average.rb +9 -0
  12. data/lib/ruby-progressbar/components.rb +5 -0
  13. data/lib/ruby-progressbar/components/bar.rb +96 -0
  14. data/lib/ruby-progressbar/components/percentage.rb +29 -0
  15. data/lib/ruby-progressbar/components/rate.rb +43 -0
  16. data/lib/ruby-progressbar/components/time.rb +103 -0
  17. data/lib/ruby-progressbar/components/title.rb +13 -0
  18. data/lib/ruby-progressbar/errors/invalid_progress_error.rb +4 -0
  19. data/lib/ruby-progressbar/format.rb +3 -0
  20. data/lib/ruby-progressbar/format/formatter.rb +27 -0
  21. data/lib/ruby-progressbar/format/molecule.rb +58 -0
  22. data/lib/ruby-progressbar/format/string.rb +36 -0
  23. data/lib/ruby-progressbar/output.rb +61 -0
  24. data/lib/ruby-progressbar/outputs/non_tty.rb +47 -0
  25. data/lib/ruby-progressbar/outputs/tty.rb +32 -0
  26. data/lib/ruby-progressbar/progress.rb +114 -0
  27. data/lib/ruby-progressbar/throttle.rb +25 -0
  28. data/lib/ruby-progressbar/time.rb +30 -0
  29. data/lib/ruby-progressbar/timer.rb +72 -0
  30. data/lib/ruby-progressbar/version.rb +3 -0
  31. data/spec/fixtures/benchmark.rb +28 -0
  32. data/spec/ruby-progressbar/base_spec.rb +949 -0
  33. data/spec/ruby-progressbar/calculators/length_calculator_spec.rb +17 -0
  34. data/spec/ruby-progressbar/calculators/running_average_spec.rb +19 -0
  35. data/spec/ruby-progressbar/components/bar_spec.rb +234 -0
  36. data/spec/ruby-progressbar/components/percentage_spec.rb +9 -0
  37. data/spec/ruby-progressbar/components/rate_spec.rb +9 -0
  38. data/spec/ruby-progressbar/components/throttle_spec.rb +157 -0
  39. data/spec/ruby-progressbar/components/time_spec.rb +307 -0
  40. data/spec/ruby-progressbar/components/title_spec.rb +12 -0
  41. data/spec/ruby-progressbar/format/formatter_spec.rb +9 -0
  42. data/spec/ruby-progressbar/format/molecule_spec.rb +30 -0
  43. data/spec/ruby-progressbar/format/string_spec.rb +9 -0
  44. data/spec/ruby-progressbar/output_spec.rb +7 -0
  45. data/spec/ruby-progressbar/outputs/non_tty_spec.rb +9 -0
  46. data/spec/ruby-progressbar/outputs/tty_spec.rb +9 -0
  47. data/spec/ruby-progressbar/progress_spec.rb +156 -0
  48. data/spec/ruby-progressbar/time_spec.rb +45 -0
  49. data/spec/ruby-progressbar/timer_spec.rb +7 -0
  50. data/spec/spec_helper.rb +6 -0
  51. data/spec/support/time.rb +17 -0
  52. metadata +134 -69
  53. metadata.gz.sig +3 -0
  54. data/.gitignore +0 -23
  55. data/.ruby-version +0 -1
  56. data/.travis.yml +0 -6
  57. data/ChangeLog +0 -113
  58. data/Gemfile +0 -4
  59. data/Gemfile.lock +0 -27
  60. data/LICENSE +0 -1
  61. data/README.rdoc +0 -116
  62. data/progressbar.gemspec +0 -29
  63. data/test/test.rb +0 -125
@@ -0,0 +1,58 @@
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
+ }.freeze
24
+
25
+ BAR_MOLECULES = %w{w B b i}.freeze
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
54
+ end
55
+ end
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|'.freeze
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_writer :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|'.freeze
7
+
8
+ alias 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,114 @@
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_reader :total,
10
+ :progress
11
+
12
+ attr_accessor :starting_position,
13
+ :running_average,
14
+ :smoothing
15
+
16
+ def initialize(options = {})
17
+ self.total = options.fetch(:total, DEFAULT_TOTAL)
18
+ self.smoothing = options[:smoothing] || DEFAULT_SMOOTHING
19
+
20
+ start :at => DEFAULT_BEGINNING_POSITION
21
+ end
22
+
23
+ def start(options = {})
24
+ self.running_average = 0
25
+ self.progress = \
26
+ self.starting_position = options[:at] || progress
27
+ end
28
+
29
+ def finish
30
+ self.progress = total unless unknown?
31
+ end
32
+
33
+ def finished?
34
+ @progress == @total
35
+ end
36
+
37
+ def increment
38
+ if progress == total
39
+ warn "WARNING: Your progress bar is currently at #{progress} out of #{total} " \
40
+ "and cannot be incremented. In v2.0.0 this will become a " \
41
+ "ProgressBar::InvalidProgressError."
42
+ end
43
+
44
+ self.progress += 1 unless progress == total
45
+ end
46
+
47
+ def decrement
48
+ if progress == 0
49
+ warn "WARNING: Your progress bar is currently at #{progress} out of #{total} " \
50
+ "and cannot be decremented. In v2.0.0 this will become a " \
51
+ "ProgressBar::InvalidProgressError."
52
+ end
53
+
54
+ self.progress -= 1 unless progress == 0
55
+ end
56
+
57
+ def reset
58
+ start :at => starting_position
59
+ end
60
+
61
+ def progress=(new_progress)
62
+ if total && new_progress > total
63
+ fail ProgressBar::InvalidProgressError,
64
+ "You can't set the item's current value to be greater than the total."
65
+ end
66
+
67
+ @progress = new_progress
68
+
69
+ self.running_average = Calculators::RunningAverage.calculate(running_average,
70
+ absolute,
71
+ smoothing)
72
+ end
73
+
74
+ def total=(new_total)
75
+ unless progress.nil? || new_total.nil? || new_total >= progress
76
+ fail ProgressBar::InvalidProgressError,
77
+ "You can't set the item's total value to less than the current progress."
78
+ end
79
+
80
+ @total = new_total
81
+ end
82
+
83
+ def percentage_completed
84
+ return 0 if total.nil?
85
+ return 100 if total == 0
86
+
87
+ # progress / total * 100
88
+ #
89
+ # Doing this way so we can avoid converting each
90
+ # number to a float and then back to an integer.
91
+ #
92
+ (progress * 100 / total).to_i
93
+ end
94
+
95
+ def none?
96
+ running_average.zero? || progress.zero?
97
+ end
98
+
99
+ def unknown?
100
+ progress.nil? || total.nil?
101
+ end
102
+
103
+ def percentage_completed_with_precision
104
+ return 100.0 if total == 0
105
+ return 0.0 if total.nil?
106
+
107
+ '%5.2f' % [(progress * 100 / total.to_f * 100).floor / 100.0]
108
+ end
109
+
110
+ def absolute
111
+ progress - starting_position
112
+ end
113
+ end
114
+ 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
@@ -0,0 +1,30 @@
1
+ class ProgressBar
2
+ class Time
3
+ TIME_MOCKING_LIBRARY_METHODS = [
4
+ :__simple_stub__now, # ActiveSupport
5
+ :now_without_mock_time, # Timecop
6
+ :now_without_delorean, # Delorean
7
+ :now # Actual
8
+ ].freeze
9
+
10
+ def initialize(time = ::Time)
11
+ self.time = time
12
+ end
13
+
14
+ def now
15
+ time.__send__ unmocked_time_method
16
+ end
17
+
18
+ def unmocked_time_method
19
+ @unmocked_time_method ||= begin
20
+ TIME_MOCKING_LIBRARY_METHODS.find do |method|
21
+ time.respond_to? method
22
+ end
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ attr_accessor :time
29
+ end
30
+ end
@@ -0,0 +1,72 @@
1
+ require 'ruby-progressbar/time'
2
+
3
+ class ProgressBar
4
+ class Timer
5
+ attr_accessor :started_at,
6
+ :stopped_at
7
+
8
+ def initialize(options = {})
9
+ self.time = options[:time] || Time.new
10
+ end
11
+
12
+ def start
13
+ self.started_at = stopped? ? time.now - (stopped_at - started_at) : time.now
14
+ self.stopped_at = nil
15
+ end
16
+
17
+ def stop
18
+ return unless started?
19
+
20
+ self.stopped_at = time.now
21
+ end
22
+
23
+ def pause
24
+ stop
25
+ end
26
+
27
+ def resume
28
+ start
29
+ end
30
+
31
+ def started?
32
+ started_at
33
+ end
34
+
35
+ def stopped?
36
+ stopped_at
37
+ end
38
+
39
+ def reset
40
+ self.started_at = nil
41
+ self.stopped_at = nil
42
+ end
43
+
44
+ def reset?
45
+ !started_at
46
+ end
47
+
48
+ def restart
49
+ reset
50
+ start
51
+ end
52
+
53
+ def elapsed_seconds
54
+ ((stopped_at || time.now) - started_at)
55
+ end
56
+
57
+ def elapsed_whole_seconds
58
+ elapsed_seconds.floor
59
+ end
60
+
61
+ def divide_seconds(seconds)
62
+ hours, seconds = seconds.divmod(3600)
63
+ minutes, seconds = seconds.divmod(60)
64
+
65
+ [hours, minutes, seconds]
66
+ end
67
+
68
+ protected
69
+
70
+ attr_accessor :time
71
+ end
72
+ end