tqdm 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3dc522c1cd180b959a8c36c2a3f1fb41ffdd51a8
4
- data.tar.gz: e17546f682e0adfe9b6970bc02477590b1d355cd
2
+ SHA256:
3
+ metadata.gz: 72b63925baf593f87124eff5deaba635425475a900dd4432d07c772026488b45
4
+ data.tar.gz: 036ac2f161ef3fca07351818d0de75ec0a4c932af831f73370d26c318213a5f1
5
5
  SHA512:
6
- metadata.gz: 2a5aecb337cfec0e565deabd81741aff57c48c1b1b13b562c08c9173ae6b9e520aeb18561734a317ee9ee2943dc0df3869c71495c17ff584580d7787857011b2
7
- data.tar.gz: 71e5e62669db44fe2d3b7aa42696c22bf5c34f87f374b48505ea9899536c9a614ae9ce92b874799e3e5df46525f2fc9ea251dea2a5f86c238db7f34468aa291b
6
+ metadata.gz: ca9b6cec37e773998ab099f6ab57e5c1d16f6fde371d82000d7a8750276ea5b3a018760ec0703a6b02830808d6292c4b387dd2beb733221b3b19f1d20bcd3504
7
+ data.tar.gz: c8e3a86ac26c82998a792b1b361fd040953a6078397a69c7d4a09d95641b45b61a04ea5288768a0662169f8e557ec6adc47f1bdd7fdfb66bc02e0027f7d6fa03
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --require spec_helper
3
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ - "2.0.0"
6
+ - "2.1.8"
7
+ - "2.2.4"
8
+ - "2.6.5"
9
+ - "2.7.2"
10
+ - "3.0.5"
11
+ - "3.1.3"
12
+ - rbx
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2016 Theodore Pak
1
+ Copyright (c) 2022 Theodore Pak
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,18 +1,18 @@
1
1
  # tqdm-ruby
