ruby-progress 1.3.1 → 1.3.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: 7f08082d9cebd17f7d3ece436ff76e4f4beb8f934d803719a6bdc3477fa8c97b
4
- data.tar.gz: da85e2d2e2587c13f4c778094fb1dcd8e2aa832dd0cff34b947b90db0f4e6585
3
+ metadata.gz: 5c5a7ddc53059cb7f6d2b7bd1c066653058e1dbb281f4c23aa04229ce360a594
4
+ data.tar.gz: 0446a713142b93f16b9fe3e102c8a3c0db3194db17da25de7f1f7f31e5090907
5
5
  SHA512:
6
- metadata.gz: f3a816024fd6cc2aba00edd334c8b82e3783d6be3916bc36238172add46c695febcd80689ba49179b0d48a2175f983dca6b381e482c143e72f2bb0d80804b247
7
- data.tar.gz: 56fe19077105ebf00cdae2c939eb761d0b37ae4f4cb82b439207c0562ed46cd97abd9105e7b6c0789868fa6087f5d646736b3ad0a58d3df6d09e5028add6d4bf
6
+ metadata.gz: 3cda8e32c95b8bd03d6c8549de1b3f4fc488f868cb028a554ddc44654428978bfd1db4178a1cb0a0a71c9a0c8ea46a1cc8da844c4026ef9b84ed45c1b43f4691
7
+ data.tar.gz: 39c31e85f87ea2201cbf3267fefedff1f4946f6bef9b1ee6178b8e1b5ecf8569a8391c20519582a1077bd6d352d229b01997ceedb358eeb049cf484c895028ed
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2025-10-09 14:47:16 UTC using RuboCop version 1.75.7.
3
+ # on 2025-10-13 12:49:46 UTC using RuboCop version 1.75.7.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -22,11 +22,10 @@ Layout/TrailingEmptyLines:
22
22
  Exclude:
23
23
  - 'test_worm_flags.rb'
24
24
 
25
- # Offense count: 4
25
+ # Offense count: 2
26
26
  # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
27
27
  Lint/DuplicateBranch:
28
28
  Exclude:
29
- - 'bin/prg'
30
29
  - 'lib/ruby-progress/utils.rb'
31
30
  - 'lib/ruby-progress/worm.rb'
32
31
 
@@ -36,6 +35,12 @@ Lint/EmptyBlock:
36
35
  Exclude:
37
36
  - 'spec/worm_integration_spec.rb'
38
37
 
38
+ # Offense count: 1
39
+ # Configuration parameters: MaximumRangeSize.
40
+ Lint/MissingCopEnableDirective:
41
+ Exclude:
42
+ - 'lib/ruby-progress/fill_cli.rb'
43
+
39
44
  # Offense count: 2
40
45
  # This cop supports safe autocorrection (--autocorrect).
41
46
  Lint/ScriptPermission:
@@ -43,63 +48,49 @@ Lint/ScriptPermission:
43
48
  - 'demo_gem.rb'
44
49
  - 'demo_worm_infinite.rb'
45
50
 
46
- # Offense count: 1
47
- Lint/SelfAssignment:
48
- Exclude:
49
- - 'lib/ruby-progress/ripple.rb'
50
-
51
- # Offense count: 1
52
- # This cop supports safe autocorrection (--autocorrect).
53
- # Configuration parameters: AutoCorrect, AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
54
- # NotImplementedExceptions: NotImplementedError
55
- Lint/UnusedMethodArgument:
56
- Exclude:
57
- - 'lib/ruby-progress/worm.rb'
58
-
59
- # Offense count: 23
51
+ # Offense count: 22
60
52
  # This cop supports safe autocorrection (--autocorrect).
61
53
  # Configuration parameters: AutoCorrect.
62
54
  Lint/UselessAssignment:
63
55
  Exclude:
64
56
  - 'demo_gem.rb'
65
- - 'lib/ruby-progress/worm.rb'
66
57
  - 'spec/cli_integration_spec.rb'
67
58
 
68
- # Offense count: 20
59
+ # Offense count: 52
69
60
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
70
61
  Metrics/AbcSize:
