rpv 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/CHANGELOG.md +8 -0
- data/README.md +104 -3
- data/Rakefile +12 -0
- data/benchmark.rb +48 -0
- data/lib/rpv/extensions.rb +9 -16
- data/lib/rpv/options.rb +3 -3
- data/lib/rpv/version.rb +1 -1
- data/lib/rpv.rb +24 -4
- metadata +3 -3
- data/lib/rpv/global.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b434261aec0276464e49a998634fc98fae8dfee68a98c24216ec77acff0f3ea6
|
4
|
+
data.tar.gz: 87fb6855cc287665162904f726cdf931c77d903c895709399510ce6c43d9a191
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03eca1d617b473e9e7132369a47ca5f9c7849d83c4137496d324a754eaaf8e7d2f6c0177055155ff0dd16edf52e8da5f9e95d5e7ca0ad10795ac0a4a1210a980
|
7
|
+
data.tar.gz: dc2a27f8adb26aa807ae9f818a08afbe0c1232673165a46ea7b976526b3a9e4e0bc75325f8b4ea0c6ee55d95d29ce82cfcb710ddf698d9acb50e5958386c9846
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.2.0] - 2024-12-18
|
4
|
+
|
5
|
+
- Improve Abbreviated API.
|
6
|
+
- `increment` accepts an optional `amount` argument.
|
7
|
+
- More options supported: `format`, `delay_start`, `width`, `height`, `timer`, `eta`, and `rate`.
|
8
|
+
- Also added a `rate_limit` option that does work. It was there before but it really didn't do anything.
|
9
|
+
- Improved documentation.
|
10
|
+
|
3
11
|
## [0.1.0] - 2024-12-11
|
4
12
|
|
5
13
|
- Initial release
|
data/README.md
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# Rpv
|
2
2
|
|
3
|
+
Rpv provides progress bar and rate limiting features to be used in Ruby scripts and programs. It
|
4
|
+
supports multiple parallel bars. It wraps [pv](https://ivarch.com/programs/pv.shtml), which needs to
|
5
|
+
be installed on the system.
|
6
|
+
|
3
7
|
## Installation
|
4
8
|
|
5
9
|
Install the gem and add to the application's Gemfile by executing:
|
@@ -10,15 +14,112 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
10
14
|
|
11
15
|
$ gem install rpv
|
12
16
|
|
17
|
+
You need to have pv installed. [It is available for most
|
18
|
+
systems](https://ivarch.com/programs/pv.shtml#packages).
|
19
|
+
|
13
20
|
## Usage
|
14
21
|
|
15
|
-
|
22
|
+
There are some [examples](examples/) available. Now for the details:
|
23
|
+
|
24
|
+
### Generic API
|
25
|
+
|
26
|
+
You'll first need to require the library:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require "rpv"
|
30
|
+
```
|
31
|
+
|
32
|
+
Rpv provides a very simple API: you instantiate the bar (with some options), then you call
|
33
|
+
`.increment` on it as many times as needed to make it advance, then `.finish` to finish the
|
34
|
+
proccess:
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
bar = Rpv.new
|
38
|
+
10.times do
|
39
|
+
# do something
|
40
|
+
bar.increment
|
41
|
+
end
|
42
|
+
bar.finish
|
43
|
+
```
|
44
|
+
|
45
|
+
`increment` takes an optional integer argument to make it advance more than one step.
|
46
|
+
|
47
|
+
#### Block syntax
|
48
|
+
|
49
|
+
Rpv also provides a block syntax, that saves you from assigning the variable and calling `.finish`:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
Rpv.new do |bar|
|
53
|
+
10.times do
|
54
|
+
# do something
|
55
|
+
bar.increment
|
56
|
+
end
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
#### Options
|
61
|
+
|
62
|
+
Rpv supports some options, which can be passed to the initializer:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
Rpv.new(name: "Processing items") do |rpv|
|
66
|
+
...
|
67
|
+
```
|
68
|
+
|
69
|
+
They all map to equally named options in `pv` (and the defaults are the same), so the best place to
|
70
|
+
look for details is [pv's manual page](https://ivarch.com/programs/quickref/pv.shtml). But here is a
|
71
|
+
summary of those that are supported:
|
72
|
+
|
73
|
+
| Option | What it does | Default |
|
74
|
+
|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
|
75
|
+
| **Display options** | | If no display options are specified: `progress`, `timer`, `eta`, and `rate`. Otherwise, only those explicitly specified. |
|
76
|
+
| `progress` | Display a progress bar. If no size is specified, the bar just moves from left to right. | |
|
77
|
+
| `timer` | Display total elapsed time. | |
|
78
|
+
| `eta` | Display estimated time to completion based on the current progress and rate. | |
|
79
|
+
| `fineta` | Display estimated local time of completion based on the current progress and rate. | |
|
80
|
+
| `rate` | Display current rate of completion (steps per second). | |
|
81
|
+
| `average_rate` | Display average rate of completion over the last 30 seconds. | |
|
82
|
+
| `format` | Ignore all other display flags and use a custom format. See [_Formatting_ in `pv`'s manual](https://ivarch.com/programs/quickref/pv.shtml#formatting). | |
|
83
|
+
| `quiet` | No output. | |
|
84
|
+
| **Output modifiers** | | |
|
85
|
+
| `delay_start` | Don't show progress information until N seconds have passed. Useful if the task at hand could be so short that a progress bar is unnecesary. Only if the task takes more than N seconds will a progress bar be shown. | `0`. |
|
86
|
+
| `size` | Total amount of steps of the wrapped task. | `nil` (meaning unknown). |
|
87
|
+
| `interval` | Interval in seconds (decimals allowed) between updates of the display. | 1 second. |
|
88
|
+
| `width` | Width of the display in columns. | Width of the terminal (80 if it can't be determined). |
|
89
|
+
| `height` | Height of the display in rows. | Height of the terminal (25 if it can't be determined). |
|
90
|
+
| `name` | Title of the display (name of the process). | empty |
|
91
|
+
| `stats` | Show a summary at the end | `false` |
|
92
|
+
| **Data transfer modifiers** | | |
|
93
|
+
| `rate_limit` | Limit the maximum number of steps that can be completed per second (the call to `increment` blocks the thread for the necessary amount of time). | No limit. |
|
94
|
+
|
95
|
+
#### Multiple bars
|
96
|
+
|
97
|
+
You don't need to do anything special to have multiple bars progressing in parallel. See [examples/multibar.rb](examples/multibar.rb).
|
98
|
+
|
99
|
+
### Abbreviated API
|
100
|
+
|
101
|
+
Finally, for the most typical case in scripts (iterate over something and do something with it), Rpv
|
102
|
+
provides an optional abbreviated API. You'll need to require it explicitly, and it'll add an extra
|
103
|
+
method on `Enumerable` that will let you do something like:
|
104
|
+
|
105
|
+
```ruby
|
106
|
+
require "rpv/extensions"
|
107
|
+
|
108
|
+
big_list.with_rpv(<options>).each do |item|
|
109
|
+
do_something_with(item)
|
110
|
+
end
|
111
|
+
```
|
16
112
|
|
17
113
|
## Development
|
18
114
|
|
19
|
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run
|
115
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run
|
116
|
+
the tests. You can also run `bin/console` for an interactive prompt that will allow you to
|
117
|
+
experiment.
|
20
118
|
|
21
|
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new
|
119
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new
|
120
|
+
version, update the version number in `version.rb`, and then run `bundle exec rake release`, which
|
121
|
+
will create a git tag for the version, push git commits and the created tag, and push the `.gem`
|
122
|
+
file to [rubygems.org](https://rubygems.org).
|
22
123
|
|
23
124
|
## Contributing
|
24
125
|
|
data/Rakefile
CHANGED
@@ -8,3 +8,15 @@ RSpec::Core::RakeTask.new(:spec)
|
|
8
8
|
require "standard/rake"
|
9
9
|
|
10
10
|
task default: %i[spec standard]
|
11
|
+
|
12
|
+
desc "Run all the examples"
|
13
|
+
task :examples do
|
14
|
+
FileList["examples/*.rb"].each do |example|
|
15
|
+
ruby example
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Run the benchmark"
|
20
|
+
task :benchmark do
|
21
|
+
ruby "benchmark.rb"
|
22
|
+
end
|
data/benchmark.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Performance is in general not very important for this kind of package. It is used to track tasks
|
2
|
+
# that _are_ slow. Yet, I want to keep an eye on it being reasonable, using other progress gems as a
|
3
|
+
# baseline. It was also useful to identify a significant bottleneck in rpv doing something that is
|
4
|
+
# only needed when applying a rate limit (a feature other progress bars don't have), and to decide
|
5
|
+
# to only do that when a rate limit option is passed (see Rpv#initialize).
|
6
|
+
#
|
7
|
+
# This script produces a lot of output in stderr (the bars). You usually want to run it redirecting
|
8
|
+
# stderr to /dev/null (otherwise you're mainly testing your terminal's performance), unless of
|
9
|
+
# course, you're testing that.
|
10
|
+
|
11
|
+
require "benchmark/ips"
|
12
|
+
require "fortschritt"
|
13
|
+
require "ruby-progressbar"
|
14
|
+
require "rpv"
|
15
|
+
|
16
|
+
# monkey-patch fortschritt to output to stderr
|
17
|
+
class Fortschritt::Meter
|
18
|
+
def print!
|
19
|
+
Fortschritt.printer.print(self, $stderr)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
Benchmark.ips(warmup: 0.1, time: 2) do |x|
|
24
|
+
x.report "ruby-progressbar" do |times|
|
25
|
+
progressbar = ProgressBar.create(total: nil, output: $stderr)
|
26
|
+
times.times { progressbar.increment }
|
27
|
+
progressbar.finish
|
28
|
+
end
|
29
|
+
|
30
|
+
x.report "fortschritt" do |times|
|
31
|
+
Fortschritt.init(0)
|
32
|
+
times.times { Fortschritt.increment }
|
33
|
+
end
|
34
|
+
|
35
|
+
x.report "rpv" do |times|
|
36
|
+
Rpv.new do |rpv|
|
37
|
+
times.times { rpv.increment }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
x.report "rpv with rate limit" do |times|
|
42
|
+
Rpv.new(rate_limit: 10**10) do |rpv|
|
43
|
+
times.times { rpv.increment }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
x.compare!
|
48
|
+
end
|
data/lib/rpv/extensions.rb
CHANGED
@@ -1,21 +1,14 @@
|
|
1
1
|
require "rpv"
|
2
|
-
require "rpv/global"
|
3
2
|
|
4
3
|
module Enumerable
|
5
|
-
def with_rpv(
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
class Object
|
17
|
-
def rpv
|
18
|
-
Rpv::Global.increment
|
19
|
-
self
|
4
|
+
def with_rpv(options = {})
|
5
|
+
Enumerator.new do |e|
|
6
|
+
Rpv.new(size: size, **options) do |rpv|
|
7
|
+
each do |i|
|
8
|
+
e.yield i
|
9
|
+
rpv.increment
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
20
13
|
end
|
21
14
|
end
|
data/lib/rpv/options.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
class Rpv::Options
|
2
|
-
MAPPED_OPTIONS = %w[size name
|
3
|
-
BOOLEAN_MAPPED_OPTIONS = %w[
|
2
|
+
MAPPED_OPTIONS = %w[format delay_start size interval width height name rate_limit]
|
3
|
+
BOOLEAN_MAPPED_OPTIONS = %w[progress timer eta fineta rate average_rate quiet stats]
|
4
4
|
|
5
5
|
def self.parse(options)
|
6
6
|
options.transform_keys!(&:to_s)
|
7
|
-
args = %w[--si --line-mode --
|
7
|
+
args = %w[--si --line-mode --cursor]
|
8
8
|
MAPPED_OPTIONS.each do |option|
|
9
9
|
args << ["--#{option.tr("_", "-")}", options[option].to_s] if options[option]
|
10
10
|
end
|
data/lib/rpv/version.rb
CHANGED
data/lib/rpv.rb
CHANGED
@@ -1,17 +1,37 @@
|
|
1
1
|
require "rpv/options"
|
2
|
+
require "open3"
|
2
3
|
|
3
4
|
class Rpv
|
4
5
|
def initialize(options = {})
|
5
|
-
|
6
|
+
if options.key?(:rate_limit)
|
7
|
+
# This also works with rate limit, but brings a performance penalty so we only use it if
|
8
|
+
# necessary. Otherwise we fallback to a simpler mechanism (IO.popen and --discard).
|
9
|
+
@pv, @out, @thread = Open3.popen2("pv", *Options.parse(options).to_a)
|
10
|
+
else
|
11
|
+
@pv = IO.popen(["pv", "--discard"] + Options.parse(options).to_a, "w+")
|
12
|
+
end
|
13
|
+
|
14
|
+
if block_given?
|
15
|
+
yield self
|
16
|
+
finish
|
17
|
+
end
|
6
18
|
end
|
7
19
|
|
8
|
-
def increment
|
9
|
-
|
10
|
-
|
20
|
+
def increment(amount = 1)
|
21
|
+
amount.times do
|
22
|
+
@pv.puts
|
23
|
+
@pv.flush
|
24
|
+
@out&.gets
|
25
|
+
end
|
11
26
|
end
|
12
27
|
|
13
28
|
def finish
|
14
29
|
@pv.flush
|
15
30
|
@pv.close
|
31
|
+
@thread&.join
|
32
|
+
end
|
33
|
+
|
34
|
+
def finished?
|
35
|
+
@pv.closed?
|
16
36
|
end
|
17
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rpv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sergio Gil
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-18 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -23,9 +23,9 @@ files:
|
|
23
23
|
- LICENSE.txt
|
24
24
|
- README.md
|
25
25
|
- Rakefile
|
26
|
+
- benchmark.rb
|
26
27
|
- lib/rpv.rb
|
27
28
|
- lib/rpv/extensions.rb
|
28
|
-
- lib/rpv/global.rb
|
29
29
|
- lib/rpv/options.rb
|
30
30
|
- lib/rpv/version.rb
|
31
31
|
- sig/rpv.rbs
|