ruby-progress 1.2.4 → 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: 446ecad2fd85e194293130a638b9e986270c5849ad5cd8a65733b5c2f01198df
4
- data.tar.gz: 35686adf5664171676333a89d48f3f296dcc03751636eea49711a3885ea86d4d
3
+ metadata.gz: 5c5a7ddc53059cb7f6d2b7bd1c066653058e1dbb281f4c23aa04229ce360a594
4
+ data.tar.gz: 0446a713142b93f16b9fe3e102c8a3c0db3194db17da25de7f1f7f31e5090907
5
5
  SHA512:
6
- metadata.gz: d5cd10f336fae3e523e00c70bc9939f6b4162b1b9473424e1c481b0aa9f077b5f0e08037bb53f96f23f5d07a38a0ac5c72947daf90d545127736f002db692c77
7
- data.tar.gz: 86f820e4b75c810e45801f1a214d219f7103e386e4c53bd733eb22a231a3162900b0b011c566f2d134b0a78e06947d33ddf1e2f9fea5c8a35552f56bc4b1f7e0
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
@@ -1,4 +1,3 @@
1
-
2
1
  # CHANGELOG
3
2
 
4
3
  All notable changes to this project will be documented in this file.
@@ -6,6 +5,44 @@ All notable changes to this project will be documented in this file.
6
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
7
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
8
7
 
8
+ ## 1.3.0 - 2025-10-12
9
+
10
+ ### Added
11
+
12
+ - PTY-based output capture: `RubyProgress::OutputCapture` now allows running commands under a PTY, keeps a rolling buffer of the last N lines for live redraw, and optionally writes the full streamed output to a `log_path` file.
13
+ - File-based daemon job queue: `RubyProgress::Daemon.process_jobs` implements atomic job enqueue/claim/processing with `.processing.result` metadata files and processed-archive behavior.
14
+ - `prg job send` CLI helper: atomically writes jobs to daemon job dirs and supports `--wait` to poll for results, `--daemon-name`, `--pid-file`, `--stdin`, and `--timeout`.
15
+ - Integration of job processing into Ripple/Twirl/Worm daemon modes so a running daemon can accept and display job output without interrupting animations.
16
+ - CLI options for output handling: `--output-position` and `--output-lines` to reserve terminal rows for captured output.
17
+
18
+ ### Changed
19
+
20
+ - Job result files now merge any Hash returned by the job handler into the `.processing.result` JSON (e.g., `exit_status`, `output`, `log_path`).
21
+
22
+ ### Tests
23
+
24
+ - Added unit and integration tests covering job enqueueing, processing, and result persistence.
25
+
26
+ ### Release notes
27
+
28
+ - Merge commit: 99d9c39 (squash-merge of feature/output-handling)
29
+
30
+ ## 1.3.2 - 2025-10-13
31
+
32
+ ### Added
33
+
34
+ - `fill` subcommand: added `-c, --command COMMAND` so the determinate progress bar can run and capture command output like the other subcommands. This includes `--output-lines` and `--output-position` support for reserving terminal rows during capture.
35
+
36
+ ### Changed
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
+
43
+ - Bumped `FILL_VERSION` (patch) to reflect the new CLI behavior.
44
+
45
+
9
46
  ## 1.2.3 - 2025-10-11
10
47
 
11
48
  ### Added
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-progress (1.2.4)
4
+ ruby-progress (1.3.2)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -8,6 +8,27 @@
8
8
 
9
9
  This repository contains three different Ruby progress indicator projects: **Ripple**, **Worm**, and **Twirl**. All provide animated terminal progress indicators with different visual styles and features.
10
10
 
