ruby-progressbar 0.11.0 → 1.0.0rc1

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 (43) hide show
  1. data/.gitignore +5 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +3 -0
  6. data/Gemfile.lock +42 -0
  7. data/Guardfile +6 -0
  8. data/LICENSE +22 -0
  9. data/README.md +229 -63
  10. data/lib/progress_bar/base.rb +166 -0
  11. data/lib/progress_bar/components.rb +5 -0
  12. data/lib/progress_bar/components/bar.rb +44 -0
  13. data/lib/progress_bar/components/elapsed_timer.rb +20 -0
  14. data/lib/progress_bar/components/estimated_timer.rb +88 -0
  15. data/lib/progress_bar/components/progressable.rb +92 -0
  16. data/lib/progress_bar/components/timer.rb +64 -0
  17. data/lib/progress_bar/depreciable.rb +121 -0
  18. data/lib/progress_bar/format.rb +2 -0
  19. data/lib/progress_bar/format/base.rb +30 -0
  20. data/lib/progress_bar/format/molecule.rb +37 -0
  21. data/lib/progress_bar/formatter.rb +109 -0
  22. data/lib/progress_bar/length_calculator.rb +53 -0
  23. data/lib/progress_bar/running_average_calculator.rb +7 -0
  24. data/lib/progress_bar/time.rb +22 -0
  25. data/lib/progress_bar/version.rb +3 -0
  26. data/lib/progressbar.rb +8 -295
  27. data/lib/ruby-progressbar.rb +19 -0
  28. data/ruby-progressbar.gemspec +44 -0
  29. data/spec/progress_bar/base_spec.rb +434 -0
  30. data/spec/progress_bar/components/bar_spec.rb +198 -0
  31. data/spec/progress_bar/components/elapsed_timer_spec.rb +79 -0
  32. data/spec/progress_bar/components/estimated_timer_spec.rb +173 -0
  33. data/spec/progress_bar/components/progressable_spec.rb +30 -0
  34. data/spec/progress_bar/format/molecule_spec.rb +22 -0
  35. data/spec/progress_bar/running_average_calculator_spec.rb +11 -0
  36. data/spec/progress_bar/time_spec.rb +51 -0
  37. data/spec/spec_helper.rb +13 -0
  38. data/spec/support/focused.rb +7 -0
  39. data/spec/support/timecop.rb +19 -0
  40. metadata +170 -19
  41. data/GPL_LICENSE +0 -340
  42. data/RUBY_LICENSE +0 -53
  43. data/test.rb +0 -247
