philiprehberger-progress 0.1.0 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba10a34300c085657e70aed11c006694d2c0ea2dccba5e0ea82a6c04fce1c50f
4
- data.tar.gz: 78f0c3f6adb6c673b841dffb3e6743ac44042de833b8bf7e7bb1a75132e827a8
3
+ metadata.gz: d278dc09081dc277006eddb173fa17baf7016199c6bd87807ac00092c77ecece
4
+ data.tar.gz: 69933ba0ec72a9aeed28659e7547951d126f463b6b764200ba8e08e50af03b31
5
5
  SHA512:
6
- metadata.gz: 17a190189ef3f1fb0487ba312796067c4fc91599452698eb7cb390fc1c928e14f9c5dce0b81d3107dd3c56c2af1fcbd4336c949db896b7d680b74f71dd65ed61
7
- data.tar.gz: b7d8033d7265d4719a60b455b9635047ca0adbdf72eacb96445a7a92960a88608ac0375ebe3d2481075a1cc7bb65417db5869becbbf43882817728c3146b3a54
6
+ metadata.gz: 9f109ddf121b047b20fbd26388dc7bdd10f5b32f4845fe6a0474d7607171f248ae24b77c05270cd642793c5ef96f4407cdbb2b76637000aababc4432bab618b1
7
+ data.tar.gz: 956e6524daf79f6eacefb7237b4eb84e91b4cb4ed99dc2785b51bf65b1a168f24171704a677146aebf26d92eb4f6d118a55e8b2fe263171d67239bf25bf497f8
data/CHANGELOG.md CHANGED
@@ -2,18 +2,25 @@
2
2
 
3
3
  All notable changes to this gem will be documented in this file.
4
4
 
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this gem adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
- ## [0.1.0] - 2026-03-21
10
+ ## [0.1.2] - 2026-03-22
11
+
12
+ ### Fixed
13
+
14
+ - Fix CHANGELOG header wording
15
+ - Add bug_tracker_uri to gemspec
16
+
17
+ ## [0.1.0] - 2026-03-22
11
18
 
12
19
  ### Added
13
- - Initial release
14
- - `Bar` class with percentage, ETA, throughput, and customizable format
15
- - `Spinner` class with multiple frame sets (default, braille, dots)
16
- - `Multi` class for tracking multiple concurrent progress bars
17
- - Convenience methods `Progress.bar`, `Progress.spin`, `Progress.multi`
18
- - `Enumerable#each_with_progress` integration
20
+
21
+ - `Bar` class with percentage, ETA, throughput, and progress visualization
22
+ - `Spinner` class with braille frame animation
23
+ - `Progress.bar` convenience method with block support and auto-finish
24
+ - `Progress.spin` convenience method with block support
25
+ - `Progress.each` for iterating enumerables with progress display
19
26
  - TTY detection to auto-disable rendering in non-terminal environments
data/README.md CHANGED
@@ -1,10 +1,9 @@
1
1
  # philiprehberger-progress
2
2
 