2
- [![Gem Version](https://badge.fury.io/rb/tqdm.svg)](https://badge.fury.io/rb/tqdm)
2
+ [![Build Status](https://travis-ci.org/powerpak/tqdm-ruby.svg?branch=master)](https://travis-ci.org/powerpak/tqdm-ruby) [![Gem Version](https://badge.fury.io/rb/tqdm.svg)](https://badge.fury.io/rb/tqdm)
3
3
 
4
4
  tqdm-ruby allows you to add a progress indicator to your loops with minimal effort.
5
5
 
6
6
  It is a port of the excellent [tqdm library][tqdm] for python. tqdm (read taqadum, تقدّم) means "progress" in Arabic.
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
+ Calling `#tqdm` (or `#with_progress`) on any `Enumerable` returns an enhanced clone that animates a meter during iteration.
9
9
 
10
10
  ```ruby
11
11
  require 'tqdm'
12
12
  (0...1000).tqdm.each { |x| sleep 0.01 }
13
13
  ```
14
14
 
15
- The default output looks like this:
15
+ The default output is sent to `$stderr` and looks like this:
16
16
 
17
17
  ![|####------| 492/1000 49% [elapsed: 00:05 left: 00:05, 88.81 iters/sec]](http://i.imgur.com/6y0t7XS.gif)
18
18
 
@@ -29,7 +29,7 @@ It works equally well from within irb, [pry](http://pryrepl.org/), and [iRuby no
29
29
 
30
30
  Install it globally from [Rubygems](https://rubygems.org/gems/tqdm):
31
31
 
32
- $ gem install tqdm # (might need sudo on OS X)
32
+ $ gem install tqdm # (might need sudo for a system ruby)
33
33
 
34
34
  *or* add this line to your application's Gemfile:
35
35
 
@@ -82,7 +82,7 @@ DB[:items].where{ price > 10 }.with_progress.each { |row| "do some processing he
82
82
  ## TODO
83
83
 
84
84
  1. Performance improvements
85
- 2. Test/benchmark suite
85
+ 2. Add benchmark suite, expand test coverage
86
86
  3. Add smoothing for speed estimates
87
87
  4. Support unicode output (smooth blocks)
88
88
  5. By default, resize to the apparent width of the output terminal
data/Rakefile CHANGED
@@ -1 +1,8 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec) do |t|
5
+ t.pattern = Dir.glob('spec/**/*_spec.rb')
6
+ end
7
+
8
+ task :default => :spec
@@ -12,6 +12,8 @@ module Tqdm
12
12
  # arr_tqdm = Decorator.new(arr).enhance
13
13
  # arr_tqdm.each { |x| sleep 0.01 }
14
14
  class Decorator
15
+
16
+ extend Forwardable
15
17
 
16
18
  attr_reader :printer, :enumerable, :iteration, :start_time
17
19
 
@@ -42,13 +44,13 @@ module Tqdm
42
44
  @min_iterations = options[:min_iters] || 1
43
45
  @min_interval = options[:min_interval] || 0.5
44
46
  @leave = options[:leave] || false
47
+ @force_refreeze = false
45
48
  end
46
49
 
47
50
  # Starts the textual progress bar.
48
51
  def start!
49
- @iteration = 0
50
- @start_time = Time.now
51
- printer.start
52
+ @iteration = @last_printed_iteration = 0
53
+ @start_time = @last_print_time = current_time!
52
54
  end
53
55
 
54
56
  # Called everytime the textual progress bar might need to be updated (i.e. on
@@ -63,8 +65,9 @@ module Tqdm
63
65
  return unless (iteration - last_printed_iteration) >= @min_iterations
64
66
  # We check the counter first, to reduce the overhead of Time.now
65
67
  return unless (current_time! - last_print_time) >= @min_interval
68
+ return if iteration == total && !@leave
66
69
 
67
- printer.status(iteration, elapsed_time!)
70
+ printer.status(iteration, elapsed_time!)
68
71
  @last_printed_iteration = iteration
69
72
  @last_print_time = current_time
70
73
  end
@@ -85,6 +88,7 @@ module Tqdm
85
88
  # progress bar.
86
89
  def enhance
87
90
  decorate_enumerable_each
91
+ enhanced.freeze if @force_refreeze
88
92
  enhanced
89
93
  end
90
94
 
@@ -94,8 +98,8 @@ module Tqdm
94
98
  tqdm = self
95
99
  enhanced.define_singleton_method(:each) do |*args, &block|
96
100
  tqdm.start!
97
- result = super(*args) do |item|
98
- block.call item if block
101
+ result = super(*args) do |*items|
102
+ block.call *items if block
99
103
  tqdm.increment!
100
104
  end
101
105
  tqdm.finish!
@@ -104,7 +108,20 @@ module Tqdm
104
108
  end
105
109
 
106
110
  def enhanced
107
- @enhanced ||= enumerable.clone
111
+ @enhanced ||= enumerable_unfrozen
112
+ end
113
+
114
+ # Uses progressively more invasive techniques to return an unfrozen copy of @enumerable
115
+ # Significantly, for some classes like Sequel::Dataset, both #clone and #dup re-freeze
116
+ # the object, so we have to drop back to Object#clone
117
+ def enumerable_unfrozen
118
+ unfrozen = enumerable.clone(freeze: false)
119
+ return unfrozen unless unfrozen.frozen?
120
+ unfrozen = enumerable.dup
121
+ return unfrozen unless unfrozen.frozen?
122
+ @force_refreeze = true
123
+ unfrozen = Object.instance_method(:clone).bind(enumerable).call(freeze: false)
124
+ unfrozen
108
125
  end
109
126
 
110
127
  def total!
@@ -134,5 +151,7 @@ module Tqdm
134
151
  def reprint?
135
152
  last_printed_iteration < iteration
136
153
  end
154
+
155
+ def_delegator :printer, :total
137
156
  end
138
157
  end
@@ -39,7 +39,7 @@ module Tqdm
39
39
  elapsed_str = interval(elapsed)
40
40
  rate = elapsed && elapsed > 0 ? ('%5.2f' % (n / elapsed)) : '?'
41
41
 
42
- if total
42
+ if total && total > 0
43
43
  frac = n.to_f / total
44
44
 
45
45
  bar_length = (frac * PROGRESS_BAR_WIDTH).to_i
@@ -62,7 +62,7 @@ module Tqdm
62
62
 
63
63
  # Formats a number of seconds into an hh:mm:ss string.
64
64
  #
65
- # @param t [Integer] a number of seconds
65
+ # @param seconds [Integer] a number of seconds
66
66
  # @return [String] an hh:mm:ss string
67
67
  def interval(seconds)
68
68
  m, s = seconds.to_i.divmod(60)
data/lib/tqdm/printer.rb CHANGED
@@ -23,10 +23,6 @@ module Tqdm
23
23
  @file = options[:file] || $stderr
24
24
  @last_printed_length = 0
25
25
  end
26
-
27
- def start
28
- line(0, 0.0)
29
- end
30
26
 
31
27
  # Pads a status line so that it is long enough to overwrite the previously written line
32
28
  #
data/lib/tqdm/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Tqdm
2
2
  # The version of this module and gem by the same name.
3
- VERSION = "0.2.0"
3
+ VERSION = "0.4.0"
4
4
  end
@@ -0,0 +1,96 @@
1
+ require 'spec_helper'
2
+ require 'timecop'
3
+ require_relative '../lib/tqdm'
4
+
5
+ describe 'When enumerating over an object' do
6
+ before { Timecop.freeze }
7
+ after { Timecop.return }
8
+
9
+ def with_stderr(&block)
10
+ old_stderr = $stderr
11
+ $stderr = StringIO.new
12
+
13
+ block.call
14
+
15
+ return $stderr.string
16
+ ensure
17
+ $stderr = old_stderr
18
+ end
19
+
20
+ def timecop_loop(enumerable, options = {})
21
+ enumerable.tqdm(options).each do |x|
22
+ Timecop.travel 1
23
+ end
24
+ end
25
+
26
+ context 'that has zero elements' do
27
+ let(:enumerable) { (0...0) }
28
+
29
+ context 'with default options' do
30
+ it 'never displays a progress bar' do
31
+ final_stderr = with_stderr { timecop_loop(enumerable) }
32
+ expect(final_stderr).to eq "\r\r"
33
+ end
34
+ end
35
+
36
+ context 'with leave: true' do
37
+ it 'never displays a progress bar' do
38
+ final_stderr = with_stderr { timecop_loop(enumerable, leave: true) }
39
+ expect(final_stderr).to eq "\n"
40
+ end
41
+ end
42
+ end
43
+
44
+ context 'that has one element' do
45
+ let(:enumerable) { (0...1) }
46
+
47
+ context 'with default options' do
48
+ it 'never displays a progress bar' do
49
+ final_stderr = with_stderr { timecop_loop(enumerable) }
50
+ expect(final_stderr).to eq "\r\r"
51
+ end
52
+ end
53
+
54
+ context 'with leave: true' do
55
+ it 'displays a progress bar once at 100%' do
56
+ final_stderr = with_stderr { timecop_loop(enumerable, leave: true) }
57
+ expect(final_stderr).to eq "" \
58
+ "\r|##########| 1/1 100% [elapsed: 00:01 left: 00:00, 1.00 iters/sec]" \
59
+ "\n"
60
+ end
61
+ end
62
+
63
+ end
64
+
65
+ context 'that has several (five) elements' do
66
+ let(:enumerable) { (0...5) }
67
+
68
+ context 'with default options' do
69
+ it 'displays a progress bar for the first four steps and deletes it' do
70
+ final_stderr = with_stderr { timecop_loop(enumerable) }
71
+
72
+ expect(final_stderr).to eq "" \
73
+ "\r|##--------| 1/5 20% [elapsed: 00:01 left: 00:04, 1.00 iters/sec]" \
74
+ "\r|####------| 2/5 40% [elapsed: 00:02 left: 00:03, 1.00 iters/sec]" \
75
+ "\r|######----| 3/5 60% [elapsed: 00:03 left: 00:02, 1.00 iters/sec]" \
76
+ "\r|########--| 4/5 80% [elapsed: 00:04 left: 00:01, 1.00 iters/sec]" \
77
+ "\r " \
78
+ "\r"
79
+ end
80
+ end
81
+
82
+ context 'with leave: true' do
83
+ it 'displays a progress bar with as many steps as elements and leaves it' do
84
+ final_stderr = with_stderr { timecop_loop(enumerable, leave: true) }
85
+
86
+ expect(final_stderr).to eq "" \
87
+ "\r|##--------| 1/5 20% [elapsed: 00:01 left: 00:04, 1.00 iters/sec]" \
88
+ "\r|####------| 2/5 40% [elapsed: 00:02 left: 00:03, 1.00 iters/sec]" \
89
+ "\r|######----| 3/5 60% [elapsed: 00:03 left: 00:02, 1.00 iters/sec]" \
90
+ "\r|########--| 4/5 80% [elapsed: 00:04 left: 00:01, 1.00 iters/sec]" \
91
+ "\r|##########| 5/5 100% [elapsed: 00:05 left: 00:00, 1.00 iters/sec]" \
92
+ "\n"
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+ require 'timecop'
3
+ require_relative '../lib/tqdm'
4
+ require_relative '../lib/tqdm/sequel'
5
+
6
+ describe 'When enumerating over a Sequel dataset' do
7
+ before { Timecop.freeze }
8
+ after { Timecop.return }
9
+
10
+ def timecop_loop(dataset, options = {})
11
+ dataset.tqdm(options).each do |x|
12
+ Timecop.travel 1
13
+ end
14
+ end
15
+
16
+ context 'that has several (five) elements' do
17
+ let(:database) do
18
+ db = Sequel.sqlite
19
+ db.create_table :items do
20
+ primary_key :id
21
+ Float :price
22
+ end
23
+
24
+ (0...5).each { db[:items].insert(price: rand * 100) }
25
+
26
+ db
27
+ end
28
+
29
+ context 'with default options' do
30
+ it 'displays a progress bar for the first four steps and deletes it' do
31
+ final_stderr = with_stderr { timecop_loop(database[:items]) }
32
+
33
+ expect(final_stderr).to eq "" \
34
+ "\r|##--------| 1/5 20% [elapsed: 00:01 left: 00:04, 1.00 iters/sec]" \
35
+ "\r|####------| 2/5 40% [elapsed: 00:02 left: 00:03, 1.00 iters/sec]" \
36
+ "\r|######----| 3/5 60% [elapsed: 00:03 left: 00:02, 1.00 iters/sec]" \
37
+ "\r|########--| 4/5 80% [elapsed: 00:04 left: 00:01, 1.00 iters/sec]" \
38
+ "\r " \
39
+ "\r"
40
+ end
41
+
42
+ it 'returns a re-frozen object' do
43
+ enhanced = timecop_loop(database[:items])
44
+ expect(enhanced.frozen?).to be_truthy
45
+ end
46
+
47
+ it 'returns an object inheriting from Sequel::Dataset' do
48
+ enhanced = timecop_loop(database[:items])
49
+ expect(enhanced).to be_kind_of(Sequel::Dataset)
50
+ end
51
+ end
52
+
53
+ context 'with leave: true' do
54
+ it 'displays a progress bar with as many steps as elements and leaves it' do
55
+ final_stderr = with_stderr { timecop_loop(database[:items], leave: true) }
56
+
57
+ expect(final_stderr).to eq "" \
58
+ "\r|##--------| 1/5 20% [elapsed: 00:01 left: 00:04, 1.00 iters/sec]" \
59
+ "\r|####------| 2/5 40% [elapsed: 00:02 left: 00:03, 1.00 iters/sec]" \
60
+ "\r|######----| 3/5 60% [elapsed: 00:03 left: 00:02, 1.00 iters/sec]" \
61
+ "\r|########--| 4/5 80% [elapsed: 00:04 left: 00:01, 1.00 iters/sec]" \
62
+ "\r|##########| 5/5 100% [elapsed: 00:05 left: 00:00, 1.00 iters/sec]" \
63
+ "\n"
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,20 @@
1
+ RSpec.configure do |config|
2
+ config.expect_with :rspec do |expectations|
3
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
4
+ end
5
+
6
+ config.mock_with :rspec do |mocks|
7
+ mocks.verify_partial_doubles = true
8
+ end
9
+ end
10
+
11
+ def with_stderr(&block)
12
+ old_stderr = $stderr
13
+ $stderr = StringIO.new
14
+
15
+ block.call
16
+
17
+ return $stderr.string
18
+ ensure
19
+ $stderr = old_stderr
20
+ end
data/tqdm.gemspec CHANGED
@@ -18,8 +18,12 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "bundler"
22
22
  spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "sequel"
24
+ spec.add_development_dependency "sqlite3"
25
+ spec.add_development_dependency "rspec"
26
+ spec.add_development_dependency "timecop"
23
27
 
24
28
  spec.required_ruby_version = '>= 1.9.2'
25
29
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tqdm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.4.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-21 00:00:00.000000000 Z
11
+ date: 2022-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.3'
19
+ version: '0'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '1.3'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,6 +38,62 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sequel
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: sqlite3
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: timecop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
41
97
  description: Enhances Enumerables to show progress while iterating. (Port of tqdm
42
98
  for Python.)
43
99
  email:
@@ -47,6 +103,8 @@ extensions: []
47
103
  extra_rdoc_files: []
48
104
  files:
49
105
  - ".gitignore"
106
+ - ".rspec"
107
+ - ".travis.yml"
50
108
  - ".yardopts"
51
109
  - Gemfile
52
110
  - LICENSE.txt
@@ -59,6 +117,9 @@ files:
59
117
  - lib/tqdm/printer/default_format.rb
60
118
  - lib/tqdm/sequel.rb
61
119
  - lib/tqdm/version.rb
120
+ - spec/enumerable_spec.rb
121
+ - spec/sequel_spec.rb
122
+ - spec/spec_helper.rb
62
123
  - tqdm.gemspec
63
124
  homepage: https://github.com/powerpak/tqdm-ruby
64
125
  licenses:
@@ -79,9 +140,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
140
  - !ruby/object:Gem::Version
80
141
  version: '0'
81
142
  requirements: []
82
- rubyforge_project:
83
- rubygems_version: 2.2.5
143
+ rubygems_version: 3.1.6
84
144
  signing_key:
85
145
  specification_version: 4
86
146
  summary: Enhances Enumerables to show progress while iterating.
87
- test_files: []
147
+ test_files:
148
+ - spec/enumerable_spec.rb
149
+ - spec/sequel_spec.rb
150
+ - spec/spec_helper.rb