@@ -0,0 +1,5 @@
1
+ require 'progress_bar/components/timer'
2
+ require 'progress_bar/components/progressable'
3
+ require 'progress_bar/components/bar'
4
+ require 'progress_bar/components/estimated_timer'
5
+ require 'progress_bar/components/elapsed_timer'
@@ -0,0 +1,44 @@
1
+ class ProgressBar
2
+ module Components
3
+ class Bar
4
+ include Progressable
5
+
6
+ DEFAULT_PROGRESS_MARK = '='
7
+
8
+ attr_accessor :progress_mark
9
+ attr_accessor :length
10
+
11
+ def initialize(options = {})
12
+ super
13
+
14
+ self.progress_mark = options[:progress_mark] || DEFAULT_PROGRESS_MARK
15
+ end
16
+
17
+ def to_s(options = {:format => :standard})
18
+ completed_string = send(:"#{options[:format]}_complete_string")
19
+ empty_string = ' ' * (length - completed_string.length)
20
+
21
+ "#{completed_string}#{empty_string}"
22
+ end
23
+
24
+ def integrated_percentage_complete_string
25
+ return standard_complete_string if completed_length < 5
26
+
27
+ " #{percentage_completed} ".to_s.center(completed_length, progress_mark)
28
+ end
29
+
30
+ def standard_complete_string
31
+ progress_mark * completed_length
32
+ end
33
+
34
+ def empty_string
35
+ ' ' * (length - completed_length)
36
+ end
37
+
38
+ private
39
+ def completed_length
40
+ length * percentage_completed / 100
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,20 @@
1
+ class ProgressBar
2
+ module Components
3
+ class ElapsedTimer
4
+ include Timer
5
+
6
+ def to_s
7
+ "Time: #{elapsed_time}"
8
+ end
9
+
10
+ private
11
+ def elapsed_time
12
+ return '--:--:--' unless started?
13
+
14
+ hours, minutes, seconds = divide_seconds(elapsed_seconds)
15
+
16
+ sprintf TIME_FORMAT, hours, minutes, seconds
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,88 @@
1
+ class ProgressBar
2
+ module Components
3
+ class EstimatedTimer
4
+ include Timer
5
+ include Progressable
6
+
7
+ VALID_OOB_TIME_FORMATS = [:unknown, :friendly, nil]
8
+
9
+ def initialize(options = {})
10
+ super
11
+ end
12
+
13
+ def start(options = {})
14
+ as(Timer).start
15
+ as(Progressable).start(options)
16
+ end
17
+
18
+ def reset
19
+ as(Timer).reset
20
+ as(Progressable).reset
21
+ end
22
+
23
+ def out_of_bounds_time_format=(format)
24
+ raise "Invalid Out Of Bounds time format. Valid formats are #{VALID_OOB_TIME_FORMATS.inspect}" unless VALID_OOB_TIME_FORMATS.include? format
25
+
26
+ @out_of_bounds_time_format = format
27
+ end
28
+
29
+ def to_s
30
+ " ETA: #{estimated_time}"
31
+ end
32
+
33
+ private
34
+ def estimated_time
35
+ return '??:??:??' if progress_made.zero?
36
+
37
+ hours, minutes, seconds = divide_seconds(estimated_seconds_remaining)
38
+
39
+ if hours > 99 && @out_of_bounds_time_format
40
+ out_of_bounds_time
41
+ else
42
+ sprintf TIME_FORMAT, hours, minutes, seconds
43
+ end
44
+ end
45
+
46
+ def average_seconds_per_each
47
+ return 0 if self.running_average.zero?
48
+
49
+ elapsed_seconds.to_f / self.running_average
50
+ end
51
+
52
+ def estimated_seconds_remaining
53
+ ((average_seconds_per_each * self.total) - elapsed_seconds.to_f).floor
54
+ end
55
+
56
+ def out_of_bounds_time
57
+ case @out_of_bounds_time_format
58
+ when :unknown
59
+ '??:??:??'
60
+ when :friendly
61
+ '> 4 Days'
62
+ end
63
+ end
64
+
65
+ def as(ancestor, &blk)
66
+ @__as ||= {}
67
+ unless r = @__as[ancestor]
68
+ r = (@__as[ancestor] = As.new(self, ancestor))
69
+ end
70
+ r.instance_eval(&blk) if block_given?
71
+ r
72
+ end
73
+
74
+ class As
75
+ private *instance_methods.select { |m| m !~ /(^__|^\W|^binding$)/ }
76
+
77
+ def initialize(subject, ancestor)
78
+ @subject = subject
79
+ @ancestor = ancestor
80
+ end
81
+
82
+ def method_missing(sym, *args, &blk)
83
+ @ancestor.instance_method(sym).bind(@subject).call(*args,&blk)
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,92 @@
1
+ class ProgressBar
2
+ module Components
3
+ module Progressable
4
+ DEFAULT_TOTAL = 100
5
+ DEFAULT_BEGINNING_POSITION = 0
6
+ DEFAULT_SMOOTHING = 0.1
7
+
8
+ attr_reader :total
9
+ attr_reader :progress
10
+ attr_accessor :starting_position
11
+ attr_accessor :running_average
12
+ attr_accessor :smoothing
13
+
14
+ def initialize(options = {})
15
+ self.total = options[:total] || DEFAULT_TOTAL
16
+ self.smoothing = options[:smoothing] || DEFAULT_SMOOTHING
17
+
18
+ start :at => DEFAULT_BEGINNING_POSITION
19
+ end
20
+
21
+ def start(options = {})
22
+ self.running_average = 0
23
+
24
+ self.progress = \
25
+ self.starting_position = options[:at] || self.progress
26
+ end
27
+
28
+ def started?
29
+ !!self.starting_position
30
+ end
31
+
32
+ def increment
33
+ self.progress += 1 unless progress == total
34
+ end
35
+
36
+ def decrement
37
+ self.progress -= 1 unless progress == 0
38
+ end
39
+
40
+ def reset
41
+ start :at => self.starting_position
42
+ end
43
+
44
+ def progress=(new_progress)
45
+ validate_progress(new_progress)
46
+
47
+ @progress = new_progress
48
+
49
+ update_running_average
50
+ end
51
+
52
+ def total=(new_total)
53
+ validate_total(new_total)
54
+ @total = new_total
55
+ end
56
+
57
+ def finish
58
+ self.progress = self.total
59
+ end
60
+
61
+ def percentage_completed
62
+ # progress / total * 100
63
+ #
64
+ # Doing this way so we can avoid converting each
65
+ # number to a float and then back to an integer.
66
+ #
67
+ self.progress * 100 / total
68
+ end
69
+
70
+ def percentage_completed_with_precision
71
+ format('%5.2f', (progress.to_f * 100.0 / total * 100.0).floor / 100.0)
72
+ end
73
+
74
+ private
75
+ def validate_total(new_total)
76
+ (progress.nil? || new_total >= progress) || raise("You can't set the item's total value to be less than the current progress.")
77
+ end
78
+
79
+ def validate_progress(new_progress)
80
+ (total.nil? || new_progress <= total) || raise("You can't set the item's current value to be greater than the total.")
81
+ end
82
+
83
+ def progress_made
84
+ started? ? self.progress - self.starting_position : 0
85
+ end
86
+
87
+ def update_running_average
88
+ self.running_average = RunningAverageCalculator.calculate(self.running_average, self.progress, self.smoothing)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,64 @@
1
+ require 'progress_bar/time'
2
+
3
+ class ProgressBar
4
+ module Components
5
+ module Timer
6
+ TIME_FORMAT = '%02d:%02d:%02d'
7
+
8
+ def start
9
+ @started_at = stopped? ? now - (@stopped_at - @started_at) : now
10
+ @stopped_at = nil
11
+ end
12
+
13
+ def stop
14
+ @stopped_at = now
15
+ end
16
+
17
+ def pause
18
+ stop
19
+ end
20
+
21
+ def resume
22
+ start
23
+ end
24
+
25
+ def started?
26
+ !!@started_at
27
+ end
28
+
29
+ def stopped?
30
+ !!@stopped_at
31
+ end
32
+
33
+ def reset
34
+ @started_at = nil
35
+ @stopped_at = nil
36
+ end
37
+
38
+ private
39
+ def now
40
+ ProgressBar::Time.now
41
+ end
42
+
43
+ def elapsed_seconds
44
+ ((@stopped_at || now) - @started_at).floor
45
+ end
46
+
47
+ def elapsed_time
48
+ return '--:--:--' unless started?
49
+
50
+ hours, seconds = elapsed_seconds.divmod(3600)
51
+ minutes, seconds = seconds.divmod(60)
52
+
53
+ sprintf TIME_FORMAT, hours, minutes, seconds
54
+ end
55
+
56
+ def divide_seconds(seconds)
57
+ hours, seconds = seconds.divmod(3600)
58
+ minutes, seconds = seconds.divmod(60)
59
+
60
+ [hours, minutes, seconds]
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,121 @@
1
+ class ProgressBar
2
+ module Depreciable
3
+ DEPRECATION_DATE = "June 30th, 2013"
4
+
5
+ def backwards_compatible_args_to_options_conversion(args)
6
+ options = {}
7
+
8
+ if args.size > 1
9
+ puts "DEPRECATION WARNING: Creating progress bars using ProgressBar.new(title, total, output_io) has been deprecated and will be removed on or after #{DEPRECATION_DATE}. Please use ProgressBar.create(:title => title, :total => total, :output => output_io) instead. The full list of options can be found here: https://github.com/jfelchner/ruby-progressbar."
10
+ options[:title] = args[0]
11
+ options[:total] = args[1]
12
+ options[:output] = args[2]
13
+ else
14
+ options = args[0]
15
+ end
16
+
17
+ options
18
+ end
19
+
20
+ def inc(value = nil)
21
+ if value.nil?
22
+ method_deprecation_message 'inc', 'increment'
23
+
24
+ increment
25
+ else
26
+ method_removal_message 'inc', 'Rather than passing a step increment to the new #increment method, you can simply do `my_progress_bar.progress += step`.'
27
+
28
+ progress = progress + value.to_i
29
+ end
30
+ end
31
+
32
+ def set(new_value)
33
+ method_deprecation_message 'set', 'progress='
34
+
35
+ progress = new_value
36
+ end
37
+
38
+ def halt
39
+ method_deprecation_message 'halt', 'stop'
40
+
41
+ stop
42
+ end
43
+
44
+ def bar_mark=(mark)
45
+ method_deprecation_message 'bar_mark=', 'progress_mark='
46
+
47
+ progress_mark = mark
48
+ end
49
+
50
+ def title_width
51
+ method_removal_message 'title_width', 'The formatter is now smart enough to handle any title you use. Set the format for the bar as described here: https://github.com/jfelchner/ruby-progressbar'
52
+ end
53
+
54
+ def title_width=(value)
55
+ method_removal_message 'title_width=', 'The formatter is now smart enough to handle any title you use. Set the format for the bar as described here: https://github.com/jfelchner/ruby-progressbar'
56
+ end
57
+
58
+ def start_time
59
+ method_deprecation_message 'start_time'
60
+
61
+ @elapsed_time.instance_variable_get(:@started_at)
62
+ end
63
+
64
+ def start_time=(value)
65
+ method_removal_message 'start_time=', 'It is no longer appropriate to set the start time of the bar. Using #start, #stop, #pause and #resume all work as expected.'
66
+ end
67
+
68
+ def format=(value)
69
+ method_removal_message 'format=', 'The formatter has been completely rewriten for v1.0. Please use `#format(format_string)`. See https://github.com/jfelchner/ruby-progressbar for all the formatting options.'
70
+ end
71
+
72
+ def format_arguments=(value)
73
+ method_removal_message 'format_arguments=', 'The formatter has been completely rewriten for v1.0. Please use `#format(format_string)`. See https://github.com/jfelchner/ruby-progressbar for all the formatting options.'
74
+ end
75
+
76
+ def current
77
+ method_deprecation_message 'current', 'progress'
78
+
79
+ @bar.progress
80
+ end
81
+
82
+ def smoothing
83
+ method_removal_message 'smoothing'
84
+ end
85
+
86
+ def smoothing=(value)
87
+ method_removal_message 'smoothing=', 'This value can only be set via the options hash when creating a new progress bar like so: ProgressBar.create(:smoothing => 0.2)'
88
+ end
89
+
90
+ def file_transfer_mode
91
+ method_removal_message 'file_transfer_mode', 'We will be implementing a much better file transfer progress bar in the upcoming version however it has been removed for v1.0. If you still require this functionality, you should remain at v0.11.0'
92
+ end
93
+
94
+ private
95
+
96
+ def method_deprecation_message(old_item, new_item = '')
97
+ message_has_not_been_shown?(old_item) do
98
+ replacement_message = new_item.empty? ? 'There will be no replacement.' : "Please use ##{new_item} instead."
99
+ puts "DEPRECATION WARNING: ##{old_item} will be removed on or after #{DEPRECATION_DATE}. #{replacement_message}"
100
+ end
101
+ end
102
+
103
+ def method_removal_message(old_item, message = '')
104
+ message_has_not_been_shown?(old_item) do
105
+ puts "REMOVAL WARNING: ##{old_item} has been removed. There is no replacement. #{message}"
106
+ end
107
+ end
108
+
109
+ def safe_string(item)
110
+ item.gsub('=', '_setter')
111
+ end
112
+
113
+ def message_has_not_been_shown?(item)
114
+ unless instance_variable_get(:"@#{safe_string item}_deprecation_warning")
115
+ instance_variable_set(:"@#{safe_string item}_deprecation_warning", true)
116
+
117
+ yield
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,2 @@
1
+ require 'progress_bar/format/molecule'
2
+ require 'progress_bar/format/base'
@@ -0,0 +1,30 @@
1
+ class ProgressBar
2
+ module Format
3
+ class Base
4
+ attr_reader :molecules
5
+
6
+ def initialize(format_string)
7
+ @molecules = parse(format_string)
8
+ end
9
+
10
+ def non_bar_molecules
11
+ molecules.select { |molecule| !molecule.bar_molecule? }
12
+ end
13
+
14
+ def bar_molecules
15
+ molecules.select { |molecule| molecule.bar_molecule? }
16
+ end
17
+
18
+ private
19
+ def parse(format_string)
20
+ molecules = []
21
+
22
+ format_string.scan(/%[a-zA-Z]/) do |match|
23
+ molecules << Molecule.new(match[1])
24
+ end
25
+
26
+ molecules
27
+ end
28
+ end
29
+ end
30
+ end