tty-progressbar 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +32 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +492 -126
  5. data/lib/tty-progressbar.rb +2 -2
  6. data/lib/tty/progressbar.rb +168 -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 +14 -18
  17. data/lib/tty/progressbar/formatter/estimated_time.rb +37 -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 +1 -1
  30. metadata +44 -103
  31. data/Rakefile +0 -8
  32. data/examples/color.rb +0 -18
  33. data/examples/failure.rb +0 -12
  34. data/examples/iterator.rb +0 -5
  35. data/examples/lazy.rb +0 -6
  36. data/examples/multi/main_bar.rb +0 -13
  37. data/examples/multi/simple.rb +0 -13
  38. data/examples/multi/width.rb +0 -13
  39. data/examples/simple.rb +0 -7
  40. data/examples/slow_process.rb +0 -29
  41. data/examples/speed.rb +0 -11
  42. data/examples/threaded.rb +0 -14
  43. data/examples/tokens.rb +0 -12
  44. data/examples/unicode.rb +0 -7
  45. data/spec/spec_helper.rb +0 -53
  46. data/spec/unit/advance_spec.rb +0 -25
  47. data/spec/unit/clear_spec.rb +0 -17
  48. data/spec/unit/complete_spec.rb +0 -16
  49. data/spec/unit/converter/to_bytes_spec.rb +0 -47
  50. data/spec/unit/converter/to_seconds_spec.rb +0 -15
  51. data/spec/unit/converter/to_time_spec.rb +0 -19
  52. data/spec/unit/custom_formatter_spec.rb +0 -26
  53. data/spec/unit/custom_token_spec.rb +0 -14
  54. data/spec/unit/events_spec.rb +0 -33
  55. data/spec/unit/finish_spec.rb +0 -15
  56. data/spec/unit/formatter/bar_spec.rb +0 -33
  57. data/spec/unit/formatter/byte_rate_spec.rb +0 -32
  58. data/spec/unit/formatter/current_byte_spec.rb +0 -16
  59. data/spec/unit/formatter/current_spec.rb +0 -14
  60. data/spec/unit/formatter/elapsed_spec.rb +0 -58
  61. data/spec/unit/formatter/estimated_spec.rb +0 -27
  62. data/spec/unit/formatter/mean_byte_spec.rb +0 -32
  63. data/spec/unit/formatter/mean_rate_spec.rb +0 -31
  64. data/spec/unit/formatter/percent_spec.rb +0 -16
  65. data/spec/unit/formatter/rate_spec.rb +0 -31
  66. data/spec/unit/formatter/total_byte_spec.rb +0 -16
  67. data/spec/unit/formatter/total_spec.rb +0 -16
  68. data/spec/unit/frequency_spec.rb +0 -27
  69. data/spec/unit/head_spec.rb +0 -32
  70. data/spec/unit/hide_cursor_spec.rb +0 -27
  71. data/spec/unit/inspect_spec.rb +0 -11
  72. data/spec/unit/iterate_spec.rb +0 -79
  73. data/spec/unit/log_spec.rb +0 -29
  74. data/spec/unit/meter_spec.rb +0 -70
  75. data/spec/unit/multi/advance_spec.rb +0 -123
  76. data/spec/unit/multi/events_spec.rb +0 -115
  77. data/spec/unit/multi/finish_spec.rb +0 -41
  78. data/spec/unit/multi/line_inset_spec.rb +0 -65
  79. data/spec/unit/multi/register_spec.rb +0 -35
  80. data/spec/unit/multi/reset_spec.rb +0 -28
  81. data/spec/unit/multi/stop_spec.rb +0 -15
  82. data/spec/unit/multi/width_spec.rb +0 -118
  83. data/spec/unit/new_spec.rb +0 -76
  84. data/spec/unit/pipeline_spec.rb +0 -19
  85. data/spec/unit/ratio_spec.rb +0 -31
  86. data/spec/unit/render_spec.rb +0 -25
  87. data/spec/unit/reset_spec.rb +0 -31
  88. data/spec/unit/resize_spec.rb +0 -35
  89. data/spec/unit/set_current_spec.rb +0 -43
  90. data/spec/unit/start_spec.rb +0 -14
  91. data/spec/unit/stop_spec.rb +0 -19
  92. data/spec/unit/update_spec.rb +0 -22
  93. data/spec/unit/width_spec.rb +0 -86
  94. data/tasks/console.rake +0 -9
  95. data/tasks/coverage.rake +0 -9
  96. data/tasks/spec.rake +0 -27
  97. data/tty-progressbar.gemspec +0 -32
@@ -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,24 @@ 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
+ return value.gsub(matcher, "--s")
23
+ end
27
24
 
28
- def format(value)
29
- elapsed = Time.now - @progress.start_at
25
+ elapsed = @progress.elapsed_time
30
26
  estimated = (elapsed / @progress.ratio).to_f - elapsed
31
27
  estimated = (estimated.infinite? || estimated < 0) ? 0.0 : estimated
32
- value.gsub(MATCHER, Converter.to_time(estimated))
28
+ value.gsub(matcher, Converter.to_time(estimated))
33
29
  end
34
- end # ElapsedFormatter
30
+ end # EstimatedFormatter
35
31
  end # ProgressBar
36
32
  end # TTY
@@ -0,0 +1,37 @@
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
+ return value.gsub(matcher, "--:--:--")
20
+ end
21
+
22
+ elapsed = @progress.elapsed_time
23
+ estimated = (elapsed / @progress.ratio).to_f - elapsed
24
+ estimated = (estimated.infinite? || estimated < 0) ? 0.0 : estimated
25
+
26
+ time_format = if estimated >= 86_400 # longer than a day
27
+ "%Y-%m-%d %H:%M:%S"
28
+ else
29
+ "%H:%M:%S"
30
+ end
31
+ completion_time = Time.now + estimated
32
+ eta_time = completion_time.strftime(time_format)
33
+ value.gsub(matcher, eta_time)
34
+ end
35
+ end # EstimatedTimeFormatter
36
+ end # ProgressBar
37
+ 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