71
- Max: 114
62
+ Max: 122
72
63
 
73
- # Offense count: 17
64
+ # Offense count: 49
74
65
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
75
66
  # AllowedMethods: refine
76
67
  Metrics/BlockLength:
77
- Max: 109
68
+ Max: 111
78
69
 
79
- # Offense count: 2
70
+ # Offense count: 4
80
71
  # Configuration parameters: CountComments, CountAsOne.
81
72
  Metrics/ClassLength:
82
- Max: 254
73
+ Max: 268
83
74
 
84
- # Offense count: 12
75
+ # Offense count: 30
85
76
  # Configuration parameters: AllowedMethods, AllowedPatterns.
86
77
  Metrics/CyclomaticComplexity:
87
- Max: 19
78
+ Max: 26
88
79
 
89
- # Offense count: 31
80
+ # Offense count: 68
90
81
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
91
82
  Metrics/MethodLength:
92
- Max: 131
83
+ Max: 156
93
84
 
94
- # Offense count: 3
85
+ # Offense count: 9
95
86
  # Configuration parameters: CountComments, CountAsOne.
96
87
  Metrics/ModuleLength:
97
- Max: 206
88
+ Max: 285
98
89
 
99
- # Offense count: 10
90
+ # Offense count: 31
100
91
  # Configuration parameters: AllowedMethods, AllowedPatterns.
101
92
  Metrics/PerceivedComplexity:
102
- Max: 20
93
+ Max: 27
103
94
 
104
95
  # Offense count: 1
105
96
  # Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, CheckDefinitionPathHierarchyRoots, Regex, IgnoreExecutableScripts, AllowedAcronyms.
@@ -110,7 +101,7 @@ Naming/FileName:
110
101
  - 'Rakefile.rb'
111
102
  - 'lib/ruby-progress.rb'
112
103
 
113
- # Offense count: 17
104
+ # Offense count: 10
114
105
  # Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
115
106
  # SupportedStyles: snake_case, normalcase, non_integer
116
107
  # AllowedIdentifiers: TLS1_1, TLS1_2, capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64
@@ -127,15 +118,6 @@ Style/Documentation:
127
118
  - 'lib/ruby-progress.rb'
128
119
  - 'lib/ruby-progress/daemon.rb'
129
120
 
130
- # Offense count: 4
131
- # This cop supports unsafe autocorrection (--autocorrect-all).
132
- # Configuration parameters: EnforcedStyle.
133
- # SupportedStyles: allowed_in_returns, forbidden
134
- Style/DoubleNegation:
135
- Exclude:
136
- - 'bin/prg'
137
- - 'lib/ruby-progress/worm.rb'
138
-
139
121
  # Offense count: 1
140
122
  # This cop supports safe autocorrection (--autocorrect).
141
123
  # Configuration parameters: AutoCorrect, EnforcedStyle, AllowComments.
@@ -167,14 +149,13 @@ Style/InfiniteLoop:
167
149
  Exclude:
168
150
  - 'lib/ruby-progress/ripple.rb'
169
151
 
170
- # Offense count: 2
152
+ # Offense count: 1
171
153
  # This cop supports unsafe autocorrection (--autocorrect-all).
172
154
  # Configuration parameters: EnforcedStyle, AllowedMethods, AllowedPatterns.
173
155
  # SupportedStyles: predicate, comparison
174
156
  Style/NumericPredicate:
175
157
  Exclude:
176
158
  - 'spec/**/*'
177
- - 'bin/prg'
178
159
  - 'lib/ruby-progress/ripple.rb'
179
160
 
180
161
  # Offense count: 1
@@ -193,7 +174,7 @@ Style/StringLiterals:
193
174
  Exclude:
194
175
  - 'test_worm_flags.rb'
195
176
 
196
- # Offense count: 3
177
+ # Offense count: 39
197
178
  # This cop supports safe autocorrection (--autocorrect).
198
179
  # Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
199
180
  # URISchemes: http, https
data/CHANGELOG.md CHANGED
@@ -27,7 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
27
27
 
28
28
  - Merge commit: 99d9c39 (squash-merge of feature/output-handling)
