tty-progressbar 0.15.1 → 0.18.2

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 (104) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +63 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +495 -125
  5. data/lib/tty-progressbar.rb +2 -2
  6. data/lib/tty/progressbar.rb +169 -68
  7. data/lib/tty/progressbar/configuration.rb +121 -27
  8. data/lib/tty/progressbar/converter.rb +16 -19
  9. data/lib/tty/progressbar/formats.rb +120 -0
  10. data/lib/tty/progressbar/formatter.rb +33 -38
  11. data/lib/tty/progressbar/formatter/bar.rb +74 -27
  12. data/lib/tty/progressbar/formatter/byte_rate.rb +6 -20
  13. data/lib/tty/progressbar/formatter/current.rb +4 -19
  14. data/lib/tty/progressbar/formatter/current_byte.rb +9 -17
  15. data/lib/tty/progressbar/formatter/elapsed.rb +9 -18
  16. data/lib/tty/progressbar/formatter/estimated.rb +18 -20
  17. data/lib/tty/progressbar/formatter/estimated_time.rb +39 -0
  18. data/lib/tty/progressbar/formatter/mean_byte.rb +6 -20
  19. data/lib/tty/progressbar/formatter/mean_rate.rb +6 -20
  20. data/lib/tty/progressbar/formatter/percent.rb +10 -16
  21. data/lib/tty/progressbar/formatter/rate.rb +5 -19
  22. data/lib/tty/progressbar/formatter/total.rb +10 -16
  23. data/lib/tty/progressbar/formatter/total_byte.rb +14 -18
  24. data/lib/tty/progressbar/formatters.rb +53 -0
  25. data/lib/tty/progressbar/meter.rb +2 -2
  26. data/lib/tty/progressbar/multi.rb +61 -21
  27. data/lib/tty/progressbar/pipeline.rb +13 -6
  28. data/lib/tty/progressbar/timer.rb +89 -0
  29. data/lib/tty/progressbar/version.rb +3 -1
  30. metadata +56 -164
  31. data/.codeclimate.yml +0 -11
  32. data/.gitignore +0 -14
  33. data/.rspec +0 -3
  34. data/.travis.yml +0 -26
  35. data/CODE_OF_CONDUCT.md +0 -74
  36. data/Gemfile +0 -14
  37. data/Rakefile +0 -8
  38. data/appveyor.yml +0 -23
  39. data/examples/color.rb +0 -18
  40. data/examples/failure.rb +0 -12
  41. data/examples/iterator.rb +0 -5
  42. data/examples/lazy.rb +0 -6
  43. data/examples/multi/main_bar.rb +0 -13
  44. data/examples/multi/simple.rb +0 -13
  45. data/examples/multi/width.rb +0 -13
  46. data/examples/simple.rb +0 -7
  47. data/examples/slow_process.rb +0 -29
  48. data/examples/speed.rb +0 -11
  49. data/examples/threaded.rb +0 -14
  50. data/examples/tokens.rb +0 -12
  51. data/examples/unicode.rb +0 -7
  52. data/spec/spec_helper.rb +0 -51
  53. data/spec/unit/advance_spec.rb +0 -25
  54. data/spec/unit/clear_spec.rb +0 -17
  55. data/spec/unit/complete_spec.rb +0 -16
  56. data/spec/unit/converter/to_bytes_spec.rb +0 -47
  57. data/spec/unit/converter/to_seconds_spec.rb +0 -15
  58. data/spec/unit/converter/to_time_spec.rb +0 -19
  59. data/spec/unit/custom_formatter_spec.rb +0 -26
  60. data/spec/unit/custom_token_spec.rb +0 -14
  61. data/spec/unit/events_spec.rb +0 -33
  62. data/spec/unit/finish_spec.rb +0 -15
  63. data/spec/unit/formatter/bar_spec.rb +0 -16
  64. data/spec/unit/formatter/byte_rate_spec.rb +0 -32
  65. data/spec/unit/formatter/current_byte_spec.rb +0 -16
  66. data/spec/unit/formatter/current_spec.rb +0 -14
  67. data/spec/unit/formatter/elapsed_spec.rb +0 -58
  68. data/spec/unit/formatter/estimated_spec.rb +0 -27
  69. data/spec/unit/formatter/mean_byte_spec.rb +0 -32
  70. data/spec/unit/formatter/mean_rate_spec.rb +0 -31
  71. data/spec/unit/formatter/percent_spec.rb +0 -16
  72. data/spec/unit/formatter/rate_spec.rb +0 -31
  73. data/spec/unit/formatter/total_byte_spec.rb +0 -16
  74. data/spec/unit/formatter/total_spec.rb +0 -16
  75. data/spec/unit/frequency_spec.rb +0 -27
  76. data/spec/unit/head_spec.rb +0 -32
  77. data/spec/unit/hide_cursor_spec.rb +0 -27
  78. data/spec/unit/inspect_spec.rb +0 -11
  79. data/spec/unit/iterate_spec.rb +0 -79
  80. data/spec/unit/log_spec.rb +0 -29
  81. data/spec/unit/meter_spec.rb +0 -70
  82. data/spec/unit/multi/advance_spec.rb +0 -123
  83. data/spec/unit/multi/events_spec.rb +0 -115
  84. data/spec/unit/multi/finish_spec.rb +0 -41
  85. data/spec/unit/multi/line_inset_spec.rb +0 -65
  86. data/spec/unit/multi/register_spec.rb +0 -35
  87. data/spec/unit/multi/reset_spec.rb +0 -28
  88. data/spec/unit/multi/stop_spec.rb +0 -15
  89. data/spec/unit/multi/width_spec.rb +0 -118
  90. data/spec/unit/new_spec.rb +0 -76
  91. data/spec/unit/pipeline_spec.rb +0 -19
  92. data/spec/unit/ratio_spec.rb +0 -31
  93. data/spec/unit/render_spec.rb +0 -25
  94. data/spec/unit/reset_spec.rb +0 -31
  95. data/spec/unit/resize_spec.rb +0 -35
  96. data/spec/unit/set_current_spec.rb +0 -43
  97. data/spec/unit/start_spec.rb +0 -14
  98. data/spec/unit/stop_spec.rb +0 -19
  99. data/spec/unit/update_spec.rb +0 -22
  100. data/spec/unit/width_spec.rb +0 -86
  101. data/tasks/console.rake +0 -9
  102. data/tasks/coverage.rake +0 -9
  103. data/tasks/spec.rake +0 -27
  104. data/tty-progressbar.gemspec +0 -30
