ruby-progress 1.1.9 → 1.2.4

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.
@@ -0,0 +1,296 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Ruby Progress Gem Demo Screencast Script
5
+ # ========================================
6
+ #
7
+ # This script creates a comprehensive demonstration of the ruby-progress gem
8
+ # showing all major features across the three subcommands: ripple, worm, and twirl.
9
+ #
10
+ # Usage: ruby demo_screencast.rb
11
+ #
12
+ # The script includes pauses between demonstrations to allow for narration
13
+ # and clear visual separation of different features.
14
+
15
+ require 'io/console'
16
+
17
+ # Demo runner that exercises the major features of the ruby-progress gem
18
+ # used by the documentation and screencast recordings.
19
+ class ProgressDemo
20
+ def initialize
21
+ @gem_path = File.expand_path('bin/prg', __dir__)
22
+ @lib_path = File.expand_path('lib', __dir__)
23
+
24
+ # Colors for terminal output
25
+ @colors = {
26
+ header: "\e[1;36m", # Bright cyan
27
+ command: "\e[1;33m", # Bright yellow
28
+ description: "\e[0;32m", # Green
29
+ reset: "\e[0m", # Reset
30
+ dim: "\e[2m" # Dim
31
+ }
32
+ end
33
+
34
+ def run
35
+ clear_screen
36
+ show_title
37
+
38
+ # Introduction
39
+ show_section_header('Ruby Progress Gem Demo')
40
+ show_description('Demonstrating terminal progress indicators with style!')
41
+ pause_for_narration(3)
42
+
43
+ # Basic examples for each command
44
+ demo_basic_commands
45
+
46
+ # Style demonstrations
47
+ demo_styles
48
+
49
+ # Advanced options
50
+ demo_advanced_options
51
+
52
+ # New v1.2.0 features
53
+ demo_new_features
54
+
55
+ # Finale
56
+ show_finale
57
+ end
58
+
59
+ private
60
+
61
+ def demo_basic_commands
62
+ show_section_header('Basic Commands Overview')
63
+
64
+ # Ripple - basic expanding circle animation
65
+ 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")
67
+ pause_between_demos
68
+
69
+ # Worm - progress bar animation
70
+ 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")
72
+ pause_between_demos
73
+
74
+ # Twirl - spinning indicator
75
+ show_demo_header('Twirl', 'Classic spinning indicator for quick tasks')
76
+ run_command("#{ruby_cmd} twirl --command 'sleep 3' --success 'Task completed!' --checkmark")
77
+ pause_between_demos
78
+ end
79
+
80
+ def demo_styles
81
+ show_section_header('Style Variations')
82
+
83
+ # Ripple styles
84
+ show_demo_header('Ripple Styles', 'Different visual patterns')
85
+ show_command_info('Default ripple style')
86
+ run_command("#{ruby_cmd} ripple --command 'sleep 3' --success 'Default style'")
87
+ pause_between_demos(2)
88
+
89
+ show_command_info('Pulse style')
90
+ run_command("#{ruby_cmd} ripple --style pulse --command 'sleep 3' --success 'Pulse style'")
91
+ pause_between_demos
92
+
93
+ # Worm styles
94
+ show_demo_header('Worm Styles', 'Various progress bar animations')
95
+ 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! 🎉'")
101
+ pause_between_demos(2)
102
+
103
+ show_command_info('Blocks worm style')
104
+ run_command("#{ruby_cmd} worm --length 10 --style blocks --command 'sleep 4' --success 'Block worm'")
105
+ pause_between_demos
106
+
107
+ # Twirl styles
108
+ show_demo_header('Twirl Styles', 'Different spinning patterns')
109
+ show_command_info('Classic spinner')
110
+ run_command("#{ruby_cmd} twirl --style classic --command 'sleep 3' --success 'Classic spin'")
111
+ pause_between_demos(2)
112
+
113
+ show_command_info('Dots spinner')
114
+ run_command("#{ruby_cmd} twirl --style dots --command 'sleep 3' --success 'Dotty!'")
115
+ pause_between_demos(2)
116
+
117
+ show_command_info('Arrow spinner')
118
+ run_command("#{ruby_cmd} twirl --style arrow --command 'sleep 3' --success 'Arrow spin'")
119
+ pause_between_demos
120
+ end
121
+
122
+ def demo_advanced_options
123
+ show_section_header('Advanced Options')
124
+
125
+ # Error handling
126
+ show_demo_header('Error Handling', 'Graceful failure with custom messages')
127
+ 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")
129
+ pause_between_demos
130
+
131
+ # Custom colors (if supported)
132
+ show_demo_header('Success Messages', 'Custom completion messages')
133
+ show_command_info('Custom success message with checkmark')
134
+ run_command("#{ruby_cmd} ripple --command 'sleep 3' --success 'Data synchronized successfully' --checkmark")
135
+ pause_between_demos(2)
136
+
137
+ show_command_info('Different success icon')
138
+ run_command("#{ruby_cmd} twirl --command 'sleep 3' --success 'Backup completed' --icon '✓'")
139
+ pause_between_demos
140
+
141
+ # No completion message
142
+ show_demo_header('Silent Completion', 'Progress without completion messages')
143
+ show_command_info('Silent completion (no message)')
144
+ run_command("#{ruby_cmd} worm --length 10 --command 'sleep 3'")
145
+ pause_between_demos
146
+ end
147
+
148
+ def demo_new_features
149
+ show_section_header('New in v1.2.0 - Enhanced Features')
150
+
151
+ # Universal --ends flag
152
+ show_demo_header('Universal --ends Flag', 'Add decorative start/end characters')
153
+ show_command_info("Ripple with square brackets: --ends '[]'")
154
+ run_command("#{ruby_cmd} ripple --ends '[]' --command 'sleep 4' --success 'Framed ripple!'")
155
+ pause_between_demos(2)
156
+
157
+ show_command_info("Worm with angle brackets: --ends '<<>>'")
158
+ run_command("#{ruby_cmd} worm --length 10 --ends '<<>>' --command 'sleep 4' --success 'Angled worm!'")
159
+ pause_between_demos(2)
160
+
161
+ show_command_info("Twirl with emoji decoration: --ends '🎯🎪'")
162
+ run_command("#{ruby_cmd} twirl --ends '🎯🎪' --command 'sleep 3' --success 'Emoji decorated!'")
163
+ pause_between_demos
164
+
165
+ # Worm direction control
166
+ show_demo_header('Worm Direction Control', 'Forward-only vs bidirectional movement')
167
+ show_command_info('Bidirectional worm (default back-and-forth)')
168
+ run_command("#{ruby_cmd} worm --length 10 --direction bidirectional --command 'sleep 5' --success 'Back and forth!'")
169
+ pause_between_demos(2)
170
+
171
+ show_command_info('Forward-only worm (resets at end)')
172
+ run_command("#{ruby_cmd} worm --length 10 --direction forward --command 'sleep 5' --success 'Always forward!'")
173
+ pause_between_demos
174
+
175
+ # Custom worm styles
176
+ show_demo_header('Custom Worm Styles', 'User-defined 3-character patterns')
177
+ show_command_info('ASCII custom style: --style custom=_-=')
178
+ run_command("#{ruby_cmd} worm --length 10 --style custom=_-= --command 'sleep 4' --success 'Custom ASCII!'")
179
+ pause_between_demos(2)
180
+
181
+ show_command_info('Unicode custom style: --style custom=▫▪■')
182
+ run_command("#{ruby_cmd} worm --length 10 --style custom=▫▪■ --command 'sleep 4' --success 'Custom Unicode!'")
183
+ pause_between_demos(2)
184
+
185
+ show_command_info('Emoji custom style: --style custom=🟦🟨🟥')
186
+ run_command("#{ruby_cmd} worm --length 10 --style custom=🟦🟨🟥 --command 'sleep 4' --success 'Custom emoji!'")
187
+ pause_between_demos
188
+
189
+ # Combining features
190
+ show_demo_header('Feature Combinations', 'Mixing multiple options together')
191
+ show_command_info('Custom style + direction + ends: the full package!')
192
+ # Split the long command string to avoid RuboCop line-length issues while preserving behavior
193
+ part1 = "#{ruby_cmd} worm --length 10 --style custom=.🟡* --direction forward "
194
+ part2 = "--ends '【】' --command 'sleep 5' --success 'Ultimate combo!' --checkmark"
195
+ run_command(part1 + part2)
196
+ pause_between_demos
197
+ end
198
+
199
+ def show_finale
200
+ show_section_header('Demo Complete!')
201
+ show_description('Ruby Progress Gem v1.2.0 - Making terminal progress beautiful! 🚀')
202
+ puts
203
+ show_description('Key features demonstrated:')
204
+ puts "#{@colors[:description]} • Three animation types: ripple, worm, twirl#{@colors[:reset]}"
205
+ puts "#{@colors[:description]} • Multiple built-in styles#{@colors[:reset]}"
206
+ puts "#{@colors[:description]} • Universal --ends flag for decoration#{@colors[:reset]}"
207
+ puts "#{@colors[:description]} • Worm direction control#{@colors[:reset]}"
208
+ puts "#{@colors[:description]} • Custom user-defined styles#{@colors[:reset]}"
209
+ puts "#{@colors[:description]} • Success/error handling#{@colors[:reset]}"
210
+ puts "#{@colors[:description]} • Multi-byte character support (Unicode/emoji)#{@colors[:reset]}"
211
+ puts
212
+ show_description('Install: gem install ruby-progress')
213
+ show_description('GitHub: https://github.com/ttscoff/ruby-progress')
214
+ puts
215
+ end
216
+
217
+ # Utility methods
218
+
219
+ def ruby_cmd
220
+ "ruby -I #{@lib_path} #{@gem_path}"
221
+ end
222
+
223
+ def clear_screen
224
+ system('clear') || system('cls')
225
+ end
226
+
227
+ def show_title
228
+ puts
229
+ puts "#{@colors[:header]}#{'=' * 60}#{@colors[:reset]}"
230
+ puts "#{@colors[:header]} RUBY PROGRESS GEM - DEMO SCREENCAST#{@colors[:reset]}"
231
+ puts "#{@colors[:header]} Version 1.2.0 Feature Demonstration#{@colors[:reset]}"
232
+ puts "#{@colors[:header]}#{'=' * 60}#{@colors[:reset]}"
233
+ puts
234
+ end
235
+
236
+ def show_section_header(title)
237
+ puts
238
+ puts "#{@colors[:header]}#{'-' * 50}#{@colors[:reset]}"
239
+ puts "#{@colors[:header]} #{title}#{@colors[:reset]}"
240
+ puts "#{@colors[:header]}#{'-' * 50}#{@colors[:reset]}"
241
+ puts
242
+ end
243
+
244
+ def show_demo_header(title, description)
245
+ puts
246
+ puts "#{@colors[:header]}### #{title}#{@colors[:reset]}"
247
+ puts "#{@colors[:description]}#{description}#{@colors[:reset]}"
248
+ puts
249
+ end
250
+
251
+ def show_command_info(description)
252
+ puts "#{@colors[:dim]}#{description}#{@colors[:reset]}"
253
+ end
254
+
255
+ def show_description(text)
256
+ puts "#{@colors[:description]}#{text}#{@colors[:reset]}"
257
+ end
258
+
259
+ def run_command(cmd)
260
+ puts "#{@colors[:command]}$ #{cmd}#{@colors[:reset]}"
261
+ puts
262
+ system(cmd)
263
+ puts
264
+ end
265
+
266
+ def pause_for_narration(seconds = 2)
267
+ puts "#{@colors[:dim]}[Pausing #{seconds}s for narration...]#{@colors[:reset]}"
268
+ sleep(seconds)
269
+ end
270
+
271
+ def pause_between_demos(seconds = 3)
272
+ puts "#{@colors[:dim]}[Pausing #{seconds}s between demos...]#{@colors[:reset]}"
273
+ sleep(seconds)
274
+ end
275
+ end
276
+
277
+ # Script execution
278
+ if __FILE__ == $PROGRAM_NAME
279
+ demo = ProgressDemo.new
280
+
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
289
+
290
+ begin
291
+ demo.run
292
+ rescue Interrupt
293
+ puts "\n\nDemo interrupted. Thanks for watching!"
294
+ exit(0)
295
+ end
296
+ end
@@ -1,7 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Experimental terminal line protection for daemon mode
2
4
  # This demonstrates potential solutions for the daemon output interruption problem