29
29
 
30
- ## 1.3.1 - 2025-10-12
30
+ ## 1.3.2 - 2025-10-13
31
31
 
32
32
  ### Added
33
33
 
@@ -35,6 +35,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
35
35
 
36
36
  ### Changed
37
37
 
38
+ - Added `--stop-id NAME` shorthand for targeting named daemons (implies `--stop` and normalizes the name to the canonical PID filename). This is a small convenience used by the demo and scripts.
39
+ - Demo: updated `demo_screencast.rb` to call the local `bin/prg` when stopping the demo daemon to avoid conflicts with system-installed versions.
40
+
41
+ ### Changed
42
+
38
43
  - Bumped `FILL_VERSION` (patch) to reflect the new CLI behavior.
39
44
 
40
45
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-progress (1.3.1)
4
+ ruby-progress (1.3.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -98,6 +98,39 @@ echo "bundle exec rake db:migrate" | prg job send --stdin --daemon-name mytask
98
98
  prg job send --daemon-name mytask --command "./deploy-step.sh" --wait --timeout 30
99
99
  ```
100
100
 
101
+ You can also send control/action jobs (no shell command) to a running daemon. These are JSON payloads with an `action` key handled by the daemon's job processor. The helper supports a few common actions:
102
+
103
+ ```bash
104
+ # Send a simple 'advance' action (no value)
105
+ prg job send --daemon-name demo --advance
106
+
107
+ # Send a 'percent' action with a numeric value
108
+ prg job send --daemon-name demo --percent 42
109
+
110
+ # Example using `fill` as a named daemon and sending percent updates
111
+ ```bash
112
+ # Start a named fill worker (non-detaching so animation remains visible)
113
+ prg fill --daemon-as demo --no-detach --output-lines 3 --output-position top
114
+
115
+ # Send percent updates to the named worker
116
+ prg job send --daemon-name demo --percent 10 --wait
117
+ prg job send --daemon-name demo --percent 50 --wait
118
+ prg job send --daemon-name demo --percent 100 --wait
119
+ ```
120
+
121
+ # Or use the generic action/value pair
122
+ prg job send --daemon-name demo --action percent --value 42
123
+ ```
124
+
125
+ Note about stopping named daemons:
126
+
127
+ You can target named daemons directly using the `--stop-id NAME` shorthand which implies `--stop` and targets the named daemon (it is normalized to the canonical daemon name used for the PID file). This is convenient for scripts and demos. Example:
128
+
129
+ ```bash
130
+ # Stop a named fill worker with a success message
131
+ prg fill --stop-id demo --stop-success 'Demo finished'
132
+ ```
133
+
101
134
  Behavior and file layout:
102
135
 
103
136
  - Jobs are written as JSON files into the daemon's job directory, which is derived from the daemon PID file. For example, a PID file `/tmp/ruby-progress/mytask.pid` maps to the job directory `/tmp/ruby-progress/mytask.jobs`.
@@ -139,6 +172,21 @@ This file is intended for short messages and small captured output snippets (the
139
172
  Below is an example script that demonstrates starting a worm daemon, sending a job, waiting for the result, and stopping the daemon.
140
173
  ---
141
174
 
175
+ If you want the background worker to continue writing to the same terminal (so you can visually watch the animation while your script continues), use the non-detaching background mode:
176
+
177
+ ```bash
178
+ # Start a named worm worker that backgrounds but does not fully detach
179
+ prg worm --daemon-as demo --no-detach
180
+
181
+ # In the same script or a subsequent command, enqueue a job to that worker
182
+ prg job send --daemon-name demo --command "echo hello; sleep 1; echo done" --wait
183
+
184
+ # Stop the worker with a success message
185
+ prg worm --stop-id demo --stop-success "Demo finished"
186
+ ```
187
+
188
+ Note: Non-detaching mode keeps the child process attached to the controlling TTY. That means both the worker and the invoking shell may write to the terminal and outputs can interleave.
189
+
142
190
  ## Ripple
143
191
 
144
192
  Ripple is a sophisticated text animation library that creates ripple effects across text strings in the terminal. It supports various animation modes including bidirectional movement, and rainbow colors.
data/Rakefile CHANGED
@@ -108,7 +108,6 @@ namespace :markdown do
108
108
  !!(line =~ /^\s*```|^\s*~~~/)