@@ -1,27 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../formatter"
4
+
3
5
  module TTY
4
6
  class ProgressBar
5
7
  # Used by {Pipeline} to format bar
6
8
  #
7
9
  # @api private
8
10
  class BarFormatter
9
- MATCHER = /:bar/.freeze
10
-
11
- def initialize(progress)
12
- @progress = progress
13
- end
14
-
15
- # Determines whether this formatter is applied or not.
16
- #
17
- # @param [Object] value
18
- #
19
- # @return [Boolean]
20
- #
21
- # @api private
22
- def matches?(value)
23
- !!(value.to_s =~ MATCHER)
24
- end
11
+ include TTY::ProgressBar::Formatter[/:bar/i.freeze]
25
12
 
26
13
  # Format :bar token
27
14
  #
@@ -29,30 +16,90 @@ module TTY
29
16
  # the value being formatted
30
17
  #
31
18
  # @api public
32
- def format(value)
33
- without_bar = value.gsub(/:bar/, '')
19
+ def call(value)
20
+ without_bar = value.gsub(/:bar/, "")
34
21
  available_space = [0, ProgressBar.max_columns -
35
22
  ProgressBar.display_columns(without_bar) -
36
23
  @progress.inset].max
37
- width = [@progress.width, available_space].min
24
+ width = [@progress.width.to_i, available_space].min
25
+
26
+ # When we don't know the total progress, use either user
27
+ # defined width or rely on terminal width detection
28
+ if @progress.indeterminate?
29
+ width = available_space if width.zero?
30
+
31
+ format_indeterminate(value, width)
32
+ else
33
+ format_determinate(value, width)
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ # @api private
40
+ def format_indeterminate(value, width)
41
+ buffer = []
42
+ possible_width = width
43
+ unknown_char_length = ProgressBar.display_columns(@progress.unknown)
44
+ complete_char_length = ProgressBar.display_columns(@progress.complete)
45
+ incomplete_char_length = ProgressBar.display_columns(@progress.incomplete)
46
+ head_char_length = ProgressBar.display_columns(@progress.head)
47
+
48
+ possible_width -= unknown_char_length
49
+ max_char_length = [complete_char_length, incomplete_char_length,
50
+ head_char_length].max
51
+ # figure out how many unicode chars would fit normally
52
+ # when the bar has total to prevent resizing
53
+ possible_width = (possible_width / max_char_length) * max_char_length
54
+ complete = (possible_width * @progress.ratio).round
55
+ incomplete = possible_width - complete
56
+
57
+ buffer << " " * complete
58
+ buffer << @progress.unknown
59
+ buffer << " " * incomplete
60
+
61
+ value.gsub(matcher, buffer.join)
62
+ end
63
+
64
+ # @api private
65
+ def format_determinate(value, width)
38
66
  complete_bar_length = (width * @progress.ratio).round