3
5
 
4
6
  module RubyProgress
7
+ # SmartTerminal: experimental helpers for safer terminal cursor/line operations
8
+ # used by daemon-mode demos and scripts where output can interleave with animations.
5
9
  module SmartTerminal
6
10
  # Save current cursor position
7
11
  def self.save_cursor_position
@@ -16,6 +20,8 @@ module RubyProgress
16
20
  end
17
21
 
18
22
  # Get current cursor position (requires terminal interaction)
23
+ # rubocop:disable Naming/AccessorMethodName
24
+ # Intentionally named get_cursor_position because it performs an I/O request
19
25
  def self.get_cursor_position
20
26
  # This is complex and requires reading from stdin
21
27
  # which may not work reliably in daemon mode
@@ -24,6 +30,7 @@ module RubyProgress
24
30
  # Would need to read response: "\e[{row};{col}R"
25
31
  # But this requires terminal input capability
26
32
  end
33
+ # rubocop:enable Naming/AccessorMethodName
27
34
 
28
35
  # Alternative: Use absolute positioning
29
36
  def self.position_cursor_absolute(row, col)
@@ -0,0 +1,193 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'optparse'
4
+
5
+ module RubyProgress
6
+ module FillCLI
7
+ # Option parsing extracted to reduce module length in FillCLI
8
+ module Options
9
+ def self.parse_cli_options
10
+ options = {
11
+ style: :blocks,
12
+ length: 20,
13
+ speed: :medium,
14
+ percent: nil,
15
+ advance: false,
16
+ complete: false,
17
+ cancel: false,
18
+ success_message: nil,
19
+ error_message: nil,
20
+ checkmark: false,
21
+ daemon: false,
22
+ pid_file: nil,
23
+ stop: false,
24
+ status: false,
25
+ current: false,
26
+ report: false
27
+ }
28
+
29
+ begin
30
+ OptionParser.new do |opts|
31
+ opts.banner = 'Usage: prg fill [options]'
32
+ opts.separator ''
33
+ opts.separator 'Progress Bar Options:'
34
+
35
+ opts.on('-l', '--length LENGTH', Integer, 'Progress bar length (default: 20)') do |length|
36
+ options[:length] = length
37
+ end
38
+
39
+ opts.on('-s', '--style STYLE', 'Progress bar style (blocks, classic, dots, etc. or custom=XY)') do |style|
40
+ options[:style] = style
41
+ end
42
+
43
+ opts.on('--ends CHARS', 'Start/end characters (even number of chars, split in half)') do |chars|
44
+ options[:ends] = chars
45
+ end
46
+
47
+ opts.separator ''
48
+ opts.separator 'Progress Control:'
49
+
50
+ opts.on('-p', '--percent PERCENT', Float, 'Set progress to percentage (0-100)') do |percent|
51
+ options[:percent] = percent
52
+ end
53
+
54
+ opts.on('--advance', 'Advance progress by one step') do
55
+ options[:advance] = true
56
+ end
57
+
58
+ opts.on('--complete', 'Complete the progress bar') do
59
+ options[:complete] = true
60
+ end
61
+
62
+ opts.on('--cancel', 'Cancel the progress bar') do
63
+ options[:cancel] = true
64
+ end
65
+
66
+ opts.on('--current', 'Show current progress percentage (0-100 float)') do
67
+ options[:current] = true
68
+ end
69
+
70
+ opts.on('--report', 'Show detailed progress report') do
71
+ options[:report] = true
72
+ end
73
+
74
+ opts.separator ''
75
+ opts.separator 'Auto-advance Mode:'
76
+
77
+ opts.on('--speed SPEED', 'Auto-advance speed (fast/medium/slow or numeric)') do |speed|
78
+ options[:speed] = case speed.downcase
79
+ when /^f/ then :fast
80
+ when /^m/ then :medium
81
+ when /^s/ then :slow
82
+ else speed.to_f.positive? ? speed.to_f : :medium
83
+ end
84
+ end
85
+
86
+ opts.separator ''
87
+ opts.separator 'Messages:'
88
+
89
+ opts.on('--success MESSAGE', 'Success message to display on completion') do |msg|
90
+ options[:success_message] = msg
91
+ end
92
+
93
+ opts.on('--error MESSAGE', 'Error message to display on cancellation') do |msg|
94
+ options[:error_message] = msg
95
+ end
96
+
97
+ opts.on('--checkmark', 'Show checkmarks (✅ success, 🛑 failure)') do
98
+ options[:checkmark] = true
99
+ end
100
+
101
+ opts.separator ''
102
+ opts.separator 'Daemon Mode:'
103
+
104
+ opts.on('--daemon', 'Run in background daemon mode') do
105
+ options[:daemon] = true
106
+ end
107
+
108
+ opts.on('--pid-file FILE', 'PID file location (default: /tmp/ruby-progress/fill.pid)') do |file|
109
+ options[:pid_file] = file
110
+ end
111
+
112
+ opts.on('--stop', 'Stop daemon') do
113
+ options[:stop] = true
114
+ end
115
+
116
+ opts.on('--status', 'Show daemon status') do
117
+ options[:status] = true
118
+ end
119
+
120
+ opts.separator ''
121
+ opts.separator 'General:'
122
+
123
+ opts.on('--show-styles', 'Show available fill styles with visual previews') do
124
+ options[:show_styles] = true
125
+ end
126
+
127
+ opts.on('-v', '--version', 'Show version') do
128
+ options[:version] = true
129
+ end
130
+
131
+ opts.on('-h', '--help', 'Show this help') do
132
+ options[:help] = true
133
+ end
134
+ end.parse!
135
+ rescue OptionParser::InvalidOption => e
136
+ warn "Invalid option: #{e.args.first}"
137
+ warn ''
138
+ warn 'Usage: prg fill [options]'
139
+ warn "Run 'prg fill --help' for more information."
140
+ exit 1
141
+ end
142
+
143
+ options
144
+ end
145
+
146
+ def self.help_text
147
+ opts = OptionParser.new
148
+
149
+ opts.banner = 'Usage: prg fill [options]'
150
+ opts.separator ''
151
+ opts.separator 'Progress Bar Options:'
152
+
153
+ opts.on('-l', '--length LENGTH', Integer, 'Progress bar length (default: 20)')
154
+ opts.on('-s', '--style STYLE', 'Progress bar style (blocks, classic, dots, etc. or custom=XY)')
155
+ opts.on('--ends CHARS', 'Start/end characters (even number of chars, split in half)')
156
+
157
+ opts.separator ''
158
+ opts.separator 'Progress Control:'
159
+ opts.on('-p', '--percent PERCENT', Float, 'Set progress to percentage (0-100)')
160
+ opts.on('--advance', 'Advance progress by one step')
161
+ opts.on('--complete', 'Complete the progress bar')
162
+ opts.on('--cancel', 'Cancel the progress bar')
163
+ opts.on('--current', 'Show current progress percentage (0-100 float)')
164
+ opts.on('--report', 'Show detailed progress report')
165
+
166
+ opts.separator ''
167
+ opts.separator 'Auto-advance Mode:'
168
+ opts.on('--speed SPEED', 'Auto-advance speed (fast/medium/slow or numeric)')
169
+
170
+ opts.separator ''
171
+ opts.separator 'Messages:'
172
+ opts.on('--success MESSAGE', 'Success message to display on completion')
173
+ opts.on('--error MESSAGE', 'Error message to display on cancellation')
174
+ opts.on('--checkmark', 'Show checkmarks (✅ success, 🛑 failure)')
175
+
176
+ opts.separator ''
177
+ opts.separator 'Daemon Mode:'
178
+ opts.on('--daemon', 'Run in background daemon mode')
179
+ opts.on('--pid-file FILE', 'PID file location (default: /tmp/ruby-progress/fill.pid)')
180
+ opts.on('--stop', 'Stop daemon')
181
+ opts.on('--status', 'Show daemon status')
182
+
183
+ opts.separator ''
184
+ opts.separator 'General:'
185
+ opts.on('--show-styles', 'Show available fill styles with visual previews')
186
+ opts.on('-v', '--version', 'Show version')
187
+ opts.on('-h', '--help', 'Show this help')
188
+
189
+ opts.to_s
190
+ end
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'fileutils'
4
+ require_relative 'ripple_options'
5
+
6
+ # Enhanced Ripple CLI with unified flags (extracted from bin/prg)
7
+ module RippleCLI
8
+ def self.run
9
+ trap('INT') do
10
+ RubyProgress::Utils.show_cursor
11
+ exit
12
+ end
13
+
14
+ options = RippleCLI::Options.parse_cli_options
15
+
16
+ # Daemon/status/stop handling (process these without requiring text)
17
+ if options[:status]
18
+ pid_file = options[:pid_file] || RubyProgress::Daemon.default_pid_file
19
+ RubyProgress::Daemon.show_status(pid_file)
20
+ exit
21
+ elsif options[:stop]
22
+ pid_file = options[:pid_file] || RubyProgress::Daemon.default_pid_file
23
+ stop_msg = options[:stop_error] || options[:stop_success]
24
+ is_error = !options[:stop_error].nil?
25
+ RubyProgress::Daemon.stop_daemon_by_pid_file(
26
+ pid_file,
27
+ message: stop_msg,
28
+ checkmark: options[:stop_checkmark],
29
+ error: is_error
30
+ )
31
+ exit
32
+ elsif options[:daemon]
33
+ # For daemon mode, detach so shell has no tracked job
34
+ PrgCLI.daemonize
35
+
36
+ # For daemon mode, default message if none provided
37
+ text = options[:message] || ARGV.join(' ')
38
+ text = 'Processing' if text.nil? || text.empty?
39
+ run_daemon_mode(text, options)
40
+ else
41
+ # Non-daemon path requires text
42
+ text = options[:message] || ARGV.join(' ')
43
+ if text.empty?
44
+ puts 'Error: Please provide text to animate via argument or --message flag'
45
+ puts "Example: prg ripple 'Loading...' or prg ripple --message 'Loading...'"
46
+ exit 1
47
+ end
48
+
49
+ # Convert styles array to individual flags for backward compatibility
50
+ options[:rainbow] = options[:styles].include?(:rainbow)
51
+ options[:inverse] = options[:styles].include?(:inverse)
52
+ options[:caps] = options[:styles].include?(:caps)
53
+
54
+ if options[:command]
55
+ run_with_command(text, options)
56
+ else
57
+ run_indefinitely(text, options)
58
+ end
59
+ end
60
+ end
61
+
62
+ def self.run_with_command(text, options)
63
+ captured_output = nil
64
+ RubyProgress::Ripple.progress(text, options) do
65
+ captured_output = `#{options[:command]} 2>&1`
66
+ end
67
+
68
+ success = $CHILD_STATUS.success?
69
+
70
+ puts captured_output if options[:output] == :stdout
71
+ if options[:success_message] || options[:complete_checkmark]
72
+ message = success ? options[:success_message] : options[:fail_message] || options[:success_message]
73
+ RubyProgress::Ripple.complete(text, message, options[:complete_checkmark], success)
74
+ end
75
+ exit success ? 0 : 1
76
+ end
77
+
78
+ def self.run_indefinitely(text, options)
79
+ rippler = RubyProgress::Ripple.new(text, options)
80
+ RubyProgress::Utils.hide_cursor
81
+ begin
82
+ loop { rippler.advance }
83
+ ensure
84
+ RubyProgress::Utils.show_cursor
85
+ RubyProgress::Ripple.complete(text, options[:success_message], options[:complete_checkmark], true)
86
+ end
87
+ end
88
+
89
+ def self.run_daemon_mode(text, options)
90
+ pid_file = options[:pid_file] || RubyProgress::Daemon.default_pid_file
91
+ FileUtils.mkdir_p(File.dirname(pid_file))
92
+ File.write(pid_file, Process.pid.to_s)
93
+
94
+ begin
95
+ # For Ripple, re-use the existing animation loop via a simple loop
96
+ RubyProgress::Utils.hide_cursor
97
+ rippler = RubyProgress::Ripple.new(text, options)
98
+ stop_requested = false
99
+
100
+ Signal.trap('INT') { stop_requested = true }
101
+ Signal.trap('USR1') { stop_requested = true }
102
+ Signal.trap('TERM') { stop_requested = true }
103
+ Signal.trap('HUP') { stop_requested = true }
104
+
105
+ rippler.advance until stop_requested
106
+ ensure
107
+ RubyProgress::Utils.clear_line
108
+ RubyProgress::Utils.show_cursor
109
+
110
+ # If a control message file exists, output its message with optional checkmark
111
+ cmf = RubyProgress::Daemon.control_message_file(pid_file)
112
+ if File.exist?(cmf)
113
+ begin
114
+ data = JSON.parse(File.read(cmf))
115
+ message = data['message']
116
+ check = if data.key?('checkmark')
117
+ data['checkmark'] ? true : false
118
+ else
119
+ false
120
+ end
121
+ success_val = if data.key?('success')
122
+ data['success'] ? true : false
123
+ else
124
+ true
125
+ end
126
+ if message
127
+ RubyProgress::Utils.display_completion(
128
+ message,
129
+ success: success_val,
130
+ show_checkmark: check,
131
+ output_stream: :stdout
132
+ )
133
+ end
134
+ rescue StandardError
135
+ # ignore
136
+ ensure
137
+ begin
138
+ File.delete(cmf)
139
+ rescue StandardError
140
+ nil
141
+ end
142
+ end
143
+ end
144
+
145
+ FileUtils.rm_f(pid_file)
146
+ end
147
+ end
148
+
149
+ # Options parsing moved to ripple_options.rb
150
+ end