109
109
  end
110
110
 
111
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
112
111
  def format_markdown(content)
113
112
  lines = content.split("\n", -1)
114
113
  out = []
@@ -167,8 +166,6 @@ namespace :markdown do
167
166
  out << '' if (last = out.last) && !last.empty?
168
167
  out.join("\n")
169
168
  end
170
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
171
-
172
169
  desc 'Lint markdown (reports files that would be changed)'
173
170
  task :lint do
174
171
  changed = []
data/bin/prg CHANGED
@@ -148,6 +148,21 @@ module PrgCLI
148
148
  end
149
149
  end
150
150
 
151
+ # Spawn a background child but do NOT fully detach from the controlling
152
+ # terminal. This keeps the child attached to the same TTY so animations
153
+ # remain visible, while the parent exits immediately allowing the caller
154
+ # (shell or script) to continue. Use when the user requests a non-detaching
155
+ # background worker (e.g. `--daemon-as NAME --no-detach`).
156
+ def self.backgroundize
157
+ pid = fork
158
+ return unless pid
159
+
160
+ # parent: exit so the invoking shell/script continues
161
+ exit(0)
162
+
163
+ # child: continue without setsid/IO close so output remains on the TTY
164
+ end
165
+
151
166
  # Attempt to stop processes for the given subcommand. Return true if any
152
167
  # process was signaled/stopped; false otherwise. Keep quiet on missing
153
168
  # processes to satisfy integration tests.
data/demo_screencast.rb CHANGED
@@ -13,6 +13,8 @@
13
13
  # and clear visual separation of different features.
14
14
 
15
15
  require 'io/console'
16
+ require 'shellwords'
17
+ require 'tmpdir'
16
18
 
17
19
  # Demo runner that exercises the major features of the ruby-progress gem
18
20
  # used by the documentation and screencast recordings.
@@ -26,6 +28,11 @@ class ProgressDemo
26
28
  header: "\e[1;36m", # Bright cyan
27
29
  command: "\e[1;33m", # Bright yellow
28
30
  description: "\e[0;32m", # Green
31
+ exec: "\e[1;33m", # executable (bright yellow)
32
+ tool: "\e[1;35m", # prg/tool (bright magenta)
33
+ flag: "\e[1;36m", # flags (bright cyan)
34
+ value: "\e[1;37m", # flag values (bright white)
35
+ prompt: "\e[2m", # prompt (dim)
29
36
  reset: "\e[0m", # Reset
30
37
  dim: "\e[2m" # Dim
31
38
  }
@@ -33,12 +40,12 @@ class ProgressDemo
33
40
 
34
41
  def run
35
42
  clear_screen
36
- show_title
43
+ # show_title
37
44
 
38
45
  # Introduction
39
- show_section_header('Ruby Progress Gem Demo')
40
- show_description('Demonstrating terminal progress indicators with style!')
41
- pause_for_narration(3)
46
+ # show_section_header('Ruby Progress Gem Demo')
47
+ # show_description('Demonstrating terminal progress indicators with style!')
48
+ # pause_for_narration(3)
42
49
 
43
50
  # Basic examples for each command
44
51
  demo_basic_commands
@@ -63,12 +70,12 @@ class ProgressDemo
63
70
 
64
71
  # Ripple - basic expanding circle animation
65
72
  show_demo_header('Ripple', 'Expanding circle animation for tasks with unknown duration')
66
- run_command("#{ruby_cmd} ripple --command 'sleep 4' --success 'Download complete!' --checkmark")
73
+ run_command("#{ruby_cmd} ripple --command 'sleep 4' --success 'Download complete!' --checkmark PROCESSING")
67
74
  pause_between_demos
68
75
 
69
76
  # Worm - progress bar animation
70
77
  show_demo_header('Worm', 'Animated progress bar for visual feedback')
71
- run_command("#{ruby_cmd} worm --length 10 --command 'sleep 5' --success 'Processing finished!' --checkmark")
78
+ run_command("#{ruby_cmd} worm --length 10 --command 'sleep 5' --success 'Processing finished!' --checkmark --message 'Loading'")
72
79
  pause_between_demos
73
80
 
74
81
  # Twirl - spinning indicator
@@ -83,31 +90,27 @@ class ProgressDemo
83
90
  # Ripple styles
84
91
  show_demo_header('Ripple Styles', 'Different visual patterns')
85
92
  show_command_info('Default ripple style')
86
- run_command("#{ruby_cmd} ripple --command 'sleep 3' --success 'Default style'")
93
+ run_command("#{ruby_cmd} ripple --command 'sleep 3' --success 'Default style' 'Rippling Progress Default Style'")
87
94
  pause_between_demos(2)
88
95
 
89
96
  show_command_info('Pulse style')
90
- run_command("#{ruby_cmd} ripple --style pulse --command 'sleep 3' --success 'Pulse style'")
97
+ run_command("#{ruby_cmd} ripple --style pulse --command 'sleep 3' --success 'Pulse style' 'Rippling Progress'")
91
98
  pause_between_demos
92
99
 
93
100
  # Worm styles
94
101
  show_demo_header('Worm Styles', 'Various progress bar animations')
95
102
  show_command_info('Classic worm style')
96
- run_command("#{ruby_cmd} worm --length 10 --style classic --command 'sleep 4' --success 'Classic worm'")
97
- pause_between_demos(2)
98
-
99
- show_command_info('Emoji worm style')
100
- run_command("#{ruby_cmd} worm --length 10 --style emoji --command 'sleep 4' --success 'Emoji worm! 🎉'")
103
+ run_command("#{ruby_cmd} worm --length 10 --style classic --command 'sleep 4' --success 'Classic worm' --message 'Classic'")
101
104
  pause_between_demos(2)
102
105
 
103
106
  show_command_info('Blocks worm style')
104
- run_command("#{ruby_cmd} worm --length 10 --style blocks --command 'sleep 4' --success 'Block worm'")
107
+ run_command("#{ruby_cmd} worm --length 10 --style blocks --command 'sleep 4' --success 'Block worm' --message 'Blocks'")
105
108
  pause_between_demos
106
109
 
107
110
  # Twirl styles
108
111
  show_demo_header('Twirl Styles', 'Different spinning patterns')
109
112
  show_command_info('Classic spinner')
110
- run_command("#{ruby_cmd} twirl --style classic --command 'sleep 3' --success 'Classic spin'")
113
+ run_command("#{ruby_cmd} twirl --style classic --command 'sleep 3' --success 'Classic spin' --message 'Loading'")
111
114
  pause_between_demos(2)
112
115
 
113
116
  show_command_info('Dots spinner')
@@ -115,7 +118,7 @@ class ProgressDemo
115
118
  pause_between_demos(2)
116
119
 
117
120
  show_command_info('Arrow spinner')
118
- run_command("#{ruby_cmd} twirl --style arrow --command 'sleep 3' --success 'Arrow spin'")
121
+ run_command("#{ruby_cmd} twirl --style arrow --command 'sleep 3' --success 'Arrow spin' --message 'Loading'")
119
122
  pause_between_demos
120
123
  end
121
124
 
@@ -125,17 +128,17 @@ class ProgressDemo
125
128
  # Error handling
126
129
  show_demo_header('Error Handling', 'Graceful failure with custom messages')
127
130
  show_command_info('Simulating a failed task')
128
- run_command("#{ruby_cmd} worm --length 10 --command 'sleep 2 && exit 1' --error 'Something went wrong!' --fail-icon")
131
+ run_command("#{ruby_cmd} worm --length 10 --command 'sleep 2 && exit 1' --error 'Something went wrong!' --checkmark")
129
132
  pause_between_demos
130
133
 
131
134
  # Custom colors (if supported)
132
135
  show_demo_header('Success Messages', 'Custom completion messages')
133
136
  show_command_info('Custom success message with checkmark')
134
- run_command("#{ruby_cmd} ripple --command 'sleep 3' --success 'Data synchronized successfully' --checkmark")
137
+ run_command("#{ruby_cmd} ripple --command 'sleep 3' --success 'Data synchronized successfully' --checkmark --message 'Syncing data...'")
135
138
  pause_between_demos(2)
136
139
 
137
140
  show_command_info('Different success icon')
138
- run_command("#{ruby_cmd} twirl --command 'sleep 3' --success 'Backup completed' --icon '✓'")
141
+ run_command("#{ruby_cmd} twirl --command 'sleep 3' --success 'Backup completed' --success-icon '✓' --checkmark")
139
142
  pause_between_demos
140
143
 
141
144
  # No completion message
@@ -151,7 +154,7 @@ class ProgressDemo
151
154
  # Universal --ends flag
152
155
  show_demo_header('Universal --ends Flag', 'Add decorative start/end characters')
153
156
  show_command_info("Ripple with square brackets: --ends '[]'")
154
- run_command("#{ruby_cmd} ripple --ends '[]' --command 'sleep 4' --success 'Framed ripple!'")
157
+ run_command("#{ruby_cmd} ripple --ends '[]' --command 'sleep 4' --success 'Framed ripple!' 'With a frame'")
155
158
  pause_between_demos(2)
156
159
 
157
160
  show_command_info("Worm with angle brackets: --ends '<<>>'")
@@ -194,11 +197,95 @@ class ProgressDemo
194
197
  part2 = "--ends '【】' --command 'sleep 5' --success 'Ultimate combo!' --checkmark"
195
198
  run_command(part1 + part2)
196
199
  pause_between_demos
200
+
201
+ # v1.3.x additions: output capture and job queue demo snippets
202
+ show_section_header('New in v1.3.x - Output Capture & Job Queue')
203
+
204
+ show_demo_header('Fill --command (output capture)', 'Run a command and reserve terminal rows for output while preserving animation')
205
+ show_command_info('Capture command stdout/stderr into reserved rows:')
206
+ part_a = "#{ruby_cmd} fill --command \"bash -lc 'for i in 1 2 3; do echo line:$i; sleep 1; done'\" "
207
+ part_b = "--output-lines 3 --output-position top --success 'Captured!' --checkmark"
208
+ run_command(part_a + part_b)
209
+ pause_between_demos
210
+
211
+ show_demo_header('prg job send (enqueue a job)', 'Send a job to a running daemon using the file-based job queue')
212
+ show_command_info('Example: create a job payload and atomically enqueue it for the daemon')
213
+ show_command_info('Use the bundled helper to enqueue control/action jobs:')
214
+ puts "#{@colors[:command]}$ prg job send --daemon-name demo --advance#{@colors[:reset]}"
215
+ puts "#{@colors[:command]}$ prg job send --daemon-name demo --percent 42#{@colors[:reset]}"
216
+ puts
217
+ show_command_info('Or enqueue a shell command:')
218
+
219
+ # For the demo we run the worker in the foreground so you can see the
220
+ # live animation and completion message inline. Daemon mode (started with
221
+ # `--daemon` or `--daemon-as`) detaches to the background and processes
222
+ # jobs via the file-based queue; `prg job send` targets a background
223
+ # daemon and prints the job result JSON, but won't show the daemon's
224
+ # animation in the foreground.
225
+ show_command_info('Start a named fill daemon that processes percent/action jobs')
226
+ # Start the fill daemon in non-detaching background mode so animation remains visible
227
+ run_command("#{ruby_cmd} fill --daemon-as demo --no-detach --output-lines 3 --output-position top --success 'Captured!' --checkmark")
228
+ pause_between_demos(1)
229
+
230
+ show_command_info('We will enqueue several percent actions via a small shell script')
231
+ demo_script = <<~BASH
232
+ #!/usr/bin/env bash
233
+ set -eu
234
+ echo "Sending percent updates to demo daemon (atomic mktemp+mv writes)"
235
+
236
+ job_dir="/tmp/ruby-progress/demo.jobs"
237
+ mkdir -p "$job_dir"
238
+
239
+ enqueue_percent() {
240
+ percent=$1
241
+ # Build JSON payload
242
+ id=$(uuidgen 2>/dev/null || echo "job-$(date +%s%N)")
243
+ tmp=$(mktemp "$job_dir/${id}.json.tmp.XXXXXX")
244
+ printf '%s\n' '{"id":"'"${id}"'","action":"percent","value":'"${percent}"'}' > "$tmp"
245
+ mv "$tmp" "$job_dir/${id}.json"
246
+
247
+ # Wait for the daemon to process the job (poll for .processing.result)
248
+ result_path="$job_dir/${id}.json.processing.result"
249
+ start=$(date +%s)
250
+ timeout=10
251
+ while [ ! -f "$result_path" ]; do
252
+ sleep 0.1
253
+ now=$(date +%s)
254
+ if [ $((now - start)) -gt $timeout ]; then
255
+ echo "Timed out waiting for result for job ${id}" >&2
256
+ return 2
257
+ fi
258
+ done
259
+ cat "$result_path"
260
+ }
261
+
262
+ enqueue_percent 10
263
+ sleep 1
264
+ enqueue_percent 40
265
+ sleep 1
266
+ enqueue_percent 70
267
+ sleep 1
268
+ enqueue_percent 100
269
+
270
+ # After updates, stop the daemon cleanly (call local bin/prg to avoid global conflicts)
271
+ #{ruby_cmd} fill --stop-id demo --stop-success 'Demo daemon stopped'
272
+ BASH
273
+
274
+ # Show the simulated script contents
275
+ puts "#{@colors[:command]}$ cat demo_percent_updates.sh#{@colors[:reset]}"
276
+ puts demo_script
277
+
278
+ # Write and execute the script (run in a subshell so output doesn't interleave too badly)
279
+ script_path = File.join(Dir.tmpdir, "demo_percent_updates_#{Time.now.to_i}.sh")
280
+ File.write(script_path, demo_script)
281
+ File.chmod(0o755, script_path)
282
+ run_command("bash #{Shellwords.escape(script_path)}")
283
+ pause_between_demos
197
284
  end