39
67
  complete_char_length = ProgressBar.display_columns(@progress.complete)
40
68
  incomplete_char_length = ProgressBar.display_columns(@progress.incomplete)
69
+ head_char_length = ProgressBar.display_columns(@progress.head)
41
70
 
42
- # decimal number of items only when unicode chars are used
71
+ # division by char length only when unicode chars are used
43
72
  # otherwise it has no effect on regular ascii chars
44
- complete_items = (complete_bar_length / complete_char_length.to_f).round
45
- incomplete_items = (width - complete_items * complete_char_length) / incomplete_char_length
73
+ complete_items = [
74
+ complete_bar_length / complete_char_length,
75
+ # or see how many incomplete (unicode) items fit
76
+ (complete_bar_length / incomplete_char_length) * incomplete_char_length
77
+ ].min
78
+
79
+ complete_width = complete_items * complete_char_length
80
+ incomplete_width = width - complete_width
81
+ incomplete_items = [
82
+ incomplete_width / incomplete_char_length,
83
+ # or see how many complete (unicode) items fit
84
+ (incomplete_width / complete_char_length) * complete_char_length
85
+ ].min
46
86
 
47
87
  complete = Array.new(complete_items, @progress.complete)
48
88
  incomplete = Array.new(incomplete_items, @progress.incomplete)
49
- complete[-1] = @progress.head if complete_bar_length > 0
50
89
 
51
- bar = ''
52
- bar += complete.join
53
- bar += incomplete.join
90
+ if complete_items > 0 && head_char_length > 0 &&
91
+ (incomplete_items > 0 || incomplete_items.zero? && !@progress.clear_head)
92
+ # see how many head chars per complete char
93
+ times = (head_char_length / complete_char_length.to_f).round
94
+ if complete_items < times # not enough complete chars to fit
95
+ incomplete.pop(times - complete_items)
96
+ end
97
+ complete.pop(times)
98
+ extra_space = " " * (times * complete_char_length - head_char_length)
99
+ complete << "#{@progress.head}#{extra_space}"
100
+ end
54
101
 
55
- value.gsub(MATCHER, bar)
102
+ value.gsub(matcher, "#{complete.join}#{incomplete.join}")
56
103
  end
57
104
  end # BarFormatter
58
105
  end # ProgressBar
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../converter'
3
+ require_relative "../converter"
4
+ require_relative "../formatter"
4
5
 
5
6
  module TTY
6
7
  class ProgressBar
@@ -8,32 +9,17 @@ module TTY
8
9
  #
9
10
  # @api private
10
11
  class ByteRateFormatter
11
- MATCHER = /:byte_rate/i
12
-
13
- def initialize(progress)
14
- @progress = progress
15
- end
16
-
17
- # Determines whether this formatter is applied or not.
18
- #
19
- # @param [Object] value
20
- #
21
- # @return [Boolean]
22
- #
23
- # @api private
24
- def matches?(value)
25
- !!(value.to_s =~ MATCHER)
26
- end
12
+ include TTY::ProgressBar::Formatter[/:byte_rate/i.freeze]
27
13
 
28
14
  # Format :byte_rate token
29
15
  #
30
16
  # @param [String] value
31
- # the value being formatted
17
+ # the value to format
32
18
  #
33
19
  # @api public
34
- def format(value)
20
+ def call(value)
35
21
  formatted = Converter.to_bytes(@progress.rate)
36
- value.gsub(MATCHER, formatted)
22
+ value.gsub(matcher, formatted)
37
23
  end
38
24
  end # ByteRateFormatter
39
25
  end # ProgressBar
@@ -6,31 +6,16 @@ module TTY
6
6
  #
7
7
  # @api private
8
8
  class CurrentFormatter
9
- MATCHER = /:current\b/i.freeze
10
-
11
- def initialize(progress)
12
- @progress = progress
13
- end
14
-
15
- # Determines whether this formatter is applied or not.
16
- #
17
- # @param [Object] value
18
- #
19
- # @return [Boolean]
20
- #
21
- # @api private
22
- def matches?(value)
23
- !!(value.to_s =~ MATCHER)
24
- end
9
+ include TTY::ProgressBar::Formatter[/:current\b/i.freeze]
25
10
 