3
- [![Tests](https://github.com/philiprehberger/rb-progress/actions/workflows/ci.yml/badge.svg)](https://github.com/philiprehberger/rb-progress/actions/workflows/ci.yml)
4
- [![Gem Version](https://badge.fury.io/rb/philiprehberger-progress.svg)](https://rubygems.org/gems/philiprehberger-progress)
5
- [![License](https://img.shields.io/github/license/philiprehberger/rb-progress)](LICENSE)
3
+ [![Gem Version](https://badge.fury.io/rb/philiprehberger-progress.svg)](https://badge.fury.io/rb/philiprehberger-progress)
4
+ [![CI](https://github.com/philiprehberger/rb-progress/actions/workflows/ci.yml/badge.svg)](https://github.com/philiprehberger/rb-progress/actions/workflows/ci.yml)
6
5
 
7
- Terminal progress bars and spinners with ETA calculation and throughput display
6
+ Terminal progress bars and spinners with ETA calculation and throughput display.
8
7
 
9
8
  ## Requirements
10
9
 
@@ -12,16 +11,14 @@ Terminal progress bars and spinners with ETA calculation and throughput display
12
11
 
13
12
  ## Installation
14
13
 
15
- Add to your Gemfile:
16
-
17
- ```ruby
18
- gem 'philiprehberger-progress'
14
+ ```sh
15
+ gem install philiprehberger-progress
19
16
  ```
20
17
 
21
- Or install directly:
18
+ Or add to your Gemfile:
22
19
 
23
- ```bash
24
- gem install philiprehberger-progress
20
+ ```ruby
21
+ gem 'philiprehberger-progress'
25
22
  ```
26
23
 
27
24
  ## Usage
@@ -31,110 +28,94 @@ gem install philiprehberger-progress
31
28
  ```ruby
32
29
  require 'philiprehberger/progress'
33
30
 
34
- Philiprehberger::Progress.bar(total: 100) do |bar|
35
- 100.times do
36
- sleep(0.01)
37
- bar.advance
38
- end
31
+ bar = Philiprehberger::Progress::Bar.new(total: 100)
32
+ 100.times do
33
+ sleep(0.01)
34
+ bar.advance
39
35
  end
36
+ bar.finish
37
+ # [████████████████████████████████] 100.0% | 100/100 | ETA: 0s | 100.0/s
40
38
  ```
41
39
 
42
- ### Custom Format
40
+ ### Block Usage
43
41
 
44
42
  ```ruby
45
- bar = Philiprehberger::Progress::Bar.new(
46
- total: 100,
47
- format: ':bar :percent | :current/:total | :rate items/s | ETA: :eta',
48
- width: 30
49
- )
50
- bar.advance(50)
51
- puts bar.to_s
43
+ Philiprehberger::Progress.bar(total: 100) do |bar|
44
+ 100.times { bar.advance }
45
+ end
46
+ # Auto-finishes when block completes
52
47
  ```
53
48
 
54
49
  ### Spinner
55
50
 
56
51
  ```ruby
57
- Philiprehberger::Progress.spin('Loading...') do |spinner|
58
- 10.times do
59
- sleep(0.1)
60
- spinner.spin
61
- end
52
+ spinner = Philiprehberger::Progress::Spinner.new(message: 'Loading...')
53
+ 10.times do
54
+ sleep(0.1)
55
+ spinner.spin
62
56
  end
57
+ spinner.stop('done')
63
58
  ```
64
59
 
65
- ### Enumerable Integration
60
+ ### Block Spinner
66
61
 
67
62
  ```ruby
68
- items = (1..100).to_a
69
- items.each_with_progress('Processing') do |item|
70
- sleep(0.01)
63
+ Philiprehberger::Progress.spin('Processing...') do |spinner|
64
+ 10.times { spinner.spin; sleep(0.1) }
71
65
  end
72
66
  ```
73
67
 
74
- ### Multi-Bar
68
+ ### Enumerable Integration
75
69
 
76
70
  ```ruby
77
- multi = Philiprehberger::Progress.multi
78
- bar1 = multi.bar('Downloads', total: 100)
79
- bar2 = multi.bar('Uploads', total: 50)
80
-
81
- bar1.advance(10)
82
- bar2.advance(5)
83
- multi.render
71
+ items = (1..100).to_a
72
+ Philiprehberger::Progress.each(items) do |item|
73
+ sleep(0.01)
74
+ end
84
75
  ```
85
76
 
86
77
  ## API
87
78
 
88
- ### `Philiprehberger::Progress`
89
-
90
- | Method | Description |
91
- |--------|-------------|
92
- | `.bar(total:, format:, width:)` | Create a progress bar (yields if block given) |
93
- | `.spin(message, frames:)` | Create a spinner (yields if block given) |
94
- | `.multi` | Create a multi-bar display |
95
-
96
79
  ### `Philiprehberger::Progress::Bar`
97
80
 
98
81
  | Method | Description |
99
82
  |--------|-------------|
100
- | `.new(total:, format:, width:)` | Create a progress bar |
101
- | `#advance(n)` | Advance by `n` items (default: 1) |
83
+ | `.new(total:, width: 30, output: $stderr)` | Create a progress bar |
84
+ | `#advance(n = 1)` | Advance by `n` items |
102
85
  | `#finish` | Mark as complete |
103
86
  | `#finished?` | Whether the bar is finished |
104
87
  | `#percentage` | Current percentage (0.0 to 100.0) |
105
88
  | `#elapsed` | Elapsed time in seconds |
106
89
  | `#eta` | Estimated time remaining in seconds |
107
- | `#rate` | Throughput in items per second |
90
+ | `#throughput` | Items per second |
108
91
  | `#to_s` | Render the bar as a string |
109
92
 
110
93
  ### `Philiprehberger::Progress::Spinner`
111
94
 
112
95
  | Method | Description |
113
96
  |--------|-------------|
114
- | `.new(message:, frames:)` | Create a spinner |
97
+ | `.new(message:, output: $stderr)` | Create a spinner |
115
98
  | `#spin` | Advance to the next frame |
116
- | `#done(message)` | Mark as done with optional message |
117
- | `#done?` | Whether the spinner is done |
118
- | `#to_s` | Render the current frame |
99
+ | `#stop(final_message = 'done')` | Stop with a message |
100
+ | `#stopped?` | Whether the spinner is stopped |
101
+ | `#to_s` | Render the current frame with message |
119
102
 
120
- ### `Philiprehberger::Progress::Multi`
103
+ ### Module Methods
121
104
 
122
105
  | Method | Description |
123
106
  |--------|-------------|
124
- | `.new` | Create a multi-bar display |
125
- | `#bar(label, total:)` | Add a new progress bar |
126
- | `#render` | Render all bars |
127
- | `#size` | Number of bars |
128
- | `#finished?` | Whether all bars are finished |
107
+ | `Progress.bar(total:, &block)` | Create bar, auto-finish after block |
108
+ | `Progress.spin(message, &block)` | Create spinner, auto-stop after block |
109
+ | `Progress.each(enumerable, label: nil) { \|item\| }` | Iterate with progress |
129
110
 
130
111
  ## Development
131
112
 
132
- ```bash
113
+ ```sh
133
114
  bundle install
134
- bundle exec rspec # Run tests
135
- bundle exec rubocop # Check code style
115
+ bundle exec rspec
116
+ bundle exec rubocop
136
117
  ```
137
118
 
138
119
  ## License
139
120
 
140
- MIT
121
+ MIT License. See [LICENSE](LICENSE) for details.
@@ -2,29 +2,14 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module Progress
5
- # A terminal progress bar with ETA and throughput display
6
- #
7
- # @example
8
- # bar = Bar.new(total: 100)
9
- # 100.times { bar.advance }
10
- # bar.finish
11
5
  class Bar
12
- DEFAULT_FORMAT = ':bar :percent | :current/:total | :rate items/s | ETA: :eta'
13
- DEFAULT_WIDTH = 30
14
6
  FILL_CHAR = "\u2588"
15
7
  EMPTY_CHAR = "\u2591"
16
8
 
17
9
  attr_reader :current, :total
18
10
 
19
- # Create a new progress bar
20
- #
21
- # @param total [Integer] total number of items
22
- # @param format [String] format string with placeholders
23
- # @param width [Integer] width of the bar portion in characters
24
- # @param output [IO] output stream (default: $stderr)
25
- def initialize(total:, format: DEFAULT_FORMAT, width: DEFAULT_WIDTH, output: $stderr)
11
+ def initialize(total:, width: 30, output: $stderr)
26
12
  @total = [total, 0].max
27
- @format = format
28
13
  @width = width
29
14
  @output = output
30
15
  @current = 0
@@ -32,87 +17,59 @@ module Philiprehberger
32
17
  @finished = false
33
18
  end
34
19
 
35
- # Advance the progress bar
36
- #
37
- # @param n [Integer] number of items to advance (default: 1)
38
- # @return [self]
39
20
  def advance(n = 1)
40
21
  return self if @finished
41
22
 
42
23
  @current = [@current + n, @total].min
43
- render if tty?
24
+ render_to_output
44
25
  self
45
26
  end
46
27
 
47
- # Mark the progress as complete
48
- #
49
- # @return [self]
50
28
  def finish
51
29
  @current = @total
52
30
  @finished = true
53
- render if tty?
31
+ render_to_output
54
32
  @output.write("\n") if tty?
55
33
  self
56
34
  end
57
35
 
58
- # Check if the progress is finished
59
- #
60
- # @return [Boolean]
61
36
  def finished?
62
37
  @finished
63
38
  end
64
39
 
65
- # Get the progress percentage
66
- #
67
- # @return [Float] percentage from 0.0 to 100.0
68
40
  def percentage
69
41
  return 100.0 if @total.zero?
70
42
 
71
43
  (@current.to_f / @total * 100).round(1)
72
44
  end
73
45
 
74
- # Get the elapsed time in seconds
75
- #
76
- # @return [Float]
77
46
  def elapsed
78
47
  now - @start_time
79
48
  end
80
49
 
81
- # Get the estimated time remaining in seconds
82
- #
83
- # @return [Float, nil] nil if no progress has been made
84
50
  def eta
85
51
  return 0.0 if @current >= @total
86
52
  return nil if @current.zero?
87
53
 
88
54
  elapsed_time = elapsed
89
- rate = @current.to_f / elapsed_time
90
- (@total - @current) / rate
55
+ items_per_sec = @current.to_f / elapsed_time
56
+ (@total - @current) / items_per_sec
91
57
  end
92
58
 
93
- # Get the throughput in items per second
94
- #
95
- # @return [Float]
96
- def rate
59
+ def throughput
97
60
  elapsed_time = elapsed
98
61
  return 0.0 if elapsed_time.zero?
99
62
 
100
63
  @current.to_f / elapsed_time
101
64
  end
102
65
 
103
- # Render the progress bar as a string
104
- #
105
- # @return [String]
106
66
  def to_s
107
- result = @format.dup
108
- result.gsub!(':bar', render_bar)
109
- result.gsub!(':percent', format('%<pct>5.1f%%', pct: percentage))
110
- result.gsub!(':current', @current.to_s)
111
- result.gsub!(':total', @total.to_s)
112
- result.gsub!(':rate', format('%<r>.1f', r: rate))
113
- result.gsub!(':eta', format_duration(eta))
114
- result.gsub!(':elapsed', format_duration(elapsed))
115
- result
67
+ bar_str = render_bar
68
+ pct = format('%<p>5.1f%%', p: percentage)
69
+ eta_str = format_eta(eta)
70
+ tput = format('%<t>.1f/s', t: throughput)
71
+
72
+ "[#{bar_str}] #{pct} | #{@current}/#{@total} | ETA: #{eta_str} | #{tput}"
116
73
  end
117
74
 
118
75
  private
@@ -125,8 +82,8 @@ module Philiprehberger
125
82
  @output.respond_to?(:tty?) && @output.tty?
126
83
  end
127
84
 
128
- def render
129
- @output.write("\r#{self}")
85
+ def render_to_output
86
+ @output.write("\r#{self}") if tty?
130
87
  end
131
88
 
132
89
  def render_bar
@@ -137,16 +94,18 @@ module Philiprehberger
137
94
  (FILL_CHAR * filled) + (EMPTY_CHAR * empty)
138
95
  end
139
96
 
140
- def format_duration(seconds)
141
- return '--:--' if seconds.nil? || seconds.negative?
97
+ def format_eta(seconds)
98
+ return '--:--' if seconds.nil?
99
+
100
+ secs = seconds.to_i
101
+ return '0s' if secs <= 0
142
102
 
143
- seconds = seconds.to_i
144
- if seconds < 60
145
- format('0:%02d', seconds)
146
- elsif seconds < 3600
147
- format('%d:%02d', seconds / 60, seconds % 60)
103
+ if secs < 60
104
+ "#{secs}s"
105
+ elsif secs < 3600
106
+ format('%dm%02ds', secs / 60, secs % 60)
148
107
  else
149
- format('%d:%02d:%02d', seconds / 3600, (seconds % 3600) / 60, seconds % 60)
108
+ format('%dh%02dm%02ds', secs / 3600, (secs % 3600) / 60, secs % 60)
150
109
  end
151
110
  end
152
111
  end
@@ -1,70 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module Philiprehberger
4
- module Progress
5
- # Multi-bar progress display for tracking multiple concurrent tasks
6
- #
7
- # @example
8
- # multi = Multi.new
9
- # bar1 = multi.bar('Downloads', total: 100)
10
- # bar2 = multi.bar('Uploads', total: 50)
11
- class Multi
12
- # Create a new multi-bar display
13
- #
14
- # @param output [IO] output stream (default: $stderr)
15
- def initialize(output: $stderr)
16
- @output = output
17
- @bars = []
18
- end
19
-
20
- # Add a new progress bar
21
- #
22
- # @param label [String] label for the bar
23
- # @param total [Integer] total items
24
- # @param format [String] format string
25
- # @param width [Integer] bar width
26
- # @return [Bar]
27
- def bar(label, total:, format: nil, width: 20)
28
- bar_format = format || ":bar :percent | #{label}"
29
- progress_bar = Bar.new(total: total, format: bar_format, width: width, output: StringIO.new)
30
- @bars << { label: label, bar: progress_bar }
31
- progress_bar
32
- end
33
-
34
- # Render all bars
35
- #
36
- # @return [self]
37
- def render
38
- return self unless tty?
39
-
40
- # Move cursor up to overwrite previous render
41
- @output.write("\e[#{@bars.length}A") if @rendered_once
42
- @bars.each do |entry|
43
- @output.write("\r\e[2K#{entry[:bar]}\n")
44
- end
45
- @rendered_once = true
46
- self
47
- end
48
-
49
- # Number of bars being tracked
50
- #
51
- # @return [Integer]
52
- def size
53
- @bars.length
54
- end
55
-
56
- # Check if all bars are finished
57
- #
58
- # @return [Boolean]
59
- def finished?
60
- @bars.all? { |entry| entry[:bar].finished? }
61
- end
62
-
63
- private
64
-
65
- def tty?
66
- @output.respond_to?(:tty?) && @output.tty?
67
- end
68
- end
69
- end
70
- end
3
+ # This file is kept for backward compatibility but is no longer actively used.
@@ -2,73 +2,43 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module Progress
5
- # A terminal spinner for indeterminate progress
6
- #
7
- # @example
8
- # spinner = Spinner.new(message: 'Loading...')
9
- # spinner.spin
10
- # spinner.done
11
5
  class Spinner
12
- DEFAULT_FRAMES = %w[| / - \\].freeze
13
- BRAILLE_FRAMES = %W[\u2807 \u2816 \u2830 \u2821 \u280B \u2819 \u2838 \u2824].freeze
14
- DOTS_FRAMES = %W[\u2800 \u2801 \u2803 \u2807 \u280F \u281F \u283F \u287F \u28FF].freeze
6
+ FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807",
7
+ "\u280F"].freeze
15
8
 
16
- FRAME_SETS = {
17
- default: DEFAULT_FRAMES,
18
- braille: BRAILLE_FRAMES,
19
- dots: DOTS_FRAMES
20
- }.freeze
9
+ attr_reader :message
21
10
 
22
- # Create a new spinner
23
- #
24
- # @param message [String] message to display next to the spinner
25
- # @param frames [Symbol, Array<String>] frame set name or custom frames
26
- # @param output [IO] output stream (default: $stderr)
27
- def initialize(message: '', frames: :default, output: $stderr)
11
+ def initialize(message:, output: $stderr)
28
12
  @message = message
29
- @frames = frames.is_a?(Symbol) ? FRAME_SETS.fetch(frames, DEFAULT_FRAMES) : frames
30
13
  @output = output
31
14
  @index = 0
32
- @done = false
15
+ @stopped = false
33
16
  end
34
17
 
35
- # Advance the spinner by one frame
36
- #
37
- # @return [self]
38
18
  def spin
39
- return self if @done
19
+ return self if @stopped
40
20
 
41
- render if tty?
42
- @index = (@index + 1) % @frames.length
21
+ render_to_output
22
+ @index = (@index + 1) % FRAMES.length
43
23
  self
44
24
  end
45
25
 
46
- # Mark the spinner as done
47
- #
48
- # @param message [String] optional completion message
49
- # @return [self]
50
- def done(message = nil)
51
- @done = true
52
- if tty?
53
- clear_line
54
- @output.write("#{message || @message}\n") if message || !@message.empty?
55
- end
26
+ def stop(final_message = 'done')
27
+ @stopped = true
28
+ @output.write("\r\e[2K#{final_message}\n") if tty?
56
29
  self
57
30
  end
58
31
 
59
- # Check if the spinner is done
60
- #
61
- # @return [Boolean]
62
- def done?
63
- @done
32
+ def stopped?
33
+ @stopped
34
+ end
35
+
36
+ def current_frame
37
+ FRAMES[@index % FRAMES.length]
64
38
  end
65
39
 
66
- # Return the current frame
67
- #
68
- # @return [String]
69
40
  def to_s
70
- frame = @frames[@index % @frames.length]
71
- @message.empty? ? frame : "#{frame} #{@message}"
41
+ "#{current_frame} #{@message}"
72
42
  end
73
43
 
74
44
  private
@@ -77,12 +47,8 @@ module Philiprehberger
77
47
  @output.respond_to?(:tty?) && @output.tty?
78
48
  end
79
49
 
80
- def render
81
- @output.write("\r#{self}")
82
- end
83
-
84
- def clear_line
85
- @output.write("\r\e[2K")
50
+ def render_to_output
51
+ @output.write("\r#{self}") if tty?
86
52
  end
87
53
  end
88
54
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Philiprehberger
4
4
  module Progress
5
- VERSION = '0.1.0'
5
+ VERSION = '0.1.2'
6
6
  end
7
7
  end
@@ -1,27 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'stringio'
4
3
  require_relative 'progress/version'
5
4
  require_relative 'progress/bar'
6
5
  require_relative 'progress/spinner'
7
- require_relative 'progress/multi'
8
6
 
9
7
  module Philiprehberger
10
8
  module Progress
11
- class Error < StandardError; end
9
+ def self.bar(total:, width: 30, output: $stderr)
10
+ progress_bar = Bar.new(total: total, width: width, output: output)
12
11
 
13
- # Create and yield a progress bar
14
- #
15
- # @param total [Integer] total number of items
16
- # @param format [String] format string
17
- # @param width [Integer] bar width
18
- # @param output [IO] output stream
19
- # @yield [Bar] the progress bar
20
- # @return [Object] the block's return value
21
- def self.bar(total:, format: Bar::DEFAULT_FORMAT, width: Bar::DEFAULT_WIDTH, output: $stderr, &block)
22
- progress_bar = Bar.new(total: total, format: format, width: width, output: output)
23
-
24
- if block
12
+ if block_given?
25
13
  result = yield progress_bar
26
14
  progress_bar.finish unless progress_bar.finished?
27
15
  result
@@ -30,57 +18,29 @@ module Philiprehberger
30
18
  end
31
19
  end
32
20
 
33
- # Create and yield a spinner
34
- #
35
- # @param message [String] message to display
36
- # @param frames [Symbol, Array<String>] frame set
37
- # @param output [IO] output stream
38
- # @yield the work to perform
39
- # @return [Object] the block's return value
40
- def self.spin(message = 'Loading...', frames: :default, output: $stderr, &block)
41
- spinner = Spinner.new(message: message, frames: frames, output: output)
21
+ def self.spin(message, output: $stderr)
22
+ spinner = Spinner.new(message: message, output: output)
42
23
 
43
- if block
24
+ if block_given?
44
25
  result = yield spinner
45
- spinner.done unless spinner.done?
26
+ spinner.stop unless spinner.stopped?
46
27
  result
47
28
  else
48
29
  spinner
49
30
  end
50
31
  end
51
32
 
52
- # Create a multi-bar display
53
- #
54
- # @param output [IO] output stream
55
- # @return [Multi]
56
- def self.multi(output: $stderr)
57
- Multi.new(output: output)
58
- end
59
- end
60
- end
33
+ def self.each(enumerable, label: nil, output: $stderr)
34
+ items = enumerable.to_a
35
+ bar = Bar.new(total: items.length, output: output)
61
36
 
62
- # Enumerable integration
63
- module Enumerable
64
- # Iterate with a progress bar
65
- #
66
- # @param message [String] label for the progress bar
67
- # @param output [IO] output stream
68
- # @yield [Object] each element
69
- # @return [Array]
70
- def each_with_progress(message = 'Processing', output: $stderr)
71
- items = to_a
72
- bar = Philiprehberger::Progress::Bar.new(
73
- total: items.length,
74
- format: ":bar :percent | #{message} | :current/:total",
75
- output: output
76
- )
37
+ items.each do |item|
38
+ yield item
39
+ bar.advance
40
+ end
77
41
 
78
- items.each do |item|
79
- yield item
80
- bar.advance
42
+ bar.finish
43
+ items
81
44
  end
82
-
83
- bar.finish
84
- items
85
45
  end
86
46
  end
metadata CHANGED
@@ -1,20 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: philiprehberger-progress
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
- - Philip Rehberger
7
+ - philiprehberger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2026-03-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Display progress bars with percentage, ETA, and throughput, or spinners
14
- for indeterminate tasks. Supports multi-bar display, Enumerable integration, and
15
- auto-disables when not connected to a terminal.
14
+ for indeterminate tasks. Supports block-based usage, enumerable iteration, and auto-disables
15
+ rendering when not connected to a terminal.
16
16
  email:
17
- - me@philiprehberger.com
17
+ - philiprehberger@users.noreply.github.com
18
18
  executables: []
19
19
  extensions: []
20
20
  extra_rdoc_files: []
@@ -44,7 +44,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 3.1.0
47
+ version: '3.1'
48
48
  required_rubygems_version: !ruby/object:Gem::Requirement
49
49
  requirements:
50
50
  - - ">="