command_kit 0.5.5 → 0.6.0
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 +4 -4
- data/.rubocop.yml +3 -0
- data/ChangeLog.md +17 -0
- data/README.md +1 -0
- data/examples/interactive.rb +30 -0
- data/lib/command_kit/inflector.rb +2 -0
- data/lib/command_kit/interactive.rb +87 -0
- data/lib/command_kit/open.rb +104 -0
- data/lib/command_kit/options/verbose_level.rb +87 -0
- data/lib/command_kit/printing/indent.rb +4 -3
- data/lib/command_kit/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5bf3011e0c065be0e6c7fd1da97f0c0de87b80674a29e782c339b63b15384992
|
4
|
+
data.tar.gz: bcad8e0d7ad0113bee65d2c5eda383f300b9764e3a0b53d90752e551299be0d0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c13184c83e668c3afd46ad1ad28a7d78655f1e8602831120ead6f39f2f35f4f6ba08151339e16485ef9111690b7975af4cb6a219787ec3530fb0a822cd2c952
|
7
|
+
data.tar.gz: ba6caee506bb4085cab8a6fe8a389006e0423643a1ee35e1f0a26a2ec0e6fc1f5f53a982f3a8247fefebdf2e6fbf9a3c05afc5d78a1209f8921e1566643e30b8
|
data/.rubocop.yml
CHANGED
@@ -161,3 +161,6 @@ Naming/HeredocDelimiterNaming: { Enabled: false }
|
|
161
161
|
|
162
162
|
# I prefer to use explicit parenthesis for compound logical statements
|
163
163
|
Style/RedundantParentheses: { Enabled: false }
|
164
|
+
|
165
|
+
# I prefer to call `super()` with explicit arguments
|
166
|
+
Style/SuperArguments: { Enabled: false }
|
data/ChangeLog.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
### 0.6.0 / 2024-06-19
|
2
|
+
|
3
|
+
* Added {CommandKit::Interactive#ask_multiline}.
|
4
|
+
* Added {CommandKit::Open}.
|
5
|
+
* Added {CommandKit::Options::VerboseLevel}.
|
6
|
+
|
7
|
+
### 0.5.6 / 2024-06-19
|
8
|
+
|
9
|
+
#### CommandKit::Inflector
|
10
|
+
|
11
|
+
* Fixed {CommandKit::Inflector.camelize} to convert `foo-1234-5678` to
|
12
|
+
`Foo_1234_5678`.
|
13
|
+
|
14
|
+
#### CommandKit::Printing::Indent
|
15
|
+
|
16
|
+
* Micro-optimization to {CommandKit::Printing::Indent#puts}.
|
17
|
+
|
1
18
|
### 0.5.5 / 2024-04-08
|
2
19
|
|
3
20
|
#### CommandKit::Interactive
|
data/README.md
CHANGED
@@ -229,6 +229,7 @@ end
|
|
229
229
|
* [CommandKit::Help::Man](https://rubydoc.info/gems/command_kit/CommandKit/Help/Man)
|
230
230
|
* [CommandKit::Interactive](https://rubydoc.info/gems/command_kit/CommandKit/Interactive)
|
231
231
|
* [CommandKit::Main](https://rubydoc.info/gems/command_kit/CommandKit/Main)
|
232
|
+
* [CommandKit::Open](https://rubydoc.info/gems/command_kit/CommandKit/Open)
|
232
233
|
* [CommandKit::Options](https://rubydoc.info/gems/command_kit/CommandKit/Options)
|
233
234
|
* [CommandKit::Options::Quiet](https://rubydoc.info/gems/command_kit/CommandKit/Options/Quiet)
|
234
235
|
* [CommandKit::Options::Verbose](https://rubydoc.info/gems/command_kit/CommandKit/Options/Verbose)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.expand_path('../../lib',__FILE__))
|
4
|
+
require 'command_kit/command'
|
5
|
+
require 'command_kit/interactive'
|
6
|
+
|
7
|
+
class InteractiveCmd < CommandKit::Command
|
8
|
+
|
9
|
+
include CommandKit::Interactive
|
10
|
+
|
11
|
+
description 'Demonstrates interactive prompt input'
|
12
|
+
|
13
|
+
def run
|
14
|
+
you_entered = ->(result) {
|
15
|
+
puts "You entered: #{result.inspect}"
|
16
|
+
puts
|
17
|
+
}
|
18
|
+
|
19
|
+
you_entered[ask("Single-line input")]
|
20
|
+
you_entered[ask_secret("Secret input")]
|
21
|
+
you_entered[ask_yes_or_no("Yes or no prompt")]
|
22
|
+
you_entered[ask_multiple_choice("Multiple choice", %w[Red Green Blue])]
|
23
|
+
you_entered[ask_multiline('Multi-line comment 1')]
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
if __FILE__ == $0
|
29
|
+
InteractiveCmd.start
|
30
|
+
end
|
@@ -101,6 +101,8 @@ module CommandKit
|
|
101
101
|
if (word = scanner.scan(/[A-Za-z\d]+/))
|
102
102
|
word.capitalize!
|
103
103
|
new_string << word
|
104
|
+
elsif (numbers = scanner.scan(/[_-]\d+/))
|
105
|
+
new_string << "_#{numbers[1..]}"
|
104
106
|
elsif scanner.scan(/[_-]+/)
|
105
107
|
# skip
|
106
108
|
elsif scanner.scan(%r{/})
|
@@ -34,6 +34,15 @@ module CommandKit
|
|
34
34
|
# #
|
35
35
|
# # => "Lime"
|
36
36
|
#
|
37
|
+
# ### Prompt for multi-line input
|
38
|
+
#
|
39
|
+
# ask_multiline('Comment')
|
40
|
+
# # Comment (Press Ctrl^D to exit):
|
41
|
+
# # foo bar
|
42
|
+
# # baz qux
|
43
|
+
# # Ctrl^D
|
44
|
+
# # => "foo bar\nbaz qux\n"
|
45
|
+
#
|
37
46
|
module Interactive
|
38
47
|
include Stdio
|
39
48
|
|
@@ -244,5 +253,83 @@ module CommandKit
|
|
244
253
|
end
|
245
254
|
end
|
246
255
|
|
256
|
+
#
|
257
|
+
# Asks the user for multi-line text input.
|
258
|
+
#
|
259
|
+
# @param [String] prompt
|
260
|
+
# The prompt that will be printed before reading input.
|
261
|
+
#
|
262
|
+
# @param [String, nil] help
|
263
|
+
# Optional help instructions on how to exit from reading.
|
264
|
+
#
|
265
|
+
# @param [String, nil] default
|
266
|
+
# The default value to return if no input is given.
|
267
|
+
#
|
268
|
+
# @param [Boolean] required
|
269
|
+
# Requires non-empty input.
|
270
|
+
#
|
271
|
+
# @param [:double_newline, :ctrl_d] terminator
|
272
|
+
# Indicates how the input should be terminated.
|
273
|
+
# Defaults to `:ctrl_d` which indicates `Ctrl^D`.
|
274
|
+
#
|
275
|
+
# @return [String]
|
276
|
+
# The user input.
|
277
|
+
#
|
278
|
+
# @example
|
279
|
+
# ask_multiline('Comment')
|
280
|
+
# # Comment (Press Ctrl^D to exit):
|
281
|
+
# # foo bar
|
282
|
+
# # baz qux
|
283
|
+
# # Ctrl^D
|
284
|
+
# # => "foo bar\nbaz qux\n"
|
285
|
+
#
|
286
|
+
# @example Terminate input on a double newline:
|
287
|
+
# ask_multiline('Comment', terminator: :double_newline)
|
288
|
+
# # Comment (Enter two empty lines to exit):
|
289
|
+
# # foo bar
|
290
|
+
# # baz qux
|
291
|
+
# #
|
292
|
+
# # => "foo bar\nbaz qux\n"
|
293
|
+
#
|
294
|
+
# @api public
|
295
|
+
#
|
296
|
+
# @since 0.6.0
|
297
|
+
#
|
298
|
+
def ask_multiline(prompt, help: nil,
|
299
|
+
default: nil,
|
300
|
+
required: false,
|
301
|
+
terminator: :ctrl_d)
|
302
|
+
case terminator
|
303
|
+
when :ctrl_d
|
304
|
+
eos = nil
|
305
|
+
help ||= 'Press Ctrl^D to exit'
|
306
|
+
when :double_newline
|
307
|
+
eos = "#{$/}#{$/}"
|
308
|
+
help ||= 'Press Enter twice to exit'
|
309
|
+
else
|
310
|
+
raise(ArgumentError,"invalid terminator: #{terminator.inspect}")
|
311
|
+
end
|
312
|
+
|
313
|
+
prompt = "#{prompt.chomp} (#{help})"
|
314
|
+
prompt << " [#{default}]" if default
|
315
|
+
prompt << ": "
|
316
|
+
|
317
|
+
loop do
|
318
|
+
stdout.puts(prompt)
|
319
|
+
|
320
|
+
value = stdin.gets(eos)
|
321
|
+
value ||= '' # convert nil values (ctrl^D) to an empty String
|
322
|
+
|
323
|
+
if value.empty?
|
324
|
+
if required
|
325
|
+
next
|
326
|
+
else
|
327
|
+
return (default || value)
|
328
|
+
end
|
329
|
+
else
|
330
|
+
return value
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
247
334
|
end
|
248
335
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'stdio'
|
4
|
+
require_relative 'printing'
|
5
|
+
|
6
|
+
module CommandKit
|
7
|
+
#
|
8
|
+
# Adds helper methods for opening files.
|
9
|
+
#
|
10
|
+
# ## Features
|
11
|
+
#
|
12
|
+
# * Prints `No such file or directory` error if the given file does not exist.
|
13
|
+
# * Handles `-` file paths which indicate input should be read from STDIN or
|
14
|
+
# output written to STDOUT.
|
15
|
+
#
|
16
|
+
# ## Examples
|
17
|
+
#
|
18
|
+
# include CommandKit::Open
|
19
|
+
#
|
20
|
+
# def run(path)
|
21
|
+
# open(path) do |file|
|
22
|
+
# # ...
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @since 0.6.0
|
27
|
+
#
|
28
|
+
module Open
|
29
|
+
include Stdio
|
30
|
+
include Printing
|
31
|
+
|
32
|
+
#
|
33
|
+
# Opens a file for reading or writing.
|
34
|
+
#
|
35
|
+
# @param [String] path
|
36
|
+
# The path of the given file. May be `"-"` to indicate that input should
|
37
|
+
# be read from STDINT or output written to STDOUT.
|
38
|
+
#
|
39
|
+
# @param [String] mode
|
40
|
+
# The mode to open the file with.
|
41
|
+
#
|
42
|
+
# @yield [file]
|
43
|
+
# * If the given path is `"-"`.
|
44
|
+
# * and the given mode contains `w` or `a`, then {#stdout} will be
|
45
|
+
# yielded.
|
46
|
+
# * and no mode is given or if the mode contains `r`, then {#stdin} will
|
47
|
+
# be yielded.
|
48
|
+
# * Otherwise, the newly opened file.
|
49
|
+
#
|
50
|
+
# @yieldparam [File, IO] file
|
51
|
+
# The newly opened file, or {#stdin} / {#stdout} if the given path is
|
52
|
+
# `"-"`.
|
53
|
+
#
|
54
|
+
# @return [File, IO, Object]
|
55
|
+
# * If no block is given, the newly opened file, or {#stdin} / {#stdout}
|
56
|
+
# if the given path is `"-"`, will be returned.
|
57
|
+
# * If a block was given, then the return value of the block will be
|
58
|
+
# returned.
|
59
|
+
#
|
60
|
+
# @example Opening a file for reading:
|
61
|
+
# open(path)
|
62
|
+
# # => #<File:...>
|
63
|
+
#
|
64
|
+
# @example Temporarily opening a file for reading:
|
65
|
+
# open(path) do |file|
|
66
|
+
# # ...
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
# @example Opening a file for writing:
|
70
|
+
# open(path,'w')
|
71
|
+
# # => #<File:...>
|
72
|
+
#
|
73
|
+
# @example Temporarily opening a file for writing:
|
74
|
+
# open(path,'w') do |output|
|
75
|
+
# output
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# @api public
|
79
|
+
#
|
80
|
+
# @since 0.6.0
|
81
|
+
#
|
82
|
+
def open(path,mode='r',&block)
|
83
|
+
if path == '-'
|
84
|
+
io = case mode
|
85
|
+
when /[wa]/ then stdout
|
86
|
+
else stdin
|
87
|
+
end
|
88
|
+
|
89
|
+
if block_given?
|
90
|
+
return yield(io)
|
91
|
+
else
|
92
|
+
return io
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
begin
|
97
|
+
File.open(path,mode,&block)
|
98
|
+
rescue Errno::ENOENT
|
99
|
+
print_error "No such file or directory: #{path}"
|
100
|
+
exit(1)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../options'
|
4
|
+
|
5
|
+
module CommandKit
|
6
|
+
module Options
|
7
|
+
#
|
8
|
+
# Defines a `-v`,`--verbose` option that can be specified multiple times to
|
9
|
+
# increase the verbosity level.
|
10
|
+
#
|
11
|
+
# ## Examples
|
12
|
+
#
|
13
|
+
# include CommandKit::Options::VerboseLevel
|
14
|
+
#
|
15
|
+
# def run(*argv)
|
16
|
+
# # ...
|
17
|
+
# case verbose
|
18
|
+
# when 1
|
19
|
+
# puts "verbose output"
|
20
|
+
# when 2
|
21
|
+
# puts " extra verbose output"
|
22
|
+
# end
|
23
|
+
# # ...
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# @since 0.6.0
|
27
|
+
#
|
28
|
+
module VerboseLevel
|
29
|
+
include Options
|
30
|
+
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
#
|
34
|
+
module ModuleMethods
|
35
|
+
#
|
36
|
+
# Defines a `-v, --verbose` option or extends {ModuleMethods}, depending
|
37
|
+
# on whether {Options::Verbose} is being included into a class or a
|
38
|
+
# module.
|
39
|
+
#
|
40
|
+
# @param [Class, Module] context
|
41
|
+
# The class or module including {Verbose}.
|
42
|
+
#
|
43
|
+
def included(context)
|
44
|
+
super(context)
|
45
|
+
|
46
|
+
if context.class == Module
|
47
|
+
context.extend ModuleMethods
|
48
|
+
else
|
49
|
+
context.option :verbose, short: '-v', desc: 'Increases the verbosity level' do
|
50
|
+
@verbose += 1
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
extend ModuleMethods
|
57
|
+
|
58
|
+
# The verbosity level.
|
59
|
+
#
|
60
|
+
# @return [Integer]
|
61
|
+
attr_reader :verbose
|
62
|
+
|
63
|
+
#
|
64
|
+
# Initializes the command and sets {#verbose} to 0.
|
65
|
+
#
|
66
|
+
# @param [Hash{Symbol => Object}] kwargs
|
67
|
+
# Additional keyword arguments.
|
68
|
+
#
|
69
|
+
def initialize(**kwargs)
|
70
|
+
super(**kwargs)
|
71
|
+
|
72
|
+
@verbose = 0
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Determines if verbose mode is enabled.
|
77
|
+
#
|
78
|
+
# @return [Boolean]
|
79
|
+
#
|
80
|
+
# @api public
|
81
|
+
#
|
82
|
+
def verbose?
|
83
|
+
@verbose > 0
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -26,6 +26,7 @@ module CommandKit
|
|
26
26
|
#
|
27
27
|
def initialize(**kwargs)
|
28
28
|
@indent = 0
|
29
|
+
@indent_padding = String.new
|
29
30
|
|
30
31
|
super(**kwargs)
|
31
32
|
end
|
@@ -71,8 +72,10 @@ module CommandKit
|
|
71
72
|
|
72
73
|
begin
|
73
74
|
@indent += n
|
75
|
+
@indent_padding << (' ' * n)
|
74
76
|
yield
|
75
77
|
ensure
|
78
|
+
@indent_padding.slice!(original_indent,n)
|
76
79
|
@indent = original_indent
|
77
80
|
end
|
78
81
|
else
|
@@ -90,9 +93,7 @@ module CommandKit
|
|
90
93
|
#
|
91
94
|
def puts(*lines)
|
92
95
|
if (@indent > 0 && !lines.empty?)
|
93
|
-
|
94
|
-
|
95
|
-
super(*lines.map { |line| "#{padding}#{line}" })
|
96
|
+
super(*lines.map { |line| "#{@indent_padding}#{line}" })
|
96
97
|
else
|
97
98
|
super(*lines)
|
98
99
|
end
|
data/lib/command_kit/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: command_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Postmodern
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-06-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -48,6 +48,7 @@ files:
|
|
48
48
|
- command_kit.gemspec
|
49
49
|
- examples/colors.rb
|
50
50
|
- examples/command.rb
|
51
|
+
- examples/interactive.rb
|
51
52
|
- examples/pager.rb
|
52
53
|
- examples/printing/tables.rb
|
53
54
|
- examples/subcommands/cli.rb
|
@@ -90,6 +91,7 @@ files:
|
|
90
91
|
- lib/command_kit/interactive.rb
|
91
92
|
- lib/command_kit/main.rb
|
92
93
|
- lib/command_kit/man.rb
|
94
|
+
- lib/command_kit/open.rb
|
93
95
|
- lib/command_kit/open_app.rb
|
94
96
|
- lib/command_kit/options.rb
|
95
97
|
- lib/command_kit/options/option.rb
|
@@ -97,6 +99,7 @@ files:
|
|
97
99
|
- lib/command_kit/options/parser.rb
|
98
100
|
- lib/command_kit/options/quiet.rb
|
99
101
|
- lib/command_kit/options/verbose.rb
|
102
|
+
- lib/command_kit/options/verbose_level.rb
|
100
103
|
- lib/command_kit/options/version.rb
|
101
104
|
- lib/command_kit/os.rb
|
102
105
|
- lib/command_kit/os/linux.rb
|
@@ -144,7 +147,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
147
|
- !ruby/object:Gem::Version
|
145
148
|
version: '0'
|
146
149
|
requirements: []
|
147
|
-
rubygems_version: 3.
|
150
|
+
rubygems_version: 3.5.9
|
148
151
|
signing_key:
|
149
152
|
specification_version: 4
|
150
153
|
summary: An all-in-one modular Ruby CLI toolkit
|