26
11
  # Format :current token
27
12
  #
28
13
  # @param [String] value
29
- # the value being formatted
14
+ # the value to format
30
15
  #
31
16
  # @api public
32
- def format(value)
33
- value.gsub(MATCHER, @progress.current.to_s)
17
+ def call(value)
18
+ value.gsub(matcher, @progress.current.to_s)
34
19
  end
35
20
  end # CurrentFormatter
36
21
  end # ProgressBar
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../converter'
3
+ require_relative "../converter"
4
+ require_relative "../formatter"
4
5
 
5
6
  module TTY
6
7
  class ProgressBar
@@ -8,26 +9,17 @@ module TTY
8
9
  #
9
10
  # @api private
10
11
  class ByteFormatter
11
- MATCHER = /(:current_byte|:byte)\b/i.freeze
12
+ include TTY::ProgressBar::Formatter[/(:current_byte|:byte)\b/i.freeze]
12
13
 
13
- def initialize(progress)
14
- @progress = progress
15
- end
16
-
17
- # Determines whether this formatter is applied or not.
18
- #
19
- # @param [Object] value
14
+ # Format :current_byte token
20
15
  #
21
- # @return [Boolean]
16
+ # @param [String] value
17
+ # the value to format
22
18
  #
23
- # @api private
24
- def matches?(value)
25
- !!(value.to_s =~ MATCHER)
26
- end
27
-
28
- def format(value)
19
+ # @api public
20
+ def call(value)
29
21
  bytes = Converter.to_bytes(@progress.current)
30
- value.gsub(MATCHER, bytes)
22
+ value.gsub(matcher, bytes)
31
23
  end
32
24
  end # ByteFormatter
33
25
  end # ProgressBar
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../converter'
3
+ require_relative "../converter"
4
+ require_relative "../formatter"
4
5
 
5
6
  module TTY
6
7
  class ProgressBar
@@ -8,26 +9,16 @@ module TTY
8
9
  #
9
10
  # @api private
10
11
  class ElapsedFormatter
11
- MATCHER = /:elapsed/.freeze
12
+ include TTY::ProgressBar::Formatter[/:elapsed/.freeze]
12
13
 
13
- def initialize(progress)
14
- @progress = progress
15
- end
16
-
17
- # Determines whether this formatter is applied or not.
18
- #
19
- # @param [Object] value
14
+ # Format :elapsed token
20
15
  #
21
- # @return [Boolean]
16
+ # @param [String] value
17
+ # the value to format
22
18
  #
23
- # @api private
24
- def matches?(value)
25
- !!(value.to_s =~ MATCHER)
26
- end
27
-
28
- def format(value)
29
- elapsed = (Time.now - @progress.start_at)
30
- value.gsub(MATCHER, Converter.to_time(elapsed))
19
+ # @api public
20
+ def call(value)
21
+ value.gsub(matcher, Converter.to_time(@progress.elapsed_time))
31
22
  end
32
23
  end # ElapsedFormatter
33
24
  end # ProgressBar
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../converter'
3
+ require_relative "../converter"
4
+ require_relative "../formatter"
4
5
 
5
6
  module TTY
6
7
  class ProgressBar
@@ -8,29 +9,26 @@ module TTY
8
9
  #
9
10
  # @api private
10
11
  class EstimatedFormatter
11
- MATCHER = /:eta/.freeze
12
+ include TTY::ProgressBar::Formatter[/:eta/.freeze]
12
13
 
13
- def initialize(progress)
14
- @progress = progress
15
- end
16
-
17
- # Determines whether this formatter is applied or not.
14
+ # Format :eta token
18
15
  #
19
- # @param [Object] value
16
+ # @param [String] value
17
+ # the value to format
20
18
  #
21
- # @return [Boolean]
22
- #
23
- # @api private
24
- def matches?(value)
25
- !!(value.to_s =~ MATCHER)
26
- end
19
+ # @api public
20
+ def call(value)
21
+ if @progress.indeterminate? ||
22
+ (@progress.elapsed_time.zero? && @progress.ratio.zero?)
23
+ return value.gsub(matcher, "--s")
24
+ end
27
25
 
