tty-progressbar 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 86f9a4188616553d3453e6f8d5e35d4d3b434e7f
4
+ data.tar.gz: 57c8b9d98eca275035f392fa58d4b30b16f5c34d
5
+ SHA512:
6
+ metadata.gz: e04221654464e622d50a1dd349d65c4d557c957b8d7df1999bd6186eeb087f286221a6c0e13f0102e8af8c93fe5b7227a550e0cd790aff4c4b5d6a69d5111ea7
7
+ data.tar.gz: 4997afe3c9e855bcb433dc9209a8d41e6a9df9b560797cca911d5a066557ff5ad2fa542412a4e63c83197a9052bf26c8728275b3f59f4547897bde7088f62ee9
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake', '~> 10.3.2'
7
+ gem 'rspec', '~> 3.1.0'
8
+ gem 'yard', '~> 0.8.7'
9
+ gem 'timecop', '~> 0.7.1'
10
+ end
11
+
12
+ group :metrics do
13
+ gem 'coveralls', '~> 0.7.0'
14
+ gem 'simplecov', '~> 0.8.2'
15
+ gem 'yardstick', '~> 0.9.9'
16
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Piotr Murach
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,157 @@
1
+ # TTY::Progressbar
2
+ [![Gem Version](https://badge.fury.io/rb/tty-progressbar.png)][gem]
3
+ [![Build Status](https://secure.travis-ci.org/peter-murach/tty-progressbar.png?branch=master)][travis]
4
+ [![Code Climate](https://codeclimate.com/github/peter-murach/tty-progressbar.png)][codeclimate]
5
+
6
+ [gem]: http://badge.fury.io/rb/tty-progressbar
7
+ [travis]: http://travis-ci.org/peter-murach/tty-progressbar
8
+ [codeclimate]: https://codeclimate.com/github/peter-murach/tty-progressbar
9
+
10
+ A flexible progress bars drawing in terminal emulators.
11
+
12
+ ## Features
13
+
14
+ * Extremly flexible progress display formatting
15
+ * Ability to define your custom format tokens
16
+ * Works on all ECMA-48 compatible terminals
17
+
18
+ ## Installation
19
+
20
+ Add this line to your application's Gemfile:
21
+
22
+ ```ruby
23
+ gem 'tty-progressbar'
24
+ ```
25
+
26
+ And then execute:
27
+
28
+ $ bundle
29
+
30
+ Or install it yourself as:
31
+
32
+ $ gem install tty-progressbar
33
+
34
+ ## Contents
35
+
36
+ * [1. Usage](#1-usage)
37
+ * [1.1 advance](#11-advance)
38
+ * [1.1 finish](#12-finish)
39
+ * [2. Configuration](#2-configuration)
40
+ * [3. Formatting](#3-formatting)
41
+ * [3.1 Tokens](#31-tokens)
42
+ * [3.2 Custom Formatter](#31-custom-formatter)
43
+
44
+ ## 1. Usage
45
+
46
+ **TTY::ProgressBar** requires only format string and total number of steps to completion. Once initialized, use `advance` method to indicated the progress like so:
47
+
48
+ ```ruby
49
+ bar = TTY::ProgressBar.new("downloading [:bar]", total: 30)
50
+ 30.times do
51
+ sleep(0.1)
52
+ bar.advance(1)
53
+ end
54
+ ```
55
+
56
+ This would produce anmiation in your terminal:
57
+
58
+ ```ruby
59
+ downloading [======================= ]
60
+ ```
61
+
62
+ ### 1.1 advance
63
+
64
+ Once you have **ProgressBar** instance, you can progress the display by calling `advance` method. By default it will increase by `1` but you can pass any number of steps, for instance, when used to advance number of bytes of downloaded file.
65
+
66
+ ```ruby
67
+ bar.advance(1000)
68
+ ```
69
+
70
+ ### 1.2 finish
71
+
72
+ In order to immediately stop and finish the bar call `finish`. This will finish drawing the progress and return to new line.
73
+
74
+ ```ruby
75
+ bar.finish
76
+ ```
77
+
78
+ ## 2. Configuration
79
+
80
+ There are number of configuration options that can be provided:
81
+
82
+ * `total` total number of steps to completion
83
+ * `width` for the bars display including formatting options defaulting to total
84
+ * `complete` completion character by default `=`
85
+ * `incomplete` incomplete character by default single space
86
+ * `output` the output stream defaulting to `stderr`
87
+ * `frequency` used to throttle the output, by default `false`
88
+ * `hide_cursor` to hide display cursor defaulting to `false`
89
+
90
+ ## 3. Formatting
91
+
92
+ Every **TTY::ProgressBar** instance requires a format string, which apart from regular characters accepts special tokens to display dynamic information. For instance, a format to measure download progress could be:
93
+
94
+ ```ruby
95
+ "downloading [:bar] :elapsed :percent"
96
+ ```
97
+
98
+ ### 3.1 Tokens
99
+
100
+ These are the tokens that are currently supported:
101
+
102
+ * `:bar` the progress bar
103
+ * `:current` the current progress number
104
+ * `:total` the total progress number
105
+ * `:percent` the completion percentage
106
+ * `:elapsed` the elapsed time in seconds
107
+
108
+ ### 3.2 Custom formatter
109
+
110
+ If the provided tokens do not meet your needs, you can instrument formatting pipeline to use a custome formatter.
111
+
112
+ For example, begin by creating custom formatter called `TimeFormatter` that will dynamicly update `:time` token in format string as follows:
113
+
114
+ ```
115
+ class TimeFormatter
116
+ def initialize(progress)
117
+ @progress = progress
118
+ end
119
+
120
+ def format(value)
121
+ transformed = transform(value)
122
+ value.gsub(/:time/, transformed.to_s) # => :time token
123
+ end
124
+
125
+ private
126
+
127
+ def transfrom
128
+ value * (Time.now - @progress.start_at).to_i
129
+ end
130
+ end
131
+ ```
132
+
133
+ Notice that you have access to all the configuration options inside the formatter by simply invoking them on the `@progress` instance.
134
+
135
+ Create **TTY::ProgressBar** instance with new token:
136
+
137
+ ```ruby
138
+ bar = TTY::ProgressBar.new(":time", total: 30)
139
+ ```
140
+
141
+ Then add `TimeFormatter` to the pipeline like so:
142
+
143
+ ```ruby
144
+ bar.use TimeFormatter
145
+ ```
146
+
147
+ ## Contributing
148
+
149
+ 1. Fork it ( https://github.com/peter-murach/tty-progressbar/fork )
150
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
151
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
152
+ 4. Push to the branch (`git push origin my-new-feature`)
153
+ 5. Create a new Pull Request
154
+
155
+ ## Copyright
156
+
157
+ Copyright (c) 2014 Piotr Murach. See LICENSE for further details.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ require "bundler/gem_tasks"
4
+
5
+ FileList['tasks/**/*.rake'].each(&method(:import))
6
+
7
+ desc 'Run all specs'
8
+ task ci: %w[ spec ]
@@ -0,0 +1,7 @@
1
+ require'tty-progressbar'
2
+
3
+ bar = TTY::ProgressBar.new("downloading [:bar] :elapsed :percent", total: 30)
4
+ 30.times do
5
+ sleep(0.1)
6
+ bar.advance
7
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ module TTY
4
+ class ProgressBar
5
+ # Used by {Pipeline} to format bar
6
+ #
7
+ # @api private
8
+ class BarFormatter
9
+ def initialize(progress, *args, &block)
10
+ @progress = progress
11
+ end
12
+
13
+ # Format :bar token
14
+ #
15
+ # @param [String] value
16
+ # the value being formatted
17
+ #
18
+ # @api public
19
+ def format(value)
20
+ available_space = [0, @progress.max_columns - value.gsub(/:bar/, '').length].max
21
+ width = [@progress.width, available_space].min
22
+ complete_length = (width * @progress.ratio).round
23
+ complete = Array.new(complete_length, @progress.complete)
24
+ incomplete = Array.new(width - complete_length, @progress.incomplete)
25
+
26
+ bar = ''
27
+ bar += complete.join
28
+ bar += incomplete.join
29
+
30
+ value.gsub(/:bar/, bar)
31
+ end
32
+ end # BarFormatter
33
+ end # ProgressBar
34
+ end # TTY
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+
3
+ module TTY
4
+ class ProgressBar
5
+ # Responsible for converting values to different formats
6
+ #
7
+ # @api public
8
+ class Converter
9
+ def to_time(seconds)
10
+ hours = (seconds / 3600.to_f).floor
11
+ seconds -= hours * 3600
12
+ minutes = (seconds / 60).floor
13
+ seconds -= minutes * 60
14
+
15
+ if hours > 99
16
+ sprintf('%dh', hours)
17
+ elsif hours > 0
18
+ sprintf('%2dh%2dm', hours, minutes)
19
+ elsif minutes > 0
20
+ sprintf('%2dm%2ds', minutes, seconds)
21
+ else
22
+ sprintf('%2ds', seconds)
23
+ end
24
+ end
25
+ end # Converter
26
+ end # ProgressBar
27
+ end # TTY
@@ -0,0 +1,21 @@
1
+ # coding: utf-8
2
+
3
+ module TTY
4
+ class ProgressBar
5
+ class CurrentFormatter
6
+ def initialize(progress, *args, &block)
7
+ @progress = progress
8
+ end
9
+
10
+ # Format :current token
11
+ #
12
+ # @param [String] value
13
+ # the value being formatted
14
+ #
15
+ # @api public
16
+ def format(value)
17
+ value.gsub(/:current/, @progress.current.to_s)
18
+ end
19
+ end # CurrentFormatter
20
+ end # ProgressBar
21
+ end # TTY
@@ -0,0 +1,17 @@
1
+ # coding: utf-8
2
+
3
+ module TTY
4
+ class ProgressBar
5
+ class ElapsedFormatter
6
+ def initialize(progress, *args, &block)
7
+ @progress = progress
8
+ @converter = TTY::ProgressBar::Converter.new
9
+ end
10
+
11
+ def format(value)
12
+ elapsed = (Time.now - @progress.start_at)
13
+ value.gsub(/:elapsed/, @converter.to_time(elapsed))
14
+ end
15
+ end # ElapsedFormatter
16
+ end # ProgressBar
17
+ end # TTY
@@ -0,0 +1,16 @@
1
+ # coding: utf-8
2
+
3
+ module TTY
4
+ class ProgressBar
5
+ class PercentFormatter
6
+ def initialize(progress, *args, &block)
7
+ @progress = progress
8
+ end
9
+
10
+ def format(value)
11
+ percent = @progress.width == 0 ? 100 : (@progress.ratio * 100).to_i
12
+ value.gsub(/:percent/, percent.to_s + '%')
13
+ end
14
+ end # PercentFormatter
15
+ end # ProgressBar
16
+ end # TTY
@@ -0,0 +1,41 @@
1
+ # coding: utf-8
2
+
3
+ module TTY
4
+ class ProgressBar
5
+ # Used by {ProgressBar} to decorate format string
6
+ #
7
+ # @api private
8
+ class Pipeline
9
+ include Enumerable
10
+
11
+ def initialize(formatters = [])
12
+ @formatters = formatters
13
+ end
14
+
15
+ # Add new formatter
16
+ #
17
+ # @ api public
18
+ def use(formatter, *args, &block)
19
+ formatters << proc { |progress| formatter.new(progress, *args, &block) }
20
+ end
21
+
22
+ def decorate(progress, tokenized)
23
+ base = tokenized.dup
24
+ formatters.inject(base) do |formatted, formatter|
25
+ formatter.call(progress).format(formatted)
26
+ end
27
+ end
28
+
29
+ # Iterate over formatters
30
+ #
31
+ # @api public
32
+ def each(&block)
33
+ formatters.each(&block)
34
+ end
35
+
36
+ protected
37
+
38
+ attr_reader :formatters
39
+ end # Pipeline
40
+ end # ProgressBar
41
+ end # TTY
@@ -0,0 +1,15 @@
1
+ # coding: utf-8
2
+
3
+ module TTY
4
+ class ProgressBar
5
+ class TotalFormatter
6
+ def initialize(progress, *args, &block)
7
+ @progress = progress
8
+ end
9
+
10
+ def format(value)
11
+ value.gsub(/:total/, @progress.total.to_s)
12
+ end
13
+ end # TotalFormatter
14
+ end # ProgressBar
15
+ end # TTY
@@ -0,0 +1,7 @@
1
+ # coding: utf-8
2
+
3
+ module TTY
4
+ class ProgressBar
5
+ VERSION = "0.1.0"
6
+ end # ProgressBar
7
+ end # TTY
@@ -0,0 +1,230 @@
1
+ # coding: utf-8
2
+
3
+ require 'io/console'
4
+ require 'forwardable'
5
+
6
+ require 'tty/progressbar/converter'
7
+ require 'tty/progressbar/version'
8
+ require 'tty/progressbar/pipeline'
9
+ require 'tty/progressbar/bar_formatter'
10
+ require 'tty/progressbar/current_formatter'
11
+ require 'tty/progressbar/elapsed_formatter'
12
+ require 'tty/progressbar/percent_formatter'
13
+ require 'tty/progressbar/total_formatter'
14
+
15
+ module TTY
16
+ # Used for creating terminal progress bar
17
+ #
18
+ # @api public
19
+ class ProgressBar
20
+ extend Forwardable
21
+
22
+ ECMA_ESC = "\x1b"
23
+ ECMA_CSI = "\x1b["
24
+ ECMA_CHA = 'G'
25
+
26
+ DEC_RST = 'l'
27
+ DEC_SET = 'h'
28
+ DEC_TCEM = '?25'
29
+
30
+ attr_reader :format
31
+
32
+ attr_reader :total
33
+
34
+ attr_reader :width
35
+
36
+ attr_reader :no_width
37
+
38
+ attr_reader :current
39
+
40
+ attr_reader :start_at
41
+
42
+ attr_reader :complete
43
+
44
+ attr_reader :incomplete
45
+
46
+ attr_reader :hide_cursor
47
+
48
+ def_delegator :@pipeline, :use
49
+
50
+ # Create progress bar
51
+ #
52
+ # @param [String] format
53
+ # the tokenized string that displays the output
54
+ #
55
+ # @param [Hash] options
56
+ # @option options [Numeric] :total
57
+ # the total number of steps to completion
58
+ # @option options [Numeric] :width
59
+ # the maximum width for the bars display including
60
+ # all formatting options
61
+ # @option options [Boolean] :no_width
62
+ # true when progression is unknown defaulting to false
63
+ # @option options [Boolean] :clear
64
+ # whether or not to clear the progress line
65
+ # @option options [Boolean] :hide_cursor
66
+ # display or hide cursor
67
+ # @option options [Object] :output
68
+ # the object that responds to print call defaulting to stderr
69
+ # @option options [Number] :frequency
70
+ # the frequency with which to display bars
71
+ #
72
+ # @api public
73
+ def initialize(format, options = {})
74
+ @format = format
75
+ @total = options.fetch(:total) { fail ArgumentError }
76
+ @width = options.fetch(:width) { @total }
77
+ @no_width = options.fetch(:no_width) { false }
78
+ @clear = options.fetch(:clear) { false }
79
+ @incomplete = options.fetch(:incomplete) { ' ' }
80
+ @complete = options.fetch(:complete) { '=' }
81
+ @hide_cursor = options.fetch(:hide_cursor) { false }
82
+ @output = options.fetch(:output) { $stderr }
83
+ @frequency = options.fetch(:frequency) { 0 } # 0Hz
84
+
85
+ @width = 0 if @no_width
86
+ @render_period = @frequency == 0 ? 0 : 1.0 / @frequency
87
+ @current = 0
88
+ @readings = 0
89
+ @last_render_time = Time.now
90
+ @last_render_width = 0
91
+ @done = false
92
+ @pipeline = TTY::ProgressBar::Pipeline.new
93
+
94
+ default_pipeline
95
+ register_callbacks
96
+ end
97
+
98
+ # Advance the progress bar
99
+ #
100
+ # @param [Object|Number] progress
101
+ #
102
+ # @api public
103
+ def advance(progress = 1)
104
+ return if @done
105
+
106
+ @start_at = Time.now if @current.zero?
107
+ @readings += 1
108
+ @current += progress
109
+
110
+ if !no_width && @current >= total
111
+ finish && return
112
+ end
113
+
114
+ now = Time.now
115
+ return if (now - @last_render_time) < @render_period
116
+ render
117
+ end
118
+
119
+ # Ratio of completed over total steps
120
+ #
121
+ # @return [Float]
122
+ #
123
+ # @api public
124
+ def ratio
125
+ proportion = (@current.to_f / @total)
126
+ [[proportion, 0].max, 1].min
127
+ end
128
+
129
+ # Determine terminal width
130
+ #
131
+ # @api public
132
+ def max_columns
133
+ IO.console.winsize.last
134
+ end
135
+
136
+ # Render progress to the output
137
+ #
138
+ # @api private
139
+ def render
140
+ return if @done
141
+ now = Time.now
142
+
143
+ if @hide_cursor && @last_render_time == 0
144
+ write(ECMA_CSI + DEC_RST + DEC_TCEM)
145
+ end
146
+
147
+ # Setup formatting values
148
+ percent = width == 0 ? 100 : (ratio * 100).to_i
149
+ elapsed = (now - @start_at) * 1000.0
150
+ estimated = (percent == 100) ? 0 : elapsed * (total / @current - 1)
151
+
152
+ formatted = @pipeline.decorate(self, @format)
153
+ write(formatted, true)
154
+
155
+ @last_render_time = Time.now
156
+ @last_render_width = formatted.length
157
+ end
158
+
159
+ # Write out to the output
160
+ #
161
+ # @param [String] data
162
+ #
163
+ # @api private
164
+ def write(data, clear_first = false)
165
+ @output.print(ECMA_CSI + '1' + ECMA_CHA) if clear_first
166
+ @output.print(data)
167
+ @output.flush
168
+ end
169
+
170
+ # Resize progress bar with new configuration
171
+ #
172
+ # @api public
173
+ def resize(new_width)
174
+ fail 'Cannot resize finished progress bar' if @done
175
+
176
+ if new_width
177
+ @no_width = false
178
+ @width = new_width
179
+ else
180
+ @no_width = true
181
+ @width = 0
182
+ end
183
+
184
+ advance(0) # rerender with new configuration
185
+ end
186
+
187
+ # End the progress
188
+ #
189
+ # @api public
190
+ def finish
191
+ # reenable cursor if it is turned off
192
+ write(ECMA_CSI + DEC_RST + DEC_TCEM, false) if @hide_cursor
193
+ return if @done
194
+ @current = @width if @no_width
195
+ render
196
+ write("\n", false)
197
+ @done = true
198
+ end
199
+
200
+ # Terminates the progress bar
201
+ #
202
+ # @api public
203
+ def terminate
204
+ @done = true
205
+ end
206
+
207
+ private
208
+
209
+ # Prepare default pipeline formatters
210
+ #
211
+ # @api private
212
+ def default_pipeline
213
+ @pipeline.use TTY::ProgressBar::CurrentFormatter
214
+ @pipeline.use TTY::ProgressBar::TotalFormatter
215
+ @pipeline.use TTY::ProgressBar::ElapsedFormatter
216
+ @pipeline.use TTY::ProgressBar::PercentFormatter
217
+ @pipeline.use TTY::ProgressBar::BarFormatter
218
+ end
219
+
220
+ # Handle resize and kill signals
221
+ #
222
+ # @api private
223
+ def register_callbacks
224
+ callback = proc { send(:resize, max_columns) }
225
+ Signal.trap('SIGWINCH', &callback)
226
+
227
+ Signal.trap('KILL') { @terminate }
228
+ end
229
+ end # ProgressBar
230
+ end # TTY
@@ -0,0 +1 @@
1
+ require 'tty/progressbar'
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ require 'timecop'
4
+ require 'tty-progressbar'
5
+
6
+ RSpec.configure do |config|
7
+ config.expect_with :rspec do |expectations|
8
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
9
+ end
10
+
11
+ config.mock_with :rspec do |mocks|
12
+ mocks.verify_partial_doubles = true
13
+ end
14
+
15
+ # Limits the available syntax to the non-monkey patched syntax that is recommended.
16
+ config.disable_monkey_patching!
17
+
18
+ # This setting enables warnings. It's recommended, but in some cases may
19
+ # be too noisy due to issues in dependencies.
20
+ config.warnings = true
21
+
22
+ if config.files_to_run.one?
23
+ config.default_formatter = 'doc'
24
+ end
25
+
26
+ config.profile_examples = 2
27
+
28
+ config.order = :random
29
+
30
+ Kernel.srand config.seed
31
+ end
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::ProgressBar, 'bar' do
6
+ let(:output) { StringIO.new('', 'w+') }
7
+
8
+ it "animates bar" do
9
+ progress = TTY::ProgressBar.new("[:bar]", output: output, total: 5)
10
+ 5.times { progress.advance }
11
+ output.rewind
12
+ expect(output.read).to eq([
13
+ "\e[1G[= ]",
14
+ "\e[1G[== ]",
15
+ "\e[1G[=== ]",
16
+ "\e[1G[==== ]",
17
+ "\e[1G[=====]\n"
18
+ ].join)
19
+ end
20
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::ProgressBar::Converter, '.to_time' do
6
+ subject(:converter) { described_class.new }
7
+
8
+ it "converts seconds to seconds" do
9
+ expect(converter.to_time(15)).to eq("15s")
10
+ end
11
+
12
+ it "converts seconds to minutes" do
13
+ expect(converter.to_time(100)).to eq(" 1m40s")
14
+ end
15
+
16
+ it "converts seconds to small hours" do
17
+ expect(converter.to_time(3600)).to eq(" 1h 0m")
18
+ end
19
+
20
+ it "converts secodns to hours" do
21
+ expect(converter.to_time(100 * 3600)).to eq("100h")
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::ProgressBar, 'current' do
6
+ let(:output) { StringIO.new('', 'w+') }
7
+
8
+ it "displays current value" do
9
+ progress = TTY::ProgressBar.new("|:current|", output: output, total: 10)
10
+ 3.times { progress.advance }
11
+ output.rewind
12
+ expect(output.read).to eq([
13
+ "\e[1G|1|",
14
+ "\e[1G|2|",
15
+ "\e[1G|3|"
16
+ ].join)
17
+ end
18
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::ProgressBar, 'custom' do
6
+ let(:output) { StringIO.new('', 'w+') }
7
+
8
+ it "allows for custom tag" do
9
+ progress = TTY::ProgressBar.new(":hi", output: output, total: 10)
10
+
11
+ HiFormatter = Class.new do
12
+ def initialize(progress)
13
+ @progress = progress
14
+ end
15
+
16
+ def format(value)
17
+ value.gsub(/:hi/, "Hello")
18
+ end
19
+ end
20
+
21
+ progress.use(HiFormatter)
22
+ progress.advance
23
+ output.rewind
24
+ expect(output.read).to eq("\e[1GHello")
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::ProgressBar, '.new' do
6
+ let(:output) { StringIO.new('', 'w+') }
7
+
8
+ before { Timecop.safe_mode = false }
9
+
10
+ it "displays elapsed time" do
11
+ time_now = Time.local(2014, 10, 5, 12, 0, 0)
12
+ Timecop.freeze(time_now)
13
+ progress = TTY::ProgressBar.new(":elapsed", output: output, total: 10)
14
+
15
+ 5.times do |sec|
16
+ time_now = Time.local(2014, 10, 5, 12, 0, sec)
17
+ Timecop.freeze(time_now)
18
+ progress.advance
19
+ end
20
+
21
+ output.rewind
22
+ expect(output.read).to eq([
23
+ "\e[1G 0s",
24
+ "\e[1G 1s",
25
+ "\e[1G 2s",
26
+ "\e[1G 3s",
27
+ "\e[1G 4s"
28
+ ].join)
29
+ Timecop.return
30
+ end
31
+ end
@@ -0,0 +1,52 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::ProgressBar, '.new' do
6
+ let(:output) { StringIO.new('', 'w+') }
7
+
8
+ it "displays output where width == total" do
9
+ progress = TTY::ProgressBar.new("[:bar]", output: output, total: 10)
10
+ progress.advance
11
+ output.rewind
12
+ expect(output.read).to eq("\e[1G[= ]")
13
+ end
14
+
15
+ it "displays output where width > total" do
16
+ progress = TTY::ProgressBar.new("[:bar]", output: output, total: 5, width: 10)
17
+ 5.times { progress.advance }
18
+ output.rewind
19
+ expect(output.read).to eq([
20
+ "\e[1G[== ]",
21
+ "\e[1G[==== ]",
22
+ "\e[1G[====== ]",
23
+ "\e[1G[======== ]",
24
+ "\e[1G[==========]\n"
25
+ ].join)
26
+ end
27
+
28
+ it "displays output where width < total" do
29
+ progress = TTY::ProgressBar.new("[:bar]", output: output, total: 10, width: 5)
30
+ 10.times { progress.advance }
31
+ output.rewind
32
+ expect(output.read).to eq([
33
+ "\e[1G[= ]",
34
+ "\e[1G[= ]",
35
+ "\e[1G[== ]",
36
+ "\e[1G[== ]",
37
+ "\e[1G[=== ]",
38
+ "\e[1G[=== ]",
39
+ "\e[1G[==== ]",
40
+ "\e[1G[==== ]",
41
+ "\e[1G[=====]",
42
+ "\e[1G[=====]\n"
43
+ ].join)
44
+ end
45
+
46
+ it "displays total value" do
47
+ progress = TTY::ProgressBar.new("|:total|", output: output, total: 10)
48
+ progress.advance(3)
49
+ output.rewind
50
+ expect(output.read).to eq("\e[1G|10|")
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::ProgressBar, 'percent' do
6
+ let(:output) { StringIO.new('', 'w+') }
7
+
8
+ it "displays percent finished" do
9
+ progress = TTY::ProgressBar.new(":percent", output: output, total: 5)
10
+ 5.times { progress.advance }
11
+ output.rewind
12
+ expect(output.read).to eq([
13
+ "\e[1G20%",
14
+ "\e[1G40%",
15
+ "\e[1G60%",
16
+ "\e[1G80%",
17
+ "\e[1G100%\n"
18
+ ].join)
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ RSpec.describe TTY::ProgressBar::Pipeline, '.decorate' do
6
+ subject(:pipeline) { described_class.new }
7
+
8
+ it "decorates tokenized string with pipeline formatters" do
9
+ pipeline.use TTY::ProgressBar::CurrentFormatter
10
+ pipeline.use TTY::ProgressBar::TotalFormatter
11
+ progress_bar = double(current: '3', total: '10')
12
+ tokenized = "[:current/:total]"
13
+ expect(pipeline.decorate(progress_bar, tokenized)).to eq("[3/10]")
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ desc 'Load gem inside irb console'
4
+ task :console do
5
+ require 'irb'
6
+ require 'irb/completion'
7
+ require File.join(__FILE__, '../../lib/tty-progresbar')
8
+ ARGV.clear
9
+ IRB.start
10
+ end
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ desc 'Measure code coverage'
4
+ task :coverage do
5
+ begin
6
+ original, ENV['COVERAGE'] = ENV['COVERAGE'], 'true'
7
+ Rake::Task['spec'].invoke
8
+ ensure
9
+ ENV['COVERAGE'] = original
10
+ end
11
+ end
data/tasks/spec.rake ADDED
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+
6
+ desc 'Run all specs'
7
+ RSpec::Core::RakeTask.new(:spec) do |task|
8
+ task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
9
+ end
10
+
11
+ namespace :spec do
12
+ desc 'Run unit specs'
13
+ RSpec::Core::RakeTask.new(:unit) do |task|
14
+ task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
15
+ end
16
+
17
+ desc 'Run integration specs'
18
+ RSpec::Core::RakeTask.new(:integration) do |task|
19
+ task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
20
+ end
21
+ end
22
+
23
+ rescue LoadError
24
+ %w[spec spec:unit spec:integration].each do |name|
25
+ task name do
26
+ $stderr.puts "In order to run #{name}, do `gem install rspec`"
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'tty/progressbar/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "tty-progressbar"
8
+ spec.version = TTY::ProgressBar::VERSION
9
+ spec.authors = ["Piotr Murach"]
10
+ spec.email = [""]
11
+ spec.summary = %q{A flexible progress bars drawing in terminal emulators.}
12
+ spec.description = %q{A flexible progress bars drawing in terminal emulators.}
13
+ spec.homepage = "https://github.com/peter-murach/tty-progressbar"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tty-progressbar
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Piotr Murach
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: A flexible progress bars drawing in terminal emulators.
42
+ email:
43
+ - ''
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .gitignore
49
+ - .rspec
50
+ - .ruby-version
51
+ - Gemfile
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - examples/simple.rb
56
+ - lib/tty-progressbar.rb
57
+ - lib/tty/progressbar.rb
58
+ - lib/tty/progressbar/bar_formatter.rb
59
+ - lib/tty/progressbar/converter.rb
60
+ - lib/tty/progressbar/current_formatter.rb
61
+ - lib/tty/progressbar/elapsed_formatter.rb
62
+ - lib/tty/progressbar/percent_formatter.rb
63
+ - lib/tty/progressbar/pipeline.rb
64
+ - lib/tty/progressbar/total_formatter.rb
65
+ - lib/tty/progressbar/version.rb
66
+ - spec/spec_helper.rb
67
+ - spec/unit/bar_formatter_spec.rb
68
+ - spec/unit/converter_spec.rb
69
+ - spec/unit/current_formatter_spec.rb
70
+ - spec/unit/custom_formatter_spec.rb
71
+ - spec/unit/elapsed_formatter_spec.rb
72
+ - spec/unit/new_spec.rb
73
+ - spec/unit/percent_formatter_spec.rb
74
+ - spec/unit/pipeline_spec.rb
75
+ - tasks/console.rake
76
+ - tasks/coverage.rake
77
+ - tasks/spec.rake
78
+ - tty-progressbar.gemspec
79
+ homepage: https://github.com/peter-murach/tty-progressbar
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ post_install_message:
84
+ rdoc_options: []
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ requirements: []
98
+ rubyforge_project:
99
+ rubygems_version: 2.0.3
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: A flexible progress bars drawing in terminal emulators.
103
+ test_files:
104
+ - spec/spec_helper.rb
105
+ - spec/unit/bar_formatter_spec.rb
106
+ - spec/unit/converter_spec.rb
107
+ - spec/unit/current_formatter_spec.rb
108
+ - spec/unit/custom_formatter_spec.rb
109
+ - spec/unit/elapsed_formatter_spec.rb
110
+ - spec/unit/new_spec.rb
111
+ - spec/unit/percent_formatter_spec.rb
112
+ - spec/unit/pipeline_spec.rb
113
+ has_rdoc: