philiprehberger-progress 0.4.0 → 0.5.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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +62 -3
- data/lib/philiprehberger/progress/bar.rb +62 -4
- data/lib/philiprehberger/progress/version.rb +1 -1
- data/lib/philiprehberger/progress.rb +16 -2
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8cd9b24ec4af77caa0242168972123e46f8aefe0aa7d010f355f634462d4e7ad
|
|
4
|
+
data.tar.gz: 956912f23898fd45c2434b06030aea103af6d33f390f11fc432a7cf285983325
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 79fcad8d626d2869ac6c3bfa9d29ec243c134f7c140dfca896282c940bb82b3879d25378b229162441708d13fc204c6e912c5f802fef0b9331fc4bd9bb845889
|
|
7
|
+
data.tar.gz: d0074a78f1adfa22c1c749bf6367c468dfdfb1fa011d56ab88b83faedcc86625ada2f5982430cdc2f69013c66ead9bd030058d0b538959b3778cbfc94c86cb9c
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.5.0] - 2026-04-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- `Bar#pause` and `Bar#resume` to freeze and unfreeze elapsed time calculation
|
|
14
|
+
- `Bar#to_h` returns a hash with `:percentage`, `:elapsed`, `:eta`, `:throughput`, `:current`, `:total`
|
|
15
|
+
- Custom bar characters via `fill:`, `empty:`, `tip:` keyword arguments (defaults: `fill: '='`, `empty: ' '`, `tip: '>'`)
|
|
16
|
+
- `Progress.json_mode!` and `Progress.text_mode!` to toggle JSON line output for bar rendering
|
|
17
|
+
|
|
10
18
|
## [0.4.0] - 2026-04-09
|
|
11
19
|
|
|
12
20
|
### Added
|
data/README.md
CHANGED
|
@@ -81,6 +81,58 @@ end
|
|
|
81
81
|
|
|
82
82
|
The thread is joined automatically when `stop` is called (or when the block completes).
|
|
83
83
|
|
|
84
|
+
### Pause and Resume
|
|
85
|
+
|
|
86
|
+
Pause the progress bar to freeze elapsed time calculation (e.g. while waiting for user input):
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
bar = Philiprehberger::Progress::Bar.new(total: 100)
|
|
90
|
+
50.times { bar.advance }
|
|
91
|
+
bar.pause
|
|
92
|
+
# ... elapsed time is frozen ...
|
|
93
|
+
bar.resume
|
|
94
|
+
50.times { bar.advance }
|
|
95
|
+
bar.finish
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Custom Bar Characters
|
|
99
|
+
|
|
100
|
+
Customize the fill, empty, and tip characters:
|
|
101
|
+
|
|
102
|
+
```ruby
|
|
103
|
+
bar = Philiprehberger::Progress::Bar.new(total: 100, fill: '#', empty: '.', tip: '>')
|
|
104
|
+
50.times { bar.advance }
|
|
105
|
+
bar.to_s
|
|
106
|
+
# [########################>.........................] 50.0% | 50/100 | ETA: 0s | 50.0/s
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Default characters are `fill: '='`, `empty: ' '`, `tip: '>'`.
|
|
110
|
+
|
|
111
|
+
### Data Export
|
|
112
|
+
|
|
113
|
+
Export the current state as a hash:
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
bar = Philiprehberger::Progress::Bar.new(total: 100)
|
|
117
|
+
50.times { bar.advance }
|
|
118
|
+
bar.to_h
|
|
119
|
+
# => { percentage: 50.0, elapsed: 1.2, eta: 1.2, throughput: 41.7, current: 50, total: 100 }
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### JSON Mode
|
|
123
|
+
|
|
124
|
+
Switch to JSON line output for machine-readable progress:
|
|
125
|
+
|
|
126
|
+
```ruby
|
|
127
|
+
Philiprehberger::Progress.json_mode!
|
|
128
|
+
bar = Philiprehberger::Progress::Bar.new(total: 100)
|
|
129
|
+
50.times { bar.advance }
|
|
130
|
+
bar.to_s
|
|
131
|
+
# {"percentage":50.0,"elapsed":1.2,"eta":1.2,"throughput":41.7,"current":50,"total":100}
|
|
132
|
+
|
|
133
|
+
Philiprehberger::Progress.text_mode! # revert to ANSI bar
|
|
134
|
+
```
|
|
135
|
+
|
|
84
136
|
### Enumerable Integration
|
|
85
137
|
|
|
86
138
|
```ruby
|
|
@@ -121,17 +173,21 @@ multi.finished? # => true
|
|
|
121
173
|
|
|
122
174
|
| Method | Description |
|
|
123
175
|
|--------|-------------|
|
|
124
|
-
| `.new(total:, width: 30, output: $stderr)` | Create a progress bar |
|
|
176
|
+
| `.new(total:, width: 30, output: $stderr, fill: '=', empty: ' ', tip: '>')` | Create a progress bar |
|
|
125
177
|
| `#advance(n = 1)` | Advance by `n` items |
|
|
126
178
|
| `#set(n)` | Set absolute progress position (clamped to 0..total) |
|
|
127
179
|
| `#reset` | Reset to 0, clear finished state, restart timer |
|
|
180
|
+
| `#pause` | Pause the bar, freezing elapsed time |
|
|
181
|
+
| `#resume` | Resume after pause |
|
|
182
|
+
| `#paused?` | Whether the bar is paused |
|
|
128
183
|
| `#finish` | Mark as complete |
|
|
129
184
|
| `#finished?` | Whether the bar is finished |
|
|
130
185
|
| `#percentage` | Current percentage (0.0 to 100.0) |
|
|
131
|
-
| `#elapsed` | Elapsed time in seconds |
|
|
186
|
+
| `#elapsed` | Elapsed time in seconds (excludes paused time) |
|
|
132
187
|
| `#eta` | Estimated time remaining in seconds |
|
|
133
188
|
| `#throughput` | Items per second |
|
|
134
|
-
| `#
|
|
189
|
+
| `#to_h` | Hash with `:percentage`, `:elapsed`, `:eta`, `:throughput`, `:current`, `:total` |
|
|
190
|
+
| `#to_s` | Render the bar as a string (or JSON line in json_mode) |
|
|
135
191
|
|
|
136
192
|
### `Philiprehberger::Progress::Spinner`
|
|
137
193
|
|
|
@@ -167,6 +223,9 @@ multi.finished? # => true
|
|
|
167
223
|
| `Progress.multi(output: $stderr, &block)` | Create multi-bar tracker |
|
|
168
224
|
| `Progress.each(enumerable, label: nil) { \|item\| }` | Iterate with progress |
|
|
169
225
|
| `Progress.map(enumerable, label: nil) { \|item\| }` | Transform with progress, returns results |
|
|
226
|
+
| `Progress.json_mode!` | Switch bar rendering to JSON line output |
|
|
227
|
+
| `Progress.text_mode!` | Switch bar rendering back to ANSI text |
|
|
228
|
+
| `Progress.json_mode?` | Whether JSON mode is active |
|
|
170
229
|
|
|
171
230
|
## Development
|
|
172
231
|
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'json'
|
|
4
|
+
|
|
3
5
|
module Philiprehberger
|
|
4
6
|
module Progress
|
|
5
7
|
class Bar
|
|
@@ -8,13 +10,19 @@ module Philiprehberger
|
|
|
8
10
|
|
|
9
11
|
attr_reader :current, :total
|
|
10
12
|
|
|
11
|
-
def initialize(total:, width: 30, output: $stderr)
|
|
13
|
+
def initialize(total:, width: 30, output: $stderr, fill: '=', empty: ' ', tip: '>')
|
|
12
14
|
@total = [total, 0].max
|
|
13
15
|
@width = width
|
|
14
16
|
@output = output
|
|
15
17
|
@current = 0
|
|
16
18
|
@start_time = now
|
|
17
19
|
@finished = false
|
|
20
|
+
@paused = false
|
|
21
|
+
@pause_elapsed = 0.0
|
|
22
|
+
@pause_start = nil
|
|
23
|
+
@fill = fill
|
|
24
|
+
@empty = empty
|
|
25
|
+
@tip = tip
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
def advance(n = 1)
|
|
@@ -43,10 +51,40 @@ module Philiprehberger
|
|
|
43
51
|
def reset
|
|
44
52
|
@current = 0
|
|
45
53
|
@finished = false
|
|
54
|
+
@paused = false
|
|
55
|
+
@pause_elapsed = 0.0
|
|
56
|
+
@pause_start = nil
|
|
46
57
|
@start_time = now
|
|
47
58
|
self
|
|
48
59
|
end
|
|
49
60
|
|
|
61
|
+
# Pause the progress bar, freezing elapsed time calculation.
|
|
62
|
+
#
|
|
63
|
+
# @return [self]
|
|
64
|
+
def pause
|
|
65
|
+
return self if @paused || @finished
|
|
66
|
+
|
|
67
|
+
@paused = true
|
|
68
|
+
@pause_start = now
|
|
69
|
+
self
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Resume after pause.
|
|
73
|
+
#
|
|
74
|
+
# @return [self]
|
|
75
|
+
def resume
|
|
76
|
+
return self unless @paused
|
|
77
|
+
|
|
78
|
+
@pause_elapsed += now - @pause_start
|
|
79
|
+
@pause_start = nil
|
|
80
|
+
@paused = false
|
|
81
|
+
self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def paused?
|
|
85
|
+
@paused
|
|
86
|
+
end
|
|
87
|
+
|
|
50
88
|
def finish
|
|
51
89
|
@current = @total
|
|
52
90
|
@finished = true
|
|
@@ -66,7 +104,9 @@ module Philiprehberger
|
|
|
66
104
|
end
|
|
67
105
|
|
|
68
106
|
def elapsed
|
|
69
|
-
now - @start_time
|
|
107
|
+
raw = now - @start_time - @pause_elapsed
|
|
108
|
+
raw -= (now - @pause_start) if @paused
|
|
109
|
+
raw
|
|
70
110
|
end
|
|
71
111
|
|
|
72
112
|
def eta
|
|
@@ -85,7 +125,20 @@ module Philiprehberger
|
|
|
85
125
|
@current.to_f / elapsed_time
|
|
86
126
|
end
|
|
87
127
|
|
|
128
|
+
def to_h
|
|
129
|
+
{
|
|
130
|
+
percentage: percentage,
|
|
131
|
+
elapsed: elapsed,
|
|
132
|
+
eta: eta,
|
|
133
|
+
throughput: throughput,
|
|
134
|
+
current: @current,
|
|
135
|
+
total: @total
|
|
136
|
+
}
|
|
137
|
+
end
|
|
138
|
+
|
|
88
139
|
def to_s
|
|
140
|
+
return to_h.to_json if Philiprehberger::Progress.json_mode?
|
|
141
|
+
|
|
89
142
|
bar_str = render_bar
|
|
90
143
|
pct = format('%<p>5.1f%%', p: percentage)
|
|
91
144
|
eta_str = format_eta(eta)
|
|
@@ -109,11 +162,16 @@ module Philiprehberger
|
|
|
109
162
|
end
|
|
110
163
|
|
|
111
164
|
def render_bar
|
|
112
|
-
return
|
|
165
|
+
return @fill * @width if @total.zero?
|
|
113
166
|
|
|
114
167
|
filled = (@current.to_f / @total * @width).round
|
|
115
168
|
empty = @width - filled
|
|
116
|
-
|
|
169
|
+
|
|
170
|
+
if filled.positive? && filled < @width
|
|
171
|
+
(@fill * (filled - 1)) + @tip + (@empty * empty)
|
|
172
|
+
else
|
|
173
|
+
(@fill * filled) + (@empty * empty)
|
|
174
|
+
end
|
|
117
175
|
end
|
|
118
176
|
|
|
119
177
|
def format_eta(seconds)
|
|
@@ -7,8 +7,22 @@ require_relative 'progress/multi'
|
|
|
7
7
|
|
|
8
8
|
module Philiprehberger
|
|
9
9
|
module Progress
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
@json_mode = false
|
|
11
|
+
|
|
12
|
+
def self.json_mode!
|
|
13
|
+
@json_mode = true
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def self.text_mode!
|
|
17
|
+
@json_mode = false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.json_mode?
|
|
21
|
+
@json_mode
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.bar(total:, width: 30, output: $stderr, fill: '=', empty: ' ', tip: '>')
|
|
25
|
+
progress_bar = Bar.new(total: total, width: width, output: output, fill: fill, empty: empty, tip: tip)
|
|
12
26
|
|
|
13
27
|
if block_given?
|
|
14
28
|
result = yield progress_bar
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: philiprehberger-progress
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Philip Rehberger
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-15 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: Display progress bars with percentage, ETA, and throughput, or spinners
|
|
14
14
|
for indeterminate tasks. Supports block-based usage, enumerable iteration with each/map,
|