ruby-progress 1.0.1

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.
data/bin/prg ADDED
@@ -0,0 +1,311 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/ruby-progress'
5
+ require 'optparse'
6
+
7
+ # Unified progress indicator CLI
8
+ module PrgCLI
9
+ def self.run
10
+ if ARGV.empty?
11
+ show_help
12
+ exit 1
13
+ end
14
+
15
+ subcommand = ARGV.shift.downcase
16
+
17
+ case subcommand
18
+ when 'ripple'
19
+ RippleCLI.run
20
+ when 'worm'
21
+ WormCLI.run
22
+ when '-v', '--version'
23
+ puts "prg version #{RubyProgress::VERSION}"
24
+ puts " ripple - Text ripple animation with spinners and effects"
25
+ puts " worm - Unicode wave animation with customizable styles"
26
+ exit
27
+ when '-h', '--help', 'help'
28
+ show_help
29
+ exit
30
+ else
31
+ puts "Error: Unknown subcommand '#{subcommand}'"
32
+ puts "Run 'prg --help' for usage information."
33
+ exit 1
34
+ end
35
+ end
36
+
37
+ def self.show_help
38
+ puts <<~HELP
39
+ prg - Unified Ruby Progress Indicators
40
+
41
+ USAGE:
42
+ prg <subcommand> [options]
43
+
44
+ SUBCOMMANDS:
45
+ ripple Text ripple animation with spinners and color effects
46
+ worm Unicode wave animation with customizable dot styles
47
+
48
+ GLOBAL OPTIONS:
49
+ -v, --version Show version information
50
+ -h, --help Show this help message
51
+
52
+ EXAMPLES:
53
+ prg ripple "Loading..." --rainbow --speed fast
54
+ prg worm --message "Processing" --style blocks --checkmark
55
+ prg ripple --command "sleep 3" --success "Done!" --checkmark
56
+
57
+ Run 'prg <subcommand> --help' for specific subcommand options.
58
+ HELP
59
+ end
60
+ end
61
+
62
+ # Enhanced Ripple CLI with unified flags
63
+ module RippleCLI
64
+ def self.run
65
+ trap('INT') do
66
+ RubyProgress::Utils.show_cursor
67
+ exit
68
+ end
69
+
70
+ options = {
71
+ speed: :medium,
72
+ direction: :bidirectional,
73
+ rainbow: false,
74
+ spinner: false,
75
+ spinner_position: :before,
76
+ caps: false,
77
+ inverse: false,
78
+ command: nil,
79
+ success_message: nil,
80
+ fail_message: nil,
81
+ complete_checkmark: false,
82
+ output: :error,
83
+ message: nil # For unified interface
84
+ }
85
+
86
+ OptionParser.new do |opts|
87
+ opts.banner = 'Usage: prg ripple [options] [STRING]'
88
+ opts.separator ''
89
+ opts.separator 'Animation Options:'
90
+
91
+ opts.on('-s', '--speed SPEED', 'Animation speed (fast/medium/slow or f/m/s)') do |s|
92
+ options[:speed] = case s.downcase
93
+ when /^f/ then :fast
94
+ when /^m/ then :medium
95
+ when /^s/ then :slow
96
+ else :medium
97
+ end
98
+ end
99
+
100
+ opts.on('-m', '--message MESSAGE', 'Message to display (alternative to positional argument)') do |msg|
101
+ options[:message] = msg
102
+ end
103
+
104
+ opts.on('-r', '--rainbow', 'Enable rainbow color mode') do
105
+ options[:rainbow] = true
106
+ end
107
+
108
+ opts.on('-d', '--direction DIRECTION', 'Animation direction (forward/bidirectional or f/b)') do |f|
109
+ options[:format] = f =~ /^f/i ? :forward_only : :bidirectional
110
+ end
111
+
112
+ opts.on('-i', '--inverse', 'Enable inverse highlighting mode') do
113
+ options[:inverse] = true
114
+ end
115
+
116
+ opts.separator ''
117
+ opts.separator 'Spinner Options:'
118
+
119
+ opts.on('--spinner TYPE', 'Use spinner animation instead of text ripple') do |type|
120
+ options[:spinner] = type.normalize_type
121
+ end
122
+
123
+ opts.on('--spinner-pos POSITION', 'Spinner position (before/after or b/a)') do |pos|
124
+ options[:spinner_position] = pos =~ /^a/i ? :after : :before
125
+ end
126
+
127
+ opts.on('--caps', 'Enable case transformation mode') do
128
+ options[:caps] = true
129
+ end
130
+
131
+ opts.on('--list-spinners', 'List all available spinner types') do
132
+ show_spinners
133
+ exit
134
+ end
135
+
136
+ opts.separator ''
137
+ opts.separator 'Command Execution:'
138
+
139
+ opts.on('-c', '--command COMMAND', 'Run command during animation (optional)') do |command|
140
+ options[:command] = command
141
+ end
142
+
143
+ opts.on('--success MESSAGE', 'Success message to display') do |msg|
144
+ options[:success_message] = msg
145
+ end
146
+
147
+ opts.on('--error MESSAGE', 'Error message to display') do |msg|
148
+ options[:fail_message] = msg
149
+ end
150
+
151
+ opts.on('--checkmark', 'Show checkmarks (✅ success, 🛑 failure)') do
152
+ options[:complete_checkmark] = true
153
+ end
154
+
155
+ opts.on('--stdout', 'Output captured command result to STDOUT') do
156
+ options[:output] = :stdout
157
+ end
158
+
159
+ opts.on('--quiet', 'Suppress all output') do
160
+ options[:output] = :quiet
161
+ end
162
+
163
+ opts.separator ''
164
+ opts.separator 'General:'
165
+
166
+ opts.on('-v', '--version', 'Show version') do
167
+ puts "Ripple version #{RubyProgress::VERSION}"
168
+ exit
169
+ end
170
+
171
+ opts.on('-h', '--help', 'Show this help') do
172
+ puts opts
173
+ exit
174
+ end
175
+ end.parse!
176
+
177
+ # Get text from positional argument or --message flag
178
+ text = options[:message] || ARGV.join(' ')
179
+
180
+ if text.empty?
181
+ puts 'Error: Please provide text to animate via argument or --message flag'
182
+ puts "Example: prg ripple 'Loading...' or prg ripple --message 'Loading...'"
183
+ exit 1
184
+ end
185
+
186
+ if options[:command]
187
+ run_with_command(text, options)
188
+ else
189
+ run_indefinitely(text, options)
190
+ end
191
+ end
192
+
193
+ def self.show_spinners
194
+ puts "Available spinners:"
195
+ RubyProgress::INDICATORS.each do |name, chars|
196
+ puts " #{name.to_s.ljust(15)} #{chars[0..2].join(' ')}"
197
+ end
198
+ end
199
+
200
+ def self.run_with_command(text, options)
201
+ captured_output = nil
202
+ RubyProgress::Ripple.progress(text, options) do
203
+ captured_output = `#{options[:command]} 2>&1`
204
+ end
205
+
206
+ success = $?.success?
207
+
208
+ if options[:output] == :stdout
209
+ puts captured_output
210
+ end
211
+ if options[:success_message] || options[:complete_checkmark]
212
+ message = success ? options[:success_message] : options[:fail_message] || options[:success_message]
213
+ RubyProgress::Ripple.complete(text, message, options[:complete_checkmark], success)
214
+ end
215
+ exit success ? 0 : 1
216
+ end
217
+
218
+ def self.run_indefinitely(text, options)
219
+ rippler = RubyProgress::Ripple.new(text, options)
220
+ RubyProgress::Utils.hide_cursor
221
+ begin
222
+ while true
223
+ rippler.advance
224
+ end
225
+ ensure
226
+ RubyProgress::Utils.show_cursor
227
+ RubyProgress::Ripple.complete(text, options[:success_message], options[:complete_checkmark], true)
228
+ end
229
+ end
230
+ end
231
+
232
+ # Enhanced Worm CLI with unified flags
233
+ module WormCLI
234
+ def self.run
235
+ options = parse_cli_options
236
+
237
+ progress = RubyProgress::Worm.new(options)
238
+
239
+ if options[:command]
240
+ progress.run_with_command
241
+ else
242
+ progress.run_indefinitely
243
+ end
244
+ end
245
+
246
+ def self.parse_cli_options
247
+ options = {}
248
+
249
+ OptionParser.new do |opts|
250
+ opts.banner = 'Usage: prg worm [options]'
251
+ opts.separator ''
252
+ opts.separator 'Animation Options:'
253
+
254
+ opts.on('-s', '--speed SPEED', 'Animation speed (1-10, fast/medium/slow, or f/m/s)') do |speed|
255
+ options[:speed] = speed
256
+ end
257
+
258
+ opts.on('-m', '--message MESSAGE', 'Message to display before animation') do |message|
259
+ options[:message] = message
260
+ end
261
+
262
+ opts.on('-l', '--length LENGTH', Integer, 'Number of dots to display') do |length|
263
+ options[:length] = length
264
+ end
265
+
266
+ opts.on('--style STYLE', 'Animation style (circles/blocks/geometric or c/b/g)') do |style|
267
+ options[:style] = style
268
+ end
269
+
270
+ opts.separator ''
271
+ opts.separator 'Command Execution:'
272
+
273
+ opts.on('-c', '--command COMMAND', 'Command to run (optional - runs indefinitely without)') do |command|
274
+ options[:command] = command
275
+ end
276
+
277
+ opts.on('--success MESSAGE', 'Success message to display') do |text|
278
+ options[:success] = text
279
+ end
280
+
281
+ opts.on('--error MESSAGE', 'Error message to display') do |text|
282
+ options[:error] = text
283
+ end
284
+
285
+ opts.on('--checkmark', 'Show checkmarks (✅ success, 🛑 failure)') do
286
+ options[:checkmark] = true
287
+ end
288
+
289
+ opts.on('--stdout', 'Output captured command result to STDOUT') do
290
+ options[:stdout] = true
291
+ end
292
+
293
+ opts.separator ''
294
+ opts.separator 'General:'
295
+
296
+ opts.on('-v', '--version', 'Show version') do
297
+ puts "Worm version #{RubyProgress::VERSION}"
298
+ exit
299
+ end
300
+
301
+ opts.on('-h', '--help', 'Show this help') do
302
+ puts opts
303
+ exit
304
+ end
305
+ end.parse!
306
+
307
+ options
308
+ end
309
+ end
310
+
311
+ PrgCLI.run if __FILE__ == $PROGRAM_NAME
data/bin/ripple ADDED
@@ -0,0 +1,147 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/ruby-progress'
5
+ require 'optparse'
6
+
7
+ # Ripple CLI implementation
8
+ module RippleCLI
9
+ def self.run
10
+ trap('INT') do
11
+ RubyProgress::Utils.show_cursor
12
+ exit
13
+ end
14
+
15
+ options = {
16
+ speed: :medium,
17
+ direction: :bidirectional,
18
+ rainbow: false,
19
+ spinner: false,
20
+ spinner_position: :before,
21
+ caps: false,
22
+ inverse: false,
23
+ command: nil,
24
+ success_message: nil,
25
+ fail_message: nil,
26
+ complete_checkmark: false
27
+ }
28
+
29
+ OptionParser.new do |opts|
30
+ opts.banner = 'Usage: ripple [options] STRING'
31
+
32
+ opts.on('-s', '--speed SPEED', %i[fast medium slow], 'Set animation speed ((f)ast/(m)edium/(s)low)') do |s|
33
+ options[:speed] = case s
34
+ when /^f/ then :fast
35
+ when /^m/ then :medium
36
+ when /^s/ then :slow
37
+ else :slow
38
+ end
39
+ end
40
+
41
+ opts.on('-r', '--rainbow', 'Enable rainbow mode') do
42
+ options[:rainbow] = true
43
+ end
44
+
45
+ opts.on('-d', '--direction DIRECTION', 'Set animation format ((f)orward/(b)ack-and-forth)') do |f|
46
+ options[:format] = f =~ /^f/ ? :forward_only : :bidirectional
47
+ end
48
+
49
+ opts.on('-i', '--inverse', 'Enable inverse mode') do
50
+ options[:inverse] = true
51
+ end
52
+
53
+ opts.on('-c', '--command COMMAND', 'Run a command during the animation') do |command|
54
+ options[:command] = command
55
+ end
56
+
57
+ opts.on('--success MESSAGE', 'Message to display on success') do |msg|
58
+ options[:success_message] = msg
59
+ end
60
+
61
+ opts.on('--fail MESSAGE', 'Message to display on error') do |msg|
62
+ options[:fail_message] = msg
63
+ end
64
+
65
+ opts.on('--checkmark') do
66
+ options[:complete_checkmark] = true
67
+ end
68
+
69
+ opts.on('--spinner TYPE', 'Display a rippling spinner with the message') do |type|
70
+ options[:spinner] = type.normalize_type
71
+ end
72
+
73
+ opts.on('--spinner-pos POSITION', 'Display spinner [b]efore or [a]fter message') do |pos|
74
+ options[:spinner_position] = pos =~ /^a/ ? :after : :before
75
+ end
76
+
77
+ opts.on('--list-spinners', 'List available spinners') do
78
+ out = "Spinners:\n"
79
+ RubyProgress::INDICATORS.each do |k, v|
80
+ out += "- #{k}: #{v[2]}\n"
81
+ end
82
+ puts out
83
+ exit
84
+ end
85
+
86
+ opts.on('--caps') do
87
+ options[:caps] = true
88
+ end
89
+
90
+ opts.on('--stdout', 'Output captured command result to STDOUT') do |_output|
91
+ options[:output] = :stdout
92
+ end
93
+
94
+ opts.on('--quiet', 'Suppress all output') do |_quiet|
95
+ options[:output] = :quiet
96
+ end
97
+
98
+ opts.on('-v', '--version', 'Display the version') do
99
+ puts "Ripple version #{RubyProgress::VERSION}"
100
+ exit
101
+ end
102
+
103
+ opts.on('-h', '--help', 'Display this help message') do
104
+ puts opts
105
+ exit
106
+ end
107
+ end.parse!
108
+
109
+ if ARGV.empty?
110
+ puts 'Please provide a string to animate as an argument.'
111
+ exit 1
112
+ end
113
+
114
+ if options[:command]
115
+ captured_output = nil
116
+ res = RubyProgress::Ripple.progress(ARGV.join(' '), options) do
117
+ captured_output = `#{options[:command]} 2>&1`
118
+ end
119
+
120
+ res = $?.success?
121
+
122
+ puts captured_output if options[:output] == :stdout
123
+ if options[:success_message]
124
+ message = if res
125
+ options[:success_message]
126
+ else
127
+ options[:fail_message] || options[:success_message]
128
+ end
129
+ RubyProgress::Ripple.complete(ARGV.join(' '), message, options[:complete_checkmark], res)
130
+ end
131
+ exit res ? 0 : 1
132
+ end
133
+
134
+ rippler = RubyProgress::Ripple.new(ARGV.join(' '), {
135
+ speed: options[:speed],
136
+ format: options[:format],
137
+ rainbow: options[:rainbow],
138
+ inverse: options[:inverse]
139
+ })
140
+ RubyProgress::Utils.hide_cursor
141
+ rippler.advance while true
142
+ RubyProgress::Utils.show_cursor
143
+ RubyProgress::Ripple.complete(ARGV.join(' '), options[:success_message], options[:complete_checkmark], true)
144
+ end
145
+ end
146
+
147
+ RippleCLI.run if __FILE__ == $PROGRAM_NAME
data/bin/worm ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/ruby-progress'
5
+ require 'optparse'
6
+
7
+ # Worm CLI implementation
8
+ module WormCLI
9
+ def self.run
10
+ options = parse_cli_options
11
+ progress = RubyProgress::Worm.new(options)
12
+
13
+ if options[:command]
14
+ progress.run_with_command
15
+ else
16
+ # Run indefinitely like ripple does when no command is specified
17
+ progress.run_indefinitely
18
+ end
19
+ end
20
+
21
+ def self.parse_cli_options
22
+ options = {}
23
+
24
+ OptionParser.new do |opts|
25
+ opts.banner = "Usage: #{$PROGRAM_NAME} [options]"
26
+ opts.separator ''
27
+ opts.separator 'Options:'
28
+
29
+ opts.on('-s', '--speed SPEED', 'Animation speed (1-10, fast, medium, slow, or f/m/s)') do |speed|
30
+ options[:speed] = speed
31
+ end
32
+
33
+ opts.on('-l', '--length LENGTH', Integer, 'Number of dots to display') do |length|
34
+ options[:length] = length
35
+ end
36
+
37
+ opts.on('-m', '--message MESSAGE', 'Message to display before dots') do |message|
38
+ options[:message] = message
39
+ end
40
+
41
+ opts.on('--style STYLE', 'Animation style (blocks, geometric, circles, or b/g/c)') do |style|
42
+ options[:style] = style
43
+ end
44
+
45
+ opts.on('-c', '--command COMMAND', 'Command to run (optional - runs indefinitely without command)') do |command|
46
+ options[:command] = command
47
+ end
48
+
49
+ opts.on('--success TEXT', 'Text to display on successful completion') do |text|
50
+ options[:success] = text
51
+ end
52
+
53
+ opts.on('--error TEXT', 'Text to display on error') do |text|
54
+ options[:error] = text
55
+ end
56
+
57
+ opts.on('--checkmark', 'Show checkmarks (✅/🛑) in completion messages') do
58
+ options[:checkmark] = true
59
+ end
60
+
61
+ opts.on('--stdout', 'Output captured command result to STDOUT') do
62
+ options[:stdout] = true
63
+ end
64
+
65
+ opts.on('-h', '--help', 'Show this help message') do
66
+ puts opts
67
+ exit
68
+ end
69
+
70
+ opts.on('-v', '--version', 'Display the version') do
71
+ puts "Worm version #{RubyProgress::VERSION}"
72
+ exit
73
+ end
74
+ end.parse!
75
+
76
+ options
77
+ end
78
+ end
79
+
80
+ WormCLI.run if __FILE__ == $PROGRAM_NAME
data/demo_gem.rb ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Demo script showing gem functionality for CI/CD validation
5
+
6
+ puts '🚀 Ruby Progress Gem Demo'
7
+ puts '========================='
8
+ puts
9
+
10
+ # Test library loading
11
+ begin
12
+ require 'ruby-progress'
13
+ puts '✅ Library loaded successfully'
14
+ puts "📦 Version: #{RubyProgress::VERSION}"
15
+ rescue LoadError => e
16
+ puts "❌ Failed to load library: #{e.message}"
17
+ exit 1
18
+ end
19
+
20
+ puts
21
+
22
+ # Test Ripple class
23
+ begin
24
+ puts '🌊 Testing Ripple class...'
25
+ ripple = RubyProgress::Ripple.new('Demo Test')
26
+ puts '✅ Ripple class instantiated successfully'
27
+ rescue StandardError => e
28
+ puts "❌ Ripple test failed: #{e.message}"
29
+ exit 1
30
+ end
31
+
32
+ # Test Worm class
33
+ begin
34
+ puts '🐛 Testing Worm class...'
35
+ worm = RubyProgress::Worm.new(message: 'Demo Test')
36
+ puts '✅ Worm class instantiated successfully'
37
+ rescue StandardError => e
38
+ puts "❌ Worm test failed: #{e.message}"
39
+ exit 1
40
+ end
41
+
42
+ puts
43
+ puts '🎉 All tests passed! The gem is working correctly.'
44
+ puts
45
+ puts '📊 Key Features Verified:'
46
+ puts ' • Library structure and loading'
47
+ puts ' • Version management'
48
+ puts ' • Ripple and Worm class instantiation'
49
+ puts ' • Module namespacing'
50
+ puts
51
+ puts '🔗 Ready for badge display:'
52
+ puts ' • RubyGems version badge'
53
+ puts ' • MIT license badge'
54
+ puts ' • GitHub Actions test badge'
55
+ puts ' • Ruby version compatibility badge'
56
+ puts ' • Test coverage badge'
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Demo script showing worm.rb's new infinite mode
5
+
6
+ puts '=== Worm.rb Infinite Mode Demo ==='
7
+ puts
8
+
9
+ puts '1. Running indefinitely for 3 seconds (like ripple):'
10
+ system("timeout 3s ruby worm.rb --message 'Loading...' --speed fast --style circles || echo")
11
+ puts
12
+
13
+ puts '2. Running with command and checkmarks:'
14
+ system("ruby worm.rb --command 'sleep 1 && echo Success' --message 'Processing' --success 'Done!' --checkmark --stdout")
15
+ puts
16
+
17
+ puts '3. Running indefinitely with blocks style:'
18
+ system("timeout 2s ruby worm.rb --message 'Working' --style blocks --length 6 --speed medium || echo")
19
+ puts
20
+
21
+ puts 'Demo complete! Worm.rb now works like ripple when no command is specified.'
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Demo of RubyProgress::Utils universal utilities
5
+ require_relative '../lib/ruby-progress'
6
+
7
+ puts "=== RubyProgress::Utils Demo ==="
8
+ puts
9
+
10
+ # Test cursor control
11
+ puts "Testing cursor control..."
12
+ print "Hiding cursor for 2 seconds..."
13
+ RubyProgress::Utils.hide_cursor
14
+ sleep 2
15
+ print " showing cursor again."
16
+ RubyProgress::Utils.show_cursor
17
+ puts
18
+ puts
19
+
20
+ # Test line clearing
21
+ puts "Testing line clearing..."
22
+ print "This line will be cleared..."
23
+ sleep 1
24
+ RubyProgress::Utils.clear_line
25
+ print "New content on the same line!"
26
+ puts
27
+ puts
28
+
29
+ # Test completion messages
30
+ puts "Testing completion messages..."
31
+
32
+ RubyProgress::Utils.display_completion("Basic success message", success: true)
33
+ RubyProgress::Utils.display_completion("Basic failure message", success: false)
34
+
35
+ puts
36
+ puts "With checkmarks:"
37
+ RubyProgress::Utils.display_completion("Success with checkmark", success: true, show_checkmark: true)
38
+ RubyProgress::Utils.display_completion("Failure with checkmark", success: false, show_checkmark: true)
39
+
40
+ puts
41
+ puts "Different output streams:"
42
+ RubyProgress::Utils.display_completion("To STDOUT", success: true, show_checkmark: true, output_stream: :stdout)
43
+ RubyProgress::Utils.display_completion("To STDERR", success: false, show_checkmark: true, output_stream: :stderr)
44
+
45
+ puts
46
+ puts "Complete with clear:"
47
+ print "Content to be cleared and replaced..."
48
+ sleep 1
49
+ RubyProgress::Utils.complete_with_clear("Cleared and completed!", success: true, show_checkmark: true, output_stream: :stdout)
50
+
51
+ puts
52
+ puts "=== Demo Complete ==="