tqdm 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardopts +1 -1
- data/README.md +28 -15
- data/Rakefile +1 -1
- data/lib/core_ext/enumerable.rb +15 -14
- data/lib/tqdm.rb +9 -148
- data/lib/tqdm/decorator.rb +138 -0
- data/lib/tqdm/printer.rb +70 -0
- data/lib/tqdm/printer/default_format.rb +74 -0
- data/lib/tqdm/sequel.rb +16 -13
- data/lib/tqdm/version.rb +1 -1
- data/tqdm.gemspec +1 -1
- metadata +5 -3
- data/lib/tqdm/utils.rb +0 -50
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3dc522c1cd180b959a8c36c2a3f1fb41ffdd51a8
|
4
|
+
data.tar.gz: e17546f682e0adfe9b6970bc02477590b1d355cd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a5aecb337cfec0e565deabd81741aff57c48c1b1b13b562c08c9173ae6b9e520aeb18561734a317ee9ee2943dc0df3869c71495c17ff584580d7787857011b2
|
7
|
+
data.tar.gz: 71e5e62669db44fe2d3b7aa42696c22bf5c34f87f374b48505ea9899536c9a614ae9ce92b874799e3e5df46525f2fc9ea251dea2a5f86c238db7f34468aa291b
|
data/.yardopts
CHANGED
data/README.md
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# tqdm-ruby
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/tqdm.svg)](https://badge.fury.io/rb/tqdm)
|
2
3
|
|
3
|
-
tqdm-ruby
|
4
|
+
tqdm-ruby allows you to add a progress indicator to your loops with minimal effort.
|
4
5
|
|
5
|
-
It is a port of the excellent [
|
6
|
+
It is a port of the excellent [tqdm library][tqdm] for python. tqdm (read taqadum, تقدّم) means "progress" in Arabic.
|
6
7
|
|
7
|
-
|
8
|
+
Calling `#tqdm` (or its readable but longer alias `#with_progress`) on any `Enumerable` returns an enhanced clone that animates a meter on `$stderr` during iteration.
|
8
9
|
|
9
10
|
```ruby
|
10
11
|
require 'tqdm'
|
@@ -15,11 +16,14 @@ The default output looks like this:
|
|
15
16
|
|
16
17
|
![|####------| 492/1000 49% [elapsed: 00:05 left: 00:05, 88.81 iters/sec]](http://i.imgur.com/6y0t7XS.gif)
|
17
18
|
|
18
|
-
It works equally well from within irb, [pry](http://pryrepl.org/), and [
|
19
|
+
It works equally well from within irb, [pry](http://pryrepl.org/), and [iRuby notebooks](https://github.com/SciRuby/iruby) as seen here:
|
19
20
|
|
20
|
-
|
21
|
+
![iRuby notebook screencap](http://i.imgur.com/DilrHuX.gif)
|
22
|
+
|
23
|
+
*Why not progressbar, ruby-progressbar, powerbar, or any of the [other gems][]?* These typically have a bucketload of formatting options and you have to manually send updates to the progressbar object to use them. tqdm pleasantly encourages the laziest usage scenario, in that you "set it and forget it".
|
21
24
|
|
22
25
|
[tqdm]: https://github.com/tqdm/tqdm
|
26
|
+
[other gems]: https://www.ruby-toolbox.com/categories/CLI_Progress_Bars
|
23
27
|
|
24
28
|
## Install
|
25
29
|
|
@@ -37,22 +41,23 @@ And then execute:
|
|
37
41
|
|
38
42
|
## Usage
|
39
43
|
|
40
|
-
All `Enumerable` objects gain access to the `#
|
41
|
-
|
42
|
-
Options can be provided for `#tqdm`:
|
44
|
+
All `Enumerable` objects gain access to the `#with_progress` method (aliased as `#tqdm`), which returns an enhanced object wherein any iteration (by calling `#each` or any of its relatives: `#each_with_index`, `#map`, `#select`, etc.) produces an animated progress bar on `$stderr`.
|
43
45
|
|
44
46
|
```ruby
|
45
47
|
require 'tqdm'
|
46
|
-
|
48
|
+
num = 1629241972611353
|
49
|
+
(2..Math.sqrt(num)).with_progress.reject { |x| num % x > 0 }.map { |x| [x, num/x] }
|
50
|
+
# ... Animates a progress bar while calculating...
|
51
|
+
# => [[32599913, 49976881]]
|
47
52
|
```
|
48
53
|
|
49
|
-
The following options are available:
|
54
|
+
Options can be provided as a hash, e.g., `.with_progress(desc: "copying", leave: true)`. The following options are available:
|
50
55
|
|
51
56
|
- `desc`: Short string, describing the progress, added to the beginning of the line
|
52
|
-
- `total`: Expected number of iterations, if not given, `self.size` is used
|
57
|
+
- `total`: Expected number of iterations, if not given, `self.size || self.count` is used
|
53
58
|
- `file`: A file-like object to output the progress message to, by default, `$stderr`
|
54
|
-
- `leave`: A boolean (default false). Should the progress bar should stay on screen after it's done?
|
55
|
-
- `min_interval`: Default is `0.5`. If less than `min_interval` seconds or `min_iters` iterations have passed since the last progress meter update, it is not re-printed (
|
59
|
+
- `leave`: A boolean (default `false`). Should the progress bar should stay on screen after it's done?
|
60
|
+
- `min_interval`: Default is `0.5`. If less than `min_interval` seconds or `min_iters` iterations have passed since the last progress meter update, it is not re-printed (decreasing IO thrashing).
|
56
61
|
- `min_iters`: Default is `1`. See previous.
|
57
62
|
|
58
63
|
[Sequel](http://sequel.jeremyevans.net/) is an amazing database library for Ruby. tqdm can enhance its [`Dataset`](http://sequel.jeremyevans.net/rdoc/classes/Sequel/Dataset.html) objects to show progress while iterating (same options as above):
|
@@ -68,12 +73,20 @@ DB.create_table :items do
|
|
68
73
|
end
|
69
74
|
|
70
75
|
# Show progress during big inserts (this isn't new)
|
71
|
-
(0..100000).
|
76
|
+
(0..100000).with_progress.each { DB[:items].insert(price: rand * 100) }
|
72
77
|
|
73
78
|
# Show progress during long SELECT queries
|
74
|
-
DB[:items].where{ price > 10 }.
|
79
|
+
DB[:items].where{ price > 10 }.with_progress.each { |row| "do some processing here" }
|
75
80
|
```
|
76
81
|
|
82
|
+
## TODO
|
83
|
+
|
84
|
+
1. Performance improvements
|
85
|
+
2. Test/benchmark suite
|
86
|
+
3. Add smoothing for speed estimates
|
87
|
+
4. Support unicode output (smooth blocks)
|
88
|
+
5. By default, resize to the apparent width of the output terminal
|
89
|
+
|
77
90
|
## Contributing
|
78
91
|
|
79
92
|
1. Fork it
|
data/Rakefile
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler/gem_tasks'
|
data/lib/core_ext/enumerable.rb
CHANGED
@@ -1,25 +1,26 @@
|
|
1
|
-
require
|
1
|
+
require 'tqdm'
|
2
2
|
|
3
3
|
# We enhance all enumerable objects (e.g. `Array`, `Hash`, `Range`, ...) by extending the `Enumerable` module.
|
4
4
|
# This mixin is only supposed to be present on objects that provide an `#each` method.
|
5
5
|
#
|
6
6
|
# @see http://ruby-doc.org/core-2.2.3/Enumerable.html
|
7
7
|
module Enumerable
|
8
|
-
|
9
|
-
# Returns a clone of `self` where all calls to `#each` and related methods will print an animated progress bar
|
8
|
+
|
9
|
+
# Returns a *clone* of `self` where all calls to `#each` and related methods will print an animated progress bar
|
10
10
|
# while iterating.
|
11
11
|
#
|
12
|
-
# @param
|
13
|
-
# @option
|
14
|
-
# @option
|
15
|
-
# @option
|
16
|
-
# @option
|
17
|
-
# @option
|
18
|
-
# @option
|
12
|
+
# @param options [Hash] more options used to control behavior of the progress bar
|
13
|
+
# @option options [String] :desc a short description added to the beginning of the progress bar
|
14
|
+
# @option options [Integer] :total (self.size) the expected number of iterations
|
15
|
+
# @option options [File, IO] :file ($stderr) a file-like object to output the progress bar to
|
16
|
+
# @option options [Boolean] :leave (false) should the progress bar should stay on screen after it's done?
|
17
|
+
# @option options [Integer] :min_iters see `:min_interval`
|
18
|
+
# @option options [Float] :min_interval If less than min_interval seconds or min_iters iterations have passed since
|
19
19
|
# the last progress meter update, it is not updated again.
|
20
20
|
# @return [Enumerable] `self` with the `#each` method wrapped as described above
|
21
|
-
def
|
22
|
-
Tqdm::
|
21
|
+
def with_progress(options = {})
|
22
|
+
Tqdm::Decorator.new(self, options).enhance
|
23
23
|
end
|
24
|
-
|
25
|
-
|
24
|
+
alias :tqdm :with_progress
|
25
|
+
|
26
|
+
end
|
data/lib/tqdm.rb
CHANGED
@@ -1,163 +1,24 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require 'tqdm/version'
|
2
|
+
require 'tqdm/decorator'
|
3
|
+
require 'core_ext/enumerable'
|
4
4
|
|
5
5
|
# Add a progress bar to your loops in a second.
|
6
|
-
# A port of Python's [tqdm library](https://github.com/tqdm/tqdm), although we're currently
|
6
|
+
# A port of Python's [tqdm library](https://github.com/tqdm/tqdm), although we're currently
|
7
7
|
# closer to the feature set of [@noamraph's original release](https://github.com/noamraph/tqdm).
|
8
8
|
#
|
9
|
-
# Specifically, `Tqdm` enhances `Enumerable` by printing a progress indicator whenever
|
9
|
+
# Specifically, `Tqdm` enhances `Enumerable` by printing a progress indicator whenever
|
10
10
|
# iterating with `#each` or its close relatives.
|
11
11
|
#
|
12
12
|
# @author Theodore Pak
|
13
13
|
# @see https://github.com/tqdm/tqdm
|
14
14
|
module Tqdm
|
15
|
-
|
16
|
-
# The default width of the progress bar, in characters.
|
17
|
-
N_BARS = 10
|
18
|
-
|
15
|
+
|
19
16
|
class << self
|
20
|
-
# Upgrades `Sequel::Datasets` with the #
|
21
|
-
# @see Enumerable#
|
17
|
+
# Upgrades `Sequel::Datasets` with the #with_progress method.
|
18
|
+
# @see Enumerable#with_progress
|
22
19
|
def enhance_sequel!
|
23
|
-
require
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
# Prints a status line, handling the deletion of previously printed lines with carriage
|
28
|
-
# returns as necessary. Instantiated by a `TqdmDecorator`.
|
29
|
-
#
|
30
|
-
# @private
|
31
|
-
class StatusPrinter
|
32
|
-
# Initialize a new StatusPrinter.
|
33
|
-
#
|
34
|
-
# @param file [File, IO] the status will be printed to this via `#write` and `#flush`
|
35
|
-
def initialize(file)
|
36
|
-
@file = file
|
37
|
-
@last_printed_len = 0
|
38
|
-
end
|
39
|
-
|
40
|
-
# Prints a line of text to @file, after deleting the previously printed line
|
41
|
-
#
|
42
|
-
# @param line [String] a line of text to be printed
|
43
|
-
# @return [Integer] the number of bytes written
|
44
|
-
def print_status(line)
|
45
|
-
@file.write("\r" + line + ' ' * [@last_printed_len - line.size, 0].max)
|
46
|
-
@file.flush
|
47
|
-
@last_printed_len = line.size
|
20
|
+
require 'tqdm/sequel'
|
48
21
|
end
|
49
22
|
end
|
50
|
-
|
51
|
-
|
52
|
-
# Decorates the #each method of an `Enumerable` by wrapping it so that each
|
53
|
-
# iteration produces a pretty progress bar printed to the console or a file handle.
|
54
|
-
#
|
55
|
-
# @note The `Enumerable` is cloned before it is enhanced; it is not modified directly.
|
56
|
-
#
|
57
|
-
# @example Enhances `arr` so that an animated progress bar prints while iterating.
|
58
|
-
# arr = (0...1000)
|
59
|
-
# arr_tqdm = TqdmDecorator.new(arr).enhance
|
60
|
-
# arr_tqdm.each { |x| sleep 0.01 }
|
61
|
-
class TqdmDecorator
|
62
|
-
|
63
|
-
include Utils
|
64
23
|
|
65
|
-
# Initialize a new TqdmDecorator. Typically you wouldn't use this object, but
|
66
|
-
# would immediately call `#enhance` to retrieve the enhanced `Enumerable`.
|
67
|
-
#
|
68
|
-
# @param enumerable [Enumerable] the Enumerable object to be enhanced
|
69
|
-
# @param opts [Hash] more options used to control behavior of the progress bar
|
70
|
-
# @option opts [String] :desc a short description added to the beginning of the progress bar
|
71
|
-
# @option opts [Integer] :total (self.size) the expected number of iterations
|
72
|
-
# @option opts [File, IO] :file ($stderr) a file-like object to output the progress bar to
|
73
|
-
# @option opts [Boolean] :leave (false) should the progress bar should stay on screen after it's done?
|
74
|
-
# @option opts [Integer] :min_iters see `:min_interval`
|
75
|
-
# @option opts [Float] :min_interval If less than min_interval seconds or min_iters iterations have passed since
|
76
|
-
# the last progress meter update, it is not updated again.
|
77
|
-
#
|
78
|
-
# @example
|
79
|
-
# a = (1...1000)
|
80
|
-
# TqdmDecorator.new(a).enhance.each { |x| sleep 0.01 }
|
81
|
-
#
|
82
|
-
# @example
|
83
|
-
# a = [1, 2, 3, 4]
|
84
|
-
# TqdmDecorator.new(a, file: $stdout, leave: true)
|
85
|
-
def initialize(enumerable, opts={})
|
86
|
-
@enumerable = enumerable
|
87
|
-
@total = opts[:total] || @enumerable.size rescue @enumerable.count rescue nil
|
88
|
-
@prefix = opts[:desc] ? opts[:desc] + ': ' : ''
|
89
|
-
@file = opts[:file] || $stderr
|
90
|
-
@sp = StatusPrinter.new(@file)
|
91
|
-
@min_iters = opts[:min_iters] || 1
|
92
|
-
@min_interval = opts[:min_interval] || 0.5
|
93
|
-
@leave = opts[:leave] || false
|
94
|
-
end
|
95
|
-
|
96
|
-
# Starts the textual progress bar.
|
97
|
-
def start!
|
98
|
-
@start_t = @last_print_t = Time.now
|
99
|
-
@last_print_n = 0
|
100
|
-
@n = 0
|
101
|
-
|
102
|
-
@sp.print_status(@prefix + format_meter(0, @total, 0))
|
103
|
-
end
|
104
|
-
|
105
|
-
# Called everytime the textual progress bar might need to be updated (i.e. on
|
106
|
-
# every iteration). We still check whether the update is appropriate to print to
|
107
|
-
# the progress bar before doing so, according to the `:min_iters` and `:min_interval`
|
108
|
-
# options.
|
109
|
-
#
|
110
|
-
# @see #initialize
|
111
|
-
def increment!
|
112
|
-
@n += 1
|
113
|
-
|
114
|
-
if @n - @last_print_n >= @min_iters
|
115
|
-
# We check the counter first, to reduce the overhead of Time.now
|
116
|
-
cur_t = Time.now
|
117
|
-
if cur_t - @last_print_t >= @min_interval
|
118
|
-
@sp.print_status(@prefix + format_meter(@n, @total, cur_t - @start_t))
|
119
|
-
@last_print_n = @n
|
120
|
-
@last_print_t = cur_t
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
# Prints the final state of the textual progress bar. Based on the `:leave` option, this
|
126
|
-
# may include deleting it entirely.
|
127
|
-
def finish!
|
128
|
-
if !@leave
|
129
|
-
@sp.print_status('')
|
130
|
-
@file.write("\r")
|
131
|
-
else
|
132
|
-
if @last_print_n < @n
|
133
|
-
@sp.print_status(@prefix + format_meter(@n, @total, Time.now - @start_t))
|
134
|
-
end
|
135
|
-
@file.write("\n")
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
# Enhances the wrapped `Enumerable`.
|
140
|
-
#
|
141
|
-
# @note The `Enumerable` is cloned (shallow copied) before it is enhanced; it is not modified directly.
|
142
|
-
#
|
143
|
-
# @return [Enumerable] a clone of Enumerable enhanced so that every call to `#each` animates the
|
144
|
-
# progress bar.
|
145
|
-
def enhance
|
146
|
-
tqdm = self
|
147
|
-
|
148
|
-
enhanced = @enumerable.clone
|
149
|
-
enhanced.define_singleton_method(:each) do |*args, &block|
|
150
|
-
tqdm.start!
|
151
|
-
super(*args) do |item|
|
152
|
-
block.call item
|
153
|
-
tqdm.increment!
|
154
|
-
end
|
155
|
-
tqdm.finish!
|
156
|
-
end
|
157
|
-
|
158
|
-
enhanced
|
159
|
-
end
|
160
|
-
|
161
|
-
end
|
162
|
-
|
163
24
|
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'tqdm/printer'
|
2
|
+
|
3
|
+
module Tqdm
|
4
|
+
|
5
|
+
# Decorates the #each method of an `Enumerable` by wrapping it so that each
|
6
|
+
# iteration produces a pretty progress bar printed to the console or a file handle.
|
7
|
+
#
|
8
|
+
# @note The `Enumerable` is cloned before it is enhanced; it is not modified directly.
|
9
|
+
#
|
10
|
+
# @example Enhances `arr` so that an animated progress bar prints while iterating.
|
11
|
+
# arr = (0...1000)
|
12
|
+
# arr_tqdm = Decorator.new(arr).enhance
|
13
|
+
# arr_tqdm.each { |x| sleep 0.01 }
|
14
|
+
class Decorator
|
15
|
+
|
16
|
+
attr_reader :printer, :enumerable, :iteration, :start_time
|
17
|
+
|
18
|
+
# Initialize a new Decorator. Typically you wouldn't use this object, but
|
19
|
+
# would immediately call `#enhance` to retrieve the enhanced `Enumerable`.
|
20
|
+
#
|
21
|
+
# @param enumerable [Enumerable] the Enumerable object to be enhanced
|
22
|
+
# @param options [Hash] more options used to control behavior of the progress bar
|
23
|
+
# @option options [String] :desc a short description added to the beginning of the progress bar
|
24
|
+
# @option options [Integer] :total (self.size) the expected number of iterations
|
25
|
+
# @option options [File, IO] :file ($stderr) a file-like object to output the progress bar to
|
26
|
+
# @option options [Boolean] :leave (false) should the progress bar should stay on screen after it's done?
|
27
|
+
# @option options [Integer] :min_iters see `:min_interval`
|
28
|
+
# @option options [Float] :min_interval If less than min_interval seconds or min_iters iterations have passed since
|
29
|
+
# the last progress meter update, it is not updated again.
|
30
|
+
#
|
31
|
+
# @example
|
32
|
+
# a = (1...1000)
|
33
|
+
# Decorator.new(a).enhance.each { |x| sleep 0.01 }
|
34
|
+
#
|
35
|
+
# @example
|
36
|
+
# a = [1, 2, 3, 4]
|
37
|
+
# Decorator.new(a, file: $stdout, leave: true)
|
38
|
+
def initialize(enumerable, options={})
|
39
|
+
@enumerable = enumerable
|
40
|
+
options.merge!(total: total!) unless options[:total]
|
41
|
+
@printer = Printer.new(options)
|
42
|
+
@min_iterations = options[:min_iters] || 1
|
43
|
+
@min_interval = options[:min_interval] || 0.5
|
44
|
+
@leave = options[:leave] || false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Starts the textual progress bar.
|
48
|
+
def start!
|
49
|
+
@iteration = 0
|
50
|
+
@start_time = Time.now
|
51
|
+
printer.start
|
52
|
+
end
|
53
|
+
|
54
|
+
# Called everytime the textual progress bar might need to be updated (i.e. on
|
55
|
+
# every iteration). We still check whether the update is appropriate to print to
|
56
|
+
# the progress bar before doing so, according to the `:min_iters` and `:min_interval`
|
57
|
+
# options.
|
58
|
+
#
|
59
|
+
# @see #initialize
|
60
|
+
def increment!
|
61
|
+
@iteration += 1
|
62
|
+
|
63
|
+
return unless (iteration - last_printed_iteration) >= @min_iterations
|
64
|
+
# We check the counter first, to reduce the overhead of Time.now
|
65
|
+
return unless (current_time! - last_print_time) >= @min_interval
|
66
|
+
|
67
|
+
printer.status(iteration, elapsed_time!)
|
68
|
+
@last_printed_iteration = iteration
|
69
|
+
@last_print_time = current_time
|
70
|
+
end
|
71
|
+
|
72
|
+
# Prints the final state of the textual progress bar. Based on the `:leave` option, this
|
73
|
+
# may include deleting it entirely.
|
74
|
+
def finish!
|
75
|
+
return printer.null_finish unless @leave
|
76
|
+
|
77
|
+
printer.finish(iteration, elapsed_time!, reprint?)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Enhances the wrapped `Enumerable`.
|
81
|
+
#
|
82
|
+
# @note The `Enumerable` is cloned (shallow copied) before it is enhanced; it is not modified directly.
|
83
|
+
#
|
84
|
+
# @return [Enumerable] a clone of Enumerable enhanced so that every call to `#each` animates the
|
85
|
+
# progress bar.
|
86
|
+
def enhance
|
87
|
+
decorate_enumerable_each
|
88
|
+
enhanced
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def decorate_enumerable_each
|
94
|
+
tqdm = self
|
95
|
+
enhanced.define_singleton_method(:each) do |*args, &block|
|
96
|
+
tqdm.start!
|
97
|
+
result = super(*args) do |item|
|
98
|
+
block.call item if block
|
99
|
+
tqdm.increment!
|
100
|
+
end
|
101
|
+
tqdm.finish!
|
102
|
+
result
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def enhanced
|
107
|
+
@enhanced ||= enumerable.clone
|
108
|
+
end
|
109
|
+
|
110
|
+
def total!
|
111
|
+
enumerable.size rescue enumerable.count rescue nil
|
112
|
+
end
|
113
|
+
|
114
|
+
def last_printed_iteration
|
115
|
+
@last_printed_iteration ||= iteration
|
116
|
+
end
|
117
|
+
|
118
|
+
def last_print_time
|
119
|
+
@last_print_time ||= start_time
|
120
|
+
end
|
121
|
+
|
122
|
+
def current_time
|
123
|
+
@current_time ||= current_time!
|
124
|
+
end
|
125
|
+
|
126
|
+
def current_time!
|
127
|
+
@current_time = Time.now
|
128
|
+
end
|
129
|
+
|
130
|
+
def elapsed_time!
|
131
|
+
current_time! - start_time
|
132
|
+
end
|
133
|
+
|
134
|
+
def reprint?
|
135
|
+
last_printed_iteration < iteration
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
data/lib/tqdm/printer.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'tqdm/printer/default_format'
|
2
|
+
require 'forwardable'
|
3
|
+
|
4
|
+
module Tqdm
|
5
|
+
|
6
|
+
# Prints a status line, handling the deletion of previously printed lines with carriage
|
7
|
+
# returns as necessary. Instantiated by a `Decorator`.
|
8
|
+
#
|
9
|
+
# @private
|
10
|
+
class Printer
|
11
|
+
extend Forwardable
|
12
|
+
|
13
|
+
attr_reader :total, :format, :file
|
14
|
+
|
15
|
+
# Initialize a new Printer.
|
16
|
+
#
|
17
|
+
# @param options [Hash] the options for the instantiating Tqdm::Decorator
|
18
|
+
#
|
19
|
+
# @see Tqdm::Decorator#initialize
|
20
|
+
def initialize(options)
|
21
|
+
@total = options[:total]
|
22
|
+
@format = Printer::DefaultFormat.new(options)
|
23
|
+
@file = options[:file] || $stderr
|
24
|
+
@last_printed_length = 0
|
25
|
+
end
|
26
|
+
|
27
|
+
def start
|
28
|
+
line(0, 0.0)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Pads a status line so that it is long enough to overwrite the previously written line
|
32
|
+
#
|
33
|
+
# @param iteration [Integer] number of iterations, out of the total, that are completed
|
34
|
+
# @param elapsed_time [Float] number of seconds passed since start
|
35
|
+
# @return [String] the padded line
|
36
|
+
def padded_line(iteration, elapsed_time)
|
37
|
+
meter_line = line(iteration, elapsed_time)
|
38
|
+
pad_size = [@last_printed_length - meter_line.size, 0].max
|
39
|
+
@last_printed_length = meter_line.size
|
40
|
+
meter_line + ' ' * pad_size
|
41
|
+
end
|
42
|
+
|
43
|
+
# Prints a line of text to @file, after deleting the previously printed line
|
44
|
+
#
|
45
|
+
# @param iteration [Integer] number of iterations, out of the total, that are completed
|
46
|
+
# @param elapsed_time [Float] number of seconds passed since start
|
47
|
+
def status(iteration, elapsed_time)
|
48
|
+
file.write("\r" + padded_line(iteration, elapsed_time))
|
49
|
+
file.flush
|
50
|
+
end
|
51
|
+
|
52
|
+
# Prints a line of text to @file, after deleting the previously printed line
|
53
|
+
#
|
54
|
+
# @param iteration [Integer] number of iterations, out of the total, that are completed
|
55
|
+
# @param elapsed_time [Float] number of seconds passed since start
|
56
|
+
# @param reprint [Boolean] do we need to reprint the line one last time?
|
57
|
+
def finish(iteration, elapsed_time, reprint)
|
58
|
+
file.write("\r" + padded_line(iteration, elapsed_time)) if reprint
|
59
|
+
file.write("\n")
|
60
|
+
file.flush
|
61
|
+
end
|
62
|
+
|
63
|
+
# Disappear without a trace.
|
64
|
+
def null_finish
|
65
|
+
file.write("\r" + ' ' * @last_printed_length + "\r")
|
66
|
+
end
|
67
|
+
|
68
|
+
def_delegators :format, :line, :meter
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Tqdm
|
2
|
+
class Printer
|
3
|
+
class DefaultFormat
|
4
|
+
PROGRESS_BAR_WIDTH = 10
|
5
|
+
SPACE = '-'
|
6
|
+
PROGRESS = '#'
|
7
|
+
|
8
|
+
# Initialize a new DefaultFormat.
|
9
|
+
#
|
10
|
+
# @param options [Hash] the options for the Tqdm::Decorator
|
11
|
+
#
|
12
|
+
# @see Tqdm::Decorator#initialize
|
13
|
+
def initialize(options)
|
14
|
+
@total = options[:total]
|
15
|
+
@prefix = options[:desc] ? options[:desc] + ': ' : ''
|
16
|
+
end
|
17
|
+
|
18
|
+
# Formats the prefix, progress bar and meter as a complete line to be printed
|
19
|
+
#
|
20
|
+
# @param iteration [Integer] number of finished iterations
|
21
|
+
# @param elapsed_time [Float] total number of seconds passed since start
|
22
|
+
# @return [String] the complete line to print
|
23
|
+
#
|
24
|
+
# @see #meter
|
25
|
+
def line(iteration, elapsed_time)
|
26
|
+
prefix + meter(iteration, total, elapsed_time)
|
27
|
+
end
|
28
|
+
|
29
|
+
# Formats a count (n) of total items processed + an elapsed time into a
|
30
|
+
# textual progress bar + meter.
|
31
|
+
#
|
32
|
+
# @param n [Integer] number of finished iterations
|
33
|
+
# @param total [Integer, nil] total number of iterations, or nil
|
34
|
+
# @param elapsed [Float] number of seconds passed since start
|
35
|
+
# @return [String] a textual progress bar + meter
|
36
|
+
def meter(n, total, elapsed)
|
37
|
+
total = (n > total ? nil : total) if total
|
38
|
+
|
39
|
+
elapsed_str = interval(elapsed)
|
40
|
+
rate = elapsed && elapsed > 0 ? ('%5.2f' % (n / elapsed)) : '?'
|
41
|
+
|
42
|
+
if total
|
43
|
+
frac = n.to_f / total
|
44
|
+
|
45
|
+
bar_length = (frac * PROGRESS_BAR_WIDTH).to_i
|
46
|
+
bar = PROGRESS * bar_length + SPACE * (PROGRESS_BAR_WIDTH - bar_length)
|
47
|
+
|
48
|
+
percentage = '%3d%%' % (frac * 100)
|
49
|
+
|
50
|
+
left_str = n > 0 ? (interval(elapsed / n * (total - n))) : '?'
|
51
|
+
|
52
|
+
'|%s| %d/%d %s [elapsed: %s left: %s, %s iters/sec]' % [bar, n, total,
|
53
|
+
percentage, elapsed_str, left_str, rate]
|
54
|
+
else
|
55
|
+
'%d [elapsed: %s, %s iters/sec]' % [n, elapsed_str, rate]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
attr_reader :total, :prefix
|
62
|
+
|
63
|
+
# Formats a number of seconds into an hh:mm:ss string.
|
64
|
+
#
|
65
|
+
# @param t [Integer] a number of seconds
|
66
|
+
# @return [String] an hh:mm:ss string
|
67
|
+
def interval(seconds)
|
68
|
+
m, s = seconds.to_i.divmod(60)
|
69
|
+
h, m = m.divmod(60)
|
70
|
+
if h > 0 then '%d:%02d:%02d' % [h, m, s]; else '%02d:%02d' % [m, s]; end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/tqdm/sequel.rb
CHANGED
@@ -1,25 +1,28 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require 'sequel'
|
2
|
+
require 'tqdm'
|
3
3
|
|
4
4
|
# @see Sequel::Dataset
|
5
5
|
module Sequel
|
6
|
-
|
6
|
+
|
7
7
|
# In order to use `Tqdm` with Sequel Datasets, we can simply extend `Sequel::Dataset`
|
8
|
-
# with the same `#
|
8
|
+
# with the same `#with_progress` method
|
9
9
|
#
|
10
|
-
# @see Enumerable#
|
10
|
+
# @see Enumerable#with_progress
|
11
11
|
# @see http://sequel.jeremyevans.net/
|
12
12
|
# @see http://sequel.jeremyevans.net/rdoc/classes/Sequel/Dataset.html
|
13
13
|
class Dataset
|
14
|
-
|
15
|
-
# Returns a clone of `self` where all calls to `#each` and related methods will print an animated progress bar
|
14
|
+
|
15
|
+
# Returns a clone of `self` where all calls to `#each` and related methods will print an animated progress bar
|
16
16
|
# while iterating.
|
17
17
|
#
|
18
|
-
# @
|
19
|
-
|
20
|
-
|
18
|
+
# @param options [Hash] options are the same as Enumerable#with_progress
|
19
|
+
#
|
20
|
+
# @see Enumerable#with_progress
|
21
|
+
def with_progress(options = {})
|
22
|
+
Tqdm::Decorator.new(self, options).enhance
|
21
23
|
end
|
22
|
-
|
24
|
+
alias :tqdm :with_progress
|
25
|
+
|
23
26
|
end
|
24
|
-
|
25
|
-
end
|
27
|
+
|
28
|
+
end
|
data/lib/tqdm/version.rb
CHANGED
data/tqdm.gemspec
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tqdm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theodore Pak
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-01-
|
11
|
+
date: 2016-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -54,8 +54,10 @@ files:
|
|
54
54
|
- Rakefile
|
55
55
|
- lib/core_ext/enumerable.rb
|
56
56
|
- lib/tqdm.rb
|
57
|
+
- lib/tqdm/decorator.rb
|
58
|
+
- lib/tqdm/printer.rb
|
59
|
+
- lib/tqdm/printer/default_format.rb
|
57
60
|
- lib/tqdm/sequel.rb
|
58
|
-
- lib/tqdm/utils.rb
|
59
61
|
- lib/tqdm/version.rb
|
60
62
|
- tqdm.gemspec
|
61
63
|
homepage: https://github.com/powerpak/tqdm-ruby
|
data/lib/tqdm/utils.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require "tqdm"
|
2
|
-
|
3
|
-
module Tqdm
|
4
|
-
|
5
|
-
# Utility functions related to `Tqdm`.
|
6
|
-
module Utils
|
7
|
-
|
8
|
-
# Formats a number of seconds into an hh:mm:ss string.
|
9
|
-
#
|
10
|
-
# @param t [Integer] a number of seconds
|
11
|
-
# @return [String] an hh:mm:ss string
|
12
|
-
def format_interval(t)
|
13
|
-
mins, s = t.to_i.divmod(60)
|
14
|
-
h, m = mins.divmod(60)
|
15
|
-
if h > 0 then '%d:%02d:%02d' % [h, m, s]; else '%02d:%02d' % [m, s]; end
|
16
|
-
end
|
17
|
-
|
18
|
-
# Formats a count (n) of total items processed + an elapsed time into a
|
19
|
-
# textual progress bar + meter.
|
20
|
-
#
|
21
|
-
# @param n [Integer] number of finished iterations
|
22
|
-
# @param total [Integer, nil] total number of iterations, or nil
|
23
|
-
# @param elapsed [Integer] number of seconds passed since start
|
24
|
-
# @return [String] a textual progress bar + meter
|
25
|
-
def format_meter(n, total, elapsed)
|
26
|
-
total = (n > total ? nil : total) if total
|
27
|
-
|
28
|
-
elapsed_str = format_interval(elapsed)
|
29
|
-
rate = elapsed && elapsed > 0 ? ('%5.2f' % (n / elapsed)) : '?'
|
30
|
-
|
31
|
-
if total
|
32
|
-
frac = n.to_f / total
|
33
|
-
|
34
|
-
bar_length = (frac * N_BARS).to_i
|
35
|
-
bar = '#' * bar_length + '-' * (N_BARS - bar_length)
|
36
|
-
|
37
|
-
percentage = '%3d%%' % (frac * 100)
|
38
|
-
|
39
|
-
left_str = n > 0 ? (format_interval(elapsed / n * (total - n))) : '?'
|
40
|
-
|
41
|
-
'|%s| %d/%d %s [elapsed: %s left: %s, %s iters/sec]' % [bar, n, total,
|
42
|
-
percentage, elapsed_str, left_str, rate]
|
43
|
-
else
|
44
|
-
'%d [elapsed: %s, %s iters/sec]' % [n, elapsed_str, rate]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|