11
+ ## Table of Contents
12
+
13
+ - [Unified Interface](#unified-interface)
14
+ - [Submitting jobs to a running daemon](#submitting-jobs-to-a-running-daemon)
15
+ - [Job result schema](#job-result-schema)
16
+ - [Example: start a daemon and send a job (simple)](#example-start-a-daemon-and-send-a-job-simple)
17
+ - [Ripple](#ripple)
18
+ - [Ripple Features](#ripple-features)
19
+ - [Ripple Usage](#ripple-usage)
20
+ - [Twirl](#twirl)
21
+ - [Worm](#worm)
22
+ - [Daemon mode (background indicator)](#daemon-mode-background-indicator)
23
+ - [Requirements](#requirements)
24
+ - [Installation](#installation)
25
+ - [Universal Utilities](#universal-utilities)
26
+ - [Terminal Control](#terminal-control)
27
+ - [Completion Messages](#completion-messages)
28
+ - [Development](#development)
29
+ - [Contributing](#contributing)
30
+ - [License](#license)
31
+
11
32
  ## Unified Interface
12
33
 
13
34
  The gem provides a unified `prg` command that supports all progress indicators through subcommands:
@@ -30,12 +51,12 @@ prg twirl --message "Working..." --style dots --speed fast
30
51
 
31
52
  # Run fill directly (delegates to prg)
32
53
  fill --report --percent 50
33
- ```
34
54
 
35
55
  ### With command execution
36
56
  prg worm --command "sleep 5" --success "Completed!" --error "Failed!" --checkmark
37
57
  prg ripple "Building..." --command "make build" --success "Build complete!" --stdout
38
58
  prg twirl --command "npm install" --message "Installing packages" --style arc
59
+ prg fill --command "sleep 5" --success "Done!" --checkmark
39
60
 
40
61
  ### With start/end character decoration using --ends
41
62
  prg ripple "Loading data" --ends "[]" --style rainbow
@@ -49,160 +70,123 @@ prg worm --message "Magic" --ends "🎯🎪" --style "custom=🟦🟨🟥"
49
70
  ### Global Options
50
71
 
51
72
  - `prg --help` - Show main help
52
- - `prg --version` - Show version info
53
- - `prg --list-styles` - Show all available styles for all subcommands
54
- - `prg <subcommand> --help` - Show specific subcommand help
55
73
 
56
- ### Common Options (available for all subcommands)
74
+ Notes:
57
75
 
58
- - `--speed SPEED` - Animation speed (fast/medium/slow or f/m/s)
59
- - `--message MESSAGE` - Message to display
60
- - `--command COMMAND` - Command to execute during animation
61
- - `--success MESSAGE` - Success message after completion
62
- - `--error MESSAGE` - Error message on failure
63
- - `--checkmark` - Show checkmarks (✅ success, 🛑 failure)
64
- - `--stdout` - Output command results to STDOUT
65
- - `--ends CHARS` - Start/end characters (even number of chars, split in half)
76
+ - The CLI detaches itself (double-fork); do not append `&`. This prevents shell job notifications like “job … has ended.” The command returns immediately.
77
+ - `--stop-success` and `--stop-error` are mutually exclusive; whichever you provide determines the success state and icon if `--stop-checkmark` is set.
78
+ - The indicator clears its line on shutdown and prints the final message to STDOUT.
79
+ - `--stop-pid` is still supported for backward compatibility, but `--stop [--pid-file FILE]` is preferred.
66
80
 
67
- ### Daemon Mode (Background Progress)
81
+ ### Submitting jobs to a running daemon
68
82
 
69
- For shell scripts where you need a continuous progress indicator across multiple steps, use daemon mode. You can use named daemons or custom PID files.
83
+ When running a long-lived daemon (for example `prg worm --daemon`), you can submit additional commands to run and have their output displayed without disrupting the animation using the `prg job send` helper.
84
+
85
+ Basic usage:
70
86
 
71
87
  ```bash
72
- ### Start in background (uses default PID file)
73
- prg worm --daemon --message "Working..."
88
+ # Enqueue a command to the default daemon PID
89
+ prg job send --command "./deploy-step.sh"
74
90
 
75
- ### Start with a custom name (creates /tmp/ruby-progress/NAME.pid)
76
- prg worm --daemon-as mytask --message "Processing data..."
91
+ # Enqueue to a named daemon (creates /tmp/ruby-progress/<name>.pid)
92
+ prg job send --daemon-name mytask --command "rsync -av ./dist/ user@host:/srv/app"
77
93
 
78
- ### ... run your tasks ...
94
+ # Read command from stdin (useful in scripts)
95
+ echo "bundle exec rake db:migrate" | prg job send --stdin --daemon-name mytask
79
96
 
80
- ### Stop with a success message and checkmark (--stop-success implies --stop)
81
- prg worm --stop-success "All done" --stop-checkmark
97
+ # Wait for the job result and print the job result JSON (default timeout 10s)
98
+ prg job send --daemon-name mytask --command "./deploy-step.sh" --wait --timeout 30
99
+ ```
82
100
 
83
- ### Stop a named daemon (--stop-id implies --stop)
84
- prg worm --stop-id mytask --stop-success "Task complete!" --stop-checkmark
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:
85
102
 
86
- ### Or stop with an error message and checkmark
87
- prg worm --stop-error "Failed during step" --stop-checkmark
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
88
109
 
89
- ### Check status at any time
90
- prg worm --status
91
- prg worm --status-id mytask
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
92
114
 
93
- ### Use a completely custom PID file path
94
- prg worm --daemon --pid-file /tmp/custom-progress.pid
95
- prg worm --status --pid-file /tmp/custom-progress.pid
96
- prg worm --stop-success "Complete" --pid-file /tmp/custom-progress.pid
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
97
119
  ```
98
120
 
99
- Notes:
121
+ # Or use the generic action/value pair
122
+ prg job send --daemon-name demo --action percent --value 42
123
+ ```
100
124
 
101
- - The CLI detaches itself (double-fork); do not append `&`. This prevents shell job notifications like “job … has ended.” The command returns immediately.
102
- - `--stop-success` and `--stop-error` are mutually exclusive; whichever you provide determines the success state and icon if `--stop-checkmark` is set.
103
- - The indicator clears its line on shutdown and prints the final message to STDOUT.
104
- - `--stop-pid` is still supported for backward compatibility, but `--stop [--pid-file FILE]` is preferred.
105
- o- [Ruby Progress Indicators](#ruby-progress-indicators)
106
- - [Unified Interface](#unified-interface)
107
- - [With command execution](#with-command-execution)
108
- - [With start/end character decoration using --ends](#with-startend-character-decoration-using-ends)
109
- - [Complex --ends patterns with emojis](#complex-ends-patterns-with-emojis)
110
- - [Start in background (uses default PID file)](#start-in-background-uses-default-pid-file)
111
- - [Start with a custom name (creates /tmp/ruby-progress/NAME.pid)](#start-with-a-custom-name-creates-tmpruby-progressnamepid)
112
- - [... run your tasks ...](#-run-your-tasks-)
113
- - [Stop with a success message and checkmark (--stop-success implies --stop)](#stop-with-a-success-message-and-checkmark-stop-success-implies-stop)
114
- - [Stop a named daemon (--stop-id implies --stop)](#stop-a-named-daemon-stop-id-implies-stop)
115
- - [Or stop with an error message and checkmark](#or-stop-with-an-error-message-and-checkmark)
116
- - [Check status at any time](#check-status-at-any-time)
117
- - [Use a completely custom PID file path](#use-a-completely-custom-pid-file-path)
118
- - [Basic text animation](#basic-text-animation)
119
- - [With style options](#with-style-options)
120
- - [Multiple styles combined](#multiple-styles-combined)
121
- - [Case transformation mode](#case-transformation-mode)
122
- - [Run a command with progress animation](#run-a-command-with-progress-animation)
123
- - [Simple progress block](#simple-progress-block)
124
- - [With options](#with-options)
125
- - [Basic spinner animation](#basic-spinner-animation)
126
- - [With command execution](#with-command-execution)
127
- - [Different spinner styles](#different-spinner-styles)
128
- - [With success/error handling](#with-successerror-handling)
129
- - [Daemon mode for background tasks](#daemon-mode-for-background-tasks)
130
- - [... do other work ...](#-do-other-work-)
131
- - [Run indefinitely without a command (like ripple)](#run-indefinitely-without-a-command-like-ripple)
132
- - [Run a command with progress animation](#run-a-command-with-progress-animation)
133
- - [Customize the animation](#customize-the-animation)
134
- - [With custom error handling](#with-custom-error-handling)
135
- - [With checkmarks for visual feedback](#with-checkmarks-for-visual-feedback)
136
- - [Control animation direction (forward-only or bidirectional)](#control-animation-direction-forward-only-or-bidirectional)
137
- - [Create custom animations with 3-character patterns](#create-custom-animations-with-3-character-patterns)
138
- - [Add start/end characters around the animation](#add-startend-characters-around-the-animation)
139
- - [Capture and display command output](#capture-and-display-command-output)
140
- - [Combine checkmarks and stdout output](#combine-checkmarks-and-stdout-output)
141
- - [Start in the background (default PID file: /tmp/ruby-progress/progress.pid)](#start-in-the-background-default-pid-file-tmpruby-progressprogresspid)
142
- - [... run your tasks ...](#-run-your-tasks-)
143
- - [Stop using the default PID file](#stop-using-the-default-pid-file)
144
- - [Use a custom PID file](#use-a-custom-pid-file)
145
- - [Stop using the matching custom PID file](#stop-using-the-matching-custom-pid-file)
146
- - [Create and run animation with a block](#create-and-run-animation-with-a-block)
147
- - [Your work here](#your-work-here)
148
- - [With custom style and forward direction](#with-custom-style-and-forward-direction)
149
- - [Or run with a command](#or-run-with-a-command)
150
- - [ASCII characters](#ascii-characters)
151
- - [Unicode characters](#unicode-characters)
152
- - [Emojis (supports multi-byte characters)](#emojis-supports-multi-byte-characters)
153
- - [Mixed ASCII and emoji](#mixed-ascii-and-emoji)
154
- - [Cursor control](#cursor-control)
155
- - [Basic completion message](#basic-completion-message)
156
- - [With success/failure indication and checkmarks](#with-successfailure-indication-and-checkmarks)
157
- - [Clear line and display completion (useful for replacing progress indicators)](#clear-line-and-display-completion-useful-for-replacing-progress-indicators)
125
+ Note about stopping named daemons:
158
126
 
159
- ## Table of Contents
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:
160
128
 
161
- - [Ruby Progress Indicators](#ruby-progress-indicators)
162
- - [Unified Interface](#unified-interface)
163
- - [With command execution](#with-command-execution)
164
- - [With start/end character decoration using --ends](#with-startend-character-decoration-using---ends)
165
- - [Complex --ends patterns with emojis](#complex---ends-patterns-with-emojis)
166
- - [Table of Contents](#table-of-contents)
167
- - [Ripple](#ripple)
168
- - [Ripple Features](#ripple-features)
169
- - [Ripple Usage](#ripple-usage)
170
- - [Ripple CLI examples](#ripple-cli-examples)
171
- - [Ripple Command Line Options](#ripple-command-line-options)
172
- - [Ripple Library Usage](#ripple-library-usage)
173
- - [Twirl](#twirl)
174
- - [Twirl Features](#twirl-features)
175
- - [Twirl Usage](#twirl-usage)
176
- - [Command Line](#command-line)
177
- - [Twirl Command Line Options](#twirl-command-line-options)
178
- - [Available Spinner Styles](#available-spinner-styles)
179
- - [Worm](#worm)
180
- - [Worm Features](#worm-features)
181
- - [Worm Usage](#worm-usage)
182
- - [Command Line](#command-line-1)
183
- - [Daemon mode (background indicator)](#daemon-mode-background-indicator)
184
- - [Worm Command Line Options](#worm-command-line-options)
185
- - [Worm Library Usage](#worm-library-usage)
186
- - [Animation Styles](#animation-styles)
187
- - [Circles](#circles)
188
- - [Blocks](#blocks)
189
- - [Geometric](#geometric)
190
- - [Custom Styles](#custom-styles)
191
- - [Direction Control](#direction-control)
192
- - [Requirements](#requirements)
193
- - [Installation](#installation)
194
- - [As a Gem (Recommended)](#as-a-gem-recommended)
195
- - [From Source](#from-source)
196
- - [Development](#development)
197
- - [Universal Utilities](#universal-utilities)
198
- - [Terminal Control](#terminal-control)
199
- - [Completion Messages](#completion-messages)
200
- - [Contributing](#contributing)
201
- - [License](#license)
129
+ ```bash
130
+ # Stop a named fill worker with a success message
131
+ prg fill --stop-id demo --stop-success 'Demo finished'
132
+ ```
133
+
134
+ Behavior and file layout:
135
+
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`.
137
+ - The CLI writes the job atomically by first writing a `*.json.tmp` temporary file and then renaming it to `*.json`.
138
+ - The daemon's job processor claims jobs atomically by renaming the job file to `*.processing`, writes a `*.processing.result` JSON file when finished, and moves processed jobs to `processed-*`.
139
+
140
+ This mechanism allows you to submit many commands to a single running indicator and have their output shown in reserved terminal rows while the animation continues.
141
+
142
+ ## Job result schema
143
+
144
+ When a job is processed the daemon writes a small JSON result file next to the claimed job with the suffix `.processing.result` containing at least these keys:
145
+
146
+ - `id` - the job id (string)
147
+ - `status` - `"done"` or `"error"`
148
+ - `time` - epoch seconds when the job finished (integer)
149
+
150
+ Depending on the job handler, additional keys may be present:
151
+
152
+ - `exit_status` - the numeric process exit status (integer or nil if unknown)
153
+ - `output` - a string with the last captured lines of output (if available)
154
+ - `error` - an error message when `status` is `error`
155
+
156
+ Example:
157
+
158
+ ```json
159
+ {
160
+ "id": "8a1f6c1e-4b7a-4f2c-b0a8-9e9f1c2f1a2b",
161
+ "status": "done",
162
+ "time": 1634044800,
163
+ "exit_status": 0,
164
+ "output": "Step 1 completed\nStep 2 completed"
165
+ }
166
+ ```
202
167
 
168
+ This file is intended for short messages and small captured output snippets (the CLI captures the last N lines). If you need larger logs, write them to a persistent file from the command itself and include a reference in the job metadata.
203
169
 
170
+ ## Example: start a daemon and send a job (simple)
171
+
172
+ Below is an example script that demonstrates starting a worm daemon, sending a job, waiting for the result, and stopping the daemon.
204
173
  ---
205
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
+
206
190
  ## Ripple
207
191
 
208
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.
@@ -407,6 +391,15 @@ prg worm --message "Emoji ends" --ends "🎯🎪" --style "custom=🟦🟨🟥"
407
391
  ### Capture and display command output
408
392
  prg worm --command "git status" --message "Checking status" --stdout
409
393
 
394
+ You can reserve terminal rows for captured command output so the animation doesn't interleave with the script output. Use:
395
+
396
+ - `--output-position POSITION` — `above` (default) or `below` the animation
397
+ - `--output-lines N` — how many terminal rows to reserve for captured output (default: 3)
398
+
399
+ Examples:
400
+
401
+ prg worm --command "git status" --stdout --output-position above --output-lines 4
402
+
410
403
  ### Combine checkmarks and stdout output
411
404
  prg worm --command "echo 'Build output'" --success "Build complete!" --checkmark --stdout
412
405
  ```
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
@@ -7,6 +7,7 @@ require 'optparse'
7
7
  require 'json'
8
8
  require 'English'
9
9
 
10
+ require_relative '../lib/ruby-progress/cli/job_cli'
10
11
  # Load extracted per-subcommand CLI modules
11
12
  require_relative '../lib/ruby-progress/cli/ripple_cli'
12
13
  require_relative '../lib/ruby-progress/cli/worm_cli'
@@ -20,6 +21,18 @@ module PrgCLI
20
21
  exit 1
21
22
  end
22
23
 
24
+ # Handle `job` subcommands early
25
+ if ARGV[0] && ARGV[0].downcase == 'job'
26
+ ARGV.shift
27
+ sub = ARGV.shift
28
+ case sub
29
+ when 'send'
30
+ JobCLI.send(ARGV)
31
+ else
32
+ puts 'job subcommands: send'
33
+ exit 1
34
+ end
35
+ end
23
36
  # Early scan: detect --ends flag and validate its argument before dispatching
24
37
  if (i = ARGV.index('--ends')) && ARGV[i + 1]
25
38
  ends_val = ARGV[i + 1]
@@ -113,6 +126,43 @@ module PrgCLI
113
126
  puts '== fill =='
114
127
  end
115
128
 
129
+ # Detach the current process into a background daemon. Uses Process.daemon
130
+ # when available, otherwise falls back to a basic fork/exit helper. This is
131
+ # intentionally simple for the test environment.
132
+ def self.daemonize
133
+ if Process.respond_to?(:daemon)
134
+ Process.daemon(true)
135
+ else
136
+ pid = fork
137
+ if pid
138
+ # parent exits so child can continue as daemon
139
+ exit(0)
140
+ else
141
+ # child: detach from controlling terminal
142
+ begin
143
+ Process.setsid
144
+ rescue StandardError
145
+ nil
146
+ end
147
+ end
148
+ end
149
+ end
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
+
116
166
  # Attempt to stop processes for the given subcommand. Return true if any
117
167
  # process was signaled/stopped; false otherwise. Keep quiet on missing
118
168
  # processes to satisfy integration tests.