198
285
 
199
286
  def show_finale
200
287
  show_section_header('Demo Complete!')
201
- show_description('Ruby Progress Gem v1.2.0 - Making terminal progress beautiful! 🚀')
288
+ show_description('Ruby Progress Gem v1.3.2 - Making terminal progress beautiful! 🚀')
202
289
  puts
203
290
  show_description('Key features demonstrated:')
204
291
  puts "#{@colors[:description]} • Three animation types: ripple, worm, twirl#{@colors[:reset]}"
@@ -217,7 +304,8 @@ class ProgressDemo
217
304
  # Utility methods
218
305
 
219
306
  def ruby_cmd
220
- "ruby -I #{@lib_path} #{@gem_path}"
307
+ # "ruby -I #{@lib_path} #{@gem_path}"
308
+ 'bin/prg'
221
309
  end
222
310
 
223
311
  def clear_screen
@@ -228,7 +316,7 @@ class ProgressDemo
228
316
  puts
229
317
  puts "#{@colors[:header]}#{'=' * 60}#{@colors[:reset]}"
230
318
  puts "#{@colors[:header]} RUBY PROGRESS GEM - DEMO SCREENCAST#{@colors[:reset]}"
231
- puts "#{@colors[:header]} Version 1.2.0 Feature Demonstration#{@colors[:reset]}"
319
+ puts "#{@colors[:header]} Version 1.3.2 Feature Demonstration#{@colors[:reset]}"
232
320
  puts "#{@colors[:header]}#{'=' * 60}#{@colors[:reset]}"
233
321
  puts
234
322
  end
@@ -257,19 +345,75 @@ class ProgressDemo
257
345
  end
258
346
 
259
347
  def run_command(cmd)
260
- puts "#{@colors[:command]}$ #{cmd}#{@colors[:reset]}"
348
+ # Type the command with syntax highlighting
349
+ type_command("$ #{cmd.sub(%r{^bin/}, '')}")
261
350
  puts
262
351
  system(cmd)
263
352
  puts
264
353
  end
265
354
 
355
+ # Type out a shell command with simple token-based syntax highlighting.
356
+ # - executable (first token) uses @colors[:exec]
357
+ # - flags (tokens starting with '-') use @colors[:flag]
358
+ # - values use @colors[:value]
359
+ # The function prints one character at a time to simulate typing.
360
+ def type_command(line, speed: 0.04)
361
+ tokens = line.scan(/'[^']*'|"[^"]*"|\S+/)
362
+ pos = 0
363
+
364
+ # Determine the executable token position (skip leading prompt '$' tokens)
365
+ exec_pos = tokens.find_index { |t| !t.start_with?('$') }
366
+ subcmd_pos = exec_pos ? exec_pos + 1 : nil
367
+
368
+ tokens.each_with_index do |token, idx|
369
+ # Find token in original line starting at pos (to preserve spacing)
370
+ start_idx = line.index(token, pos) || pos
371
+
372
+ # print any intermediate whitespace
373
+ inter = line[pos...start_idx]
374
+ $stdout.print(inter) if inter && !inter.empty?
375
+
376
+ # Default color for tokens is value
377
+ color = @colors[:value]
378
+
379
+ if token.start_with?('$')
380
+ color = @colors[:prompt]
381
+ elsif idx == exec_pos && token == 'prg'
382
+ # Highlight the bundled tool name in magenta
383
+ color = @colors[:tool]
384
+ elsif idx == exec_pos
385
+ # Executable token (e.g. ruby or other) - keep exec color
386
+ color = @colors[:exec]
387
+ elsif idx == subcmd_pos
388
+ # Subcommand (ripple/twirl/worm/fill etc.) highlighted in yellow
389
+ color = @colors[:command]
390
+ elsif token.start_with?('-')
391
+ color = @colors[:flag]
392
+ end
393
+
394
+ # Print the token one char at a time
395
+ token.each_char do |ch|
396
+ $stdout.print("#{color}#{ch}#{@colors[:reset]}")
397
+ $stdout.flush
398
+ sleep(speed)
399
+ end
400
+
401
+ pos = start_idx + token.length
402
+ end
403
+
404
+ # Print any trailing whitespace/newline
405
+ trailing = line[pos..-1]
406
+ $stdout.print(trailing) if trailing
407
+ $stdout.flush
408
+ end
409
+
266
410
  def pause_for_narration(seconds = 2)
267
- puts "#{@colors[:dim]}[Pausing #{seconds}s for narration...]#{@colors[:reset]}"
268
- sleep(seconds)
411
+ # puts "#{@colors[:dim]}[Pausing #{seconds}s for narration...]#{@colors[:reset]}"
412
+ # sleep(seconds)
269
413
  end
270
414
 
271
- def pause_between_demos(seconds = 3)
272
- puts "#{@colors[:dim]}[Pausing #{seconds}s between demos...]#{@colors[:reset]}"
415
+ def pause_between_demos(seconds = 2)
416
+ # puts "#{@colors[:dim]}[Pausing #{seconds}s between demos...]#{@colors[:reset]}"
273
417
  sleep(seconds)
274
418
  end
275
419
  end
@@ -278,14 +422,14 @@ end
278
422
  if __FILE__ == $PROGRAM_NAME
279
423
  demo = ProgressDemo.new
280
424
 
281
- puts 'Ruby Progress Gem Demo Screencast'
282
- puts '================================='
283
- puts
284
- puts 'This script will demonstrate various features of the ruby-progress gem.'
285
- puts 'Press ENTER to start the demo, or Ctrl+C to exit.'
286
- puts
287
- print 'Ready? '
288
- gets
425
+ # puts 'Ruby Progress Gem Demo Screencast'
426
+ # puts '================================='
427
+ # puts
428
+ # puts 'This script will demonstrate various features of the ruby-progress gem.'
429
+ # puts 'Press ENTER to start the demo, or Ctrl+C to exit.'
430
+ # puts
431
+ # print 'Ready? '
432
+ # gets
289
433
 
290
434
  begin
291
435
  demo.run