28
- def format(value)
29
- elapsed = Time.now - @progress.start_at
30
- estimated = (elapsed / @progress.ratio).to_f - elapsed
31
- estimated = (estimated.infinite? || estimated < 0) ? 0.0 : estimated
32
- value.gsub(MATCHER, Converter.to_time(estimated))
26
+ elapsed = @progress.elapsed_time
27
+ estimated = @progress.ratio.zero? ? 0.0 : (elapsed / @progress.ratio).to_f
28
+ estimated -= elapsed
29
+ estimated = 0.0 if estimated < 0
30
+ value.gsub(matcher, Converter.to_time(estimated))
33
31
  end
34
- end # ElapsedFormatter
32
+ end # EstimatedFormatter
35
33
  end # ProgressBar
36
34
  end # TTY
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TTY
4
+ class ProgressBar
5
+ # Used by {Pipeline} to format :eta_time token
6
+ #
7
+ # @api private
8
+ class EstimatedTimeFormatter
9
+ include TTY::ProgressBar::Formatter[/:eta_time/.freeze]
10
+
11
+ # Format :eta_time token
12
+ #
13
+ # @param [String] value
14
+ # the value to format
15
+ #
16
+ # @api public
17
+ def call(value)
18
+ if @progress.indeterminate? ||
19
+ (@progress.elapsed_time.zero? && @progress.ratio.zero?)
20
+ return value.gsub(matcher, "--:--:--")
21
+ end
22
+
23
+ elapsed = @progress.elapsed_time
24
+ estimated = @progress.ratio.zero? ? 0.0 : (elapsed / @progress.ratio).to_f
25
+ estimated -= elapsed
26
+ estimated = 0.0 if estimated < 0
27
+
28
+ time_format = if estimated >= 86_400 # longer than a day
29
+ "%Y-%m-%d %H:%M:%S"
30
+ else
31
+ "%H:%M:%S"
32
+ end
33
+ completion_time = Time.now + estimated
34
+ eta_time = completion_time.strftime(time_format)
35
+ value.gsub(matcher, eta_time)
36
+ end
37
+ end # EstimatedTimeFormatter
38
+ end # ProgressBar
39
+ end # TTY
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../converter'
3
+ require_relative "../converter"
4
+ require_relative "../formatter"
4
5
 
5
6
  module TTY
6
7
  class ProgressBar
@@ -8,32 +9,17 @@ module TTY
8
9
  #
9
10
  # @api private
10
11
  class MeanByteFormatter
11
- MATCHER = /:mean_byte/i.freeze
12
+ include TTY::ProgressBar::Formatter[/:mean_byte/i.freeze]
12
13
 
13
- def initialize(progress)
14
- @progress = progress
15
- end
16
-
17
- # Determines whether this formatter is applied or not.
18
- #
19
- # @param [Object] value
20
- #
21
- # @return [Boolean]
22
- #
23
- # @api private
24
- def matches?(value)
25
- !!(value.to_s =~ MATCHER)
26
- end
27
-
28
- # Format :rate token
14
+ # Format :mean_byte token
29
15
  #
30
16
  # @param [String] value
31
17
  # the value being formatted
32
18
  #
33
19
  # @api public
34
- def format(value)
20
+ def call(value)
35
21
  formatted = Converter.to_bytes(@progress.mean_rate)
36
- value.gsub(MATCHER, formatted)
22
+ value.gsub(matcher, formatted)
37
23
  end
38
24
  end # MeanByteFormatter
39
25
  end # ProgressBar
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative '../converter'
3
+ require_relative "../converter"
4
+ require_relative "../formatter"
4
5
 
5
6
  module TTY
6
7
  class ProgressBar
@@ -8,32 +9,17 @@ module TTY
8
9
  #
9
10
  # @api private
10
11
  class MeanRateFormatter
11
- MATCHER = /:mean_rate/i.freeze
12
+ include TTY::ProgressBar::Formatter[/:mean_rate/i.freeze]
12
13
 
13
- def initialize(progress)
14
- @progress = progress
15
- end
16
-
17
- # Determines whether this formatter is applied or not.
18
- #
19
- # @param [Object] value
20
- #
21
- # @return [Boolean]
22
- #
23
- # @api private
24
- def matches?(value)
25
- !!(value.to_s =~ MATCHER)
26
- end
27
-
28
- # Format :rate token
14
+ # Format :mean_rate token
29
15
  #
30
16
  # @param [String] value
31
17
  # the value being formatted
32
18
  #
33
19
  # @api public
34
- def format(value)
20
+ def call(value)
35
21
  formatted = Converter.to_seconds(@progress.mean_rate)
36
- value.gsub(MATCHER, formatted)
22
+ value.gsub(matcher, formatted)
37
23
  end
38
24
  end # MeanRateFormatter
39
25
  end # ProgressBar