bogo-cli 0.2.18 → 0.3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/CONTRIBUTING.md +10 -14
- data/LICENSE +2 -2
- data/bogo-cli.gemspec +2 -3
- data/lib/bogo-cli/command.rb +26 -25
- data/lib/bogo-cli/parser.rb +384 -0
- data/lib/bogo-cli/setup.rb +8 -27
- data/lib/bogo-cli/version.rb +1 -1
- data/lib/bogo-cli.rb +2 -7
- metadata +8 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3d995cac00e17670f4b08c185c248f79a5bc4da9dfd99f5cd3ee38740c37045
|
4
|
+
data.tar.gz: c381604451c5b15fc8d2d521ed4dee69e52b73684895f8c94827d3f30db71ca1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b27998591ca5eeef1eacb675d53232028328b11d28164eb93563c0fe37ec1464333d3ad002a13a8304e602b02e3d6eecf5a3e463ae0232f7744e780af5158293
|
7
|
+
data.tar.gz: 1c2faafec7efb8f6cc1f17f188b903ee2ebca11ba30ce040244e1c292cc0dc07474cf5a53d9b794cc078c4d6685a0d383282614c95b6dfdfcbc0713eed2f0350
|
data/CHANGELOG.md
CHANGED
data/CONTRIBUTING.md
CHANGED
@@ -1,22 +1,18 @@
|
|
1
1
|
# Contributing
|
2
2
|
|
3
|
-
##
|
3
|
+
## Fixes
|
4
4
|
|
5
|
-
|
5
|
+
Have a fix to some bug you want to submit? Well you're
|
6
|
+
awesome. Please just include a description of the bug
|
7
|
+
(or link to originating issue) and test coverage on the
|
8
|
+
modifications.
|
6
9
|
|
7
|
-
|
10
|
+
## New Features
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
## Pull requests
|
14
|
-
|
15
|
-
* https://github.com/spox/bogo-cli/pulls
|
16
|
-
|
17
|
-
Please base all pull requests of the `develop` branch. Merges to
|
18
|
-
`master` only occur through the `develop` branch. Pull requests
|
19
|
-
based on `master` will likely be cherry picked.
|
12
|
+
Have a new feature you want to add? Well you're awesome
|
13
|
+
too! It may be a good idea to submit an issue first to
|
14
|
+
describe the desired feature and get any feedback. Please
|
15
|
+
be sure to include tests.
|
20
16
|
|
21
17
|
## Issues
|
22
18
|
|
data/LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright
|
1
|
+
Copyright 2022 Chris Roberts
|
2
2
|
|
3
3
|
Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
you may not use this file except in compliance with the License.
|
@@ -10,4 +10,4 @@
|
|
10
10
|
distributed under the License is distributed on an "AS IS" BASIS,
|
11
11
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
12
|
See the License for the specific language governing permissions and
|
13
|
-
limitations under the License.
|
13
|
+
limitations under the License.
|
data/bogo-cli.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__)) + "/lib/"
|
2
|
-
require "bogo-cli
|
2
|
+
require "bogo-cli"
|
3
3
|
Gem::Specification.new do |s|
|
4
4
|
s.name = "bogo-cli"
|
5
5
|
s.version = Bogo::Cli::VERSION.version
|
@@ -13,8 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.add_runtime_dependency "bogo", ">= 0.2.14", "< 0.6"
|
14
14
|
s.add_runtime_dependency "bogo-config", ">= 0.1.15", "< 0.5"
|
15
15
|
s.add_runtime_dependency "bogo-ui"
|
16
|
-
s.
|
17
|
-
s.add_development_dependency "rake", "~> 10"
|
16
|
+
s.add_development_dependency "rake"
|
18
17
|
s.add_development_dependency "minitest"
|
19
18
|
s.files = Dir["lib/**/*"] + %w(bogo-cli.gemspec README.md CHANGELOG.md CONTRIBUTING.md LICENSE)
|
20
19
|
end
|
data/lib/bogo-cli/command.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
require "bogo"
|
1
2
|
require "bogo-ui"
|
2
3
|
require "bogo-config"
|
3
|
-
require "
|
4
|
+
require "ostruct"
|
4
5
|
|
5
6
|
module Bogo
|
6
7
|
module Cli
|
@@ -30,21 +31,25 @@ module Bogo
|
|
30
31
|
#
|
31
32
|
# @return [self]
|
32
33
|
def initialize(cli_opts, args)
|
33
|
-
|
34
|
+
@defaults = Smash.new
|
35
|
+
@options = Smash.new
|
36
|
+
case cli_opts
|
37
|
+
when Bogo::Cli::Parser::OptionValues
|
34
38
|
process_cli_options(cli_opts)
|
39
|
+
when Bogo::Cli::Parser::Command
|
40
|
+
@options = cli_opts.parse(args).first
|
35
41
|
else
|
36
|
-
@
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
+
@options = cli_opts.to_h.to_smash(:snake)
|
43
|
+
end
|
44
|
+
[@options, *@options.values].compact.each do |hsh|
|
45
|
+
next unless hsh.is_a?(Hash)
|
46
|
+
hsh.delete_if { |k, v| v.nil? }
|
42
47
|
end
|
43
48
|
@arguments = validate_arguments!(args)
|
44
49
|
load_config!
|
45
50
|
ui_args = Smash.new(
|
46
51
|
:app_name => options.fetch(:app_name,
|
47
|
-
|
52
|
+
self.class.name.split("::").first),
|
48
53
|
).merge(config)
|
49
54
|
@ui = options.delete(:ui) || Ui.new(ui_args)
|
50
55
|
Bogo::Cli::Command.ui(ui)
|
@@ -89,7 +94,7 @@ module Bogo
|
|
89
94
|
),
|
90
95
|
Hash.new
|
91
96
|
).map { |k, v|
|
92
|
-
unless
|
97
|
+
unless v.nil?
|
93
98
|
[k, v]
|
94
99
|
end
|
95
100
|
}.compact
|
@@ -101,16 +106,16 @@ module Bogo
|
|
101
106
|
#
|
102
107
|
# @return [Hash]
|
103
108
|
def load_config!
|
104
|
-
if
|
109
|
+
if options[:config]
|
105
110
|
config_inst = Config.new(options[:config])
|
106
|
-
elsif
|
111
|
+
elsif self.class.const_defined?(:DEFAULT_CONFIGURATION_FILES)
|
107
112
|
path = self.class.const_get(:DEFAULT_CONFIGURATION_FILES).detect do |check|
|
108
113
|
full_check = File.expand_path(check)
|
109
114
|
File.exists?(full_check)
|
110
115
|
end
|
111
116
|
config_inst = Config.new(path) if path
|
112
117
|
end
|
113
|
-
if
|
118
|
+
if config_inst
|
114
119
|
options.delete(:config)
|
115
120
|
defaults_inst = Smash[
|
116
121
|
config_class.new(
|
@@ -165,7 +170,7 @@ module Bogo
|
|
165
170
|
begin
|
166
171
|
result = yield
|
167
172
|
ui.puts ui.color("complete!", :green, :bold)
|
168
|
-
if
|
173
|
+
if result
|
169
174
|
ui.puts "---> Results:"
|
170
175
|
case result
|
171
176
|
when Hash
|
@@ -190,18 +195,14 @@ module Bogo
|
|
190
195
|
# @param cli_opts [Slop]
|
191
196
|
# @return [NilClass]
|
192
197
|
def process_cli_options(cli_opts)
|
193
|
-
unless (cli_opts.is_a?(Slop))
|
194
|
-
raise TypeError.new "Expecting type `Slop` but received type `#{cli_opts.class}`"
|
195
|
-
end
|
196
198
|
@options = Smash.new
|
197
199
|
@defaults = Smash.new
|
198
|
-
cli_opts.
|
199
|
-
unless
|
200
|
-
|
201
|
-
|
202
|
-
@defaults[opt_key] = cli_opt.value
|
200
|
+
cli_opts.each_pair do |key, value|
|
201
|
+
unless value.nil?
|
202
|
+
if cli_opts.default?(key)
|
203
|
+
@defaults[key] = value
|
203
204
|
else
|
204
|
-
@options[
|
205
|
+
@options[key] = value
|
205
206
|
end
|
206
207
|
end
|
207
208
|
end
|
@@ -216,11 +217,11 @@ module Bogo
|
|
216
217
|
chk_idx = list.find_index do |item|
|
217
218
|
item.start_with?("-")
|
218
219
|
end
|
219
|
-
if
|
220
|
+
if chk_idx
|
220
221
|
marker = list.find_index do |item|
|
221
222
|
item == "--"
|
222
223
|
end
|
223
|
-
if
|
224
|
+
if marker.nil? || chk_idx.to_i < marker
|
224
225
|
raise ArgumentError.new "Unknown CLI option provided `#{list[chk_idx]}`"
|
225
226
|
end
|
226
227
|
end
|
@@ -0,0 +1,384 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'optparse'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
module Bogo
|
6
|
+
module Cli
|
7
|
+
# Parser for CLI arguments
|
8
|
+
class Parser
|
9
|
+
# @return [Symbol] represent unset value
|
10
|
+
UNSET = :__unset__
|
11
|
+
|
12
|
+
class OptionValues
|
13
|
+
extend Forwardable
|
14
|
+
|
15
|
+
NONFORWARDABLE = [:is_a?, :respond_to?, :object_id, :inspect, :keys, :to_s, :[]=].freeze
|
16
|
+
|
17
|
+
Smash.public_instance_methods.each do |ifunc|
|
18
|
+
next if ifunc.to_s.start_with?("_") || NONFORWARDABLE.include?(ifunc)
|
19
|
+
def_delegator :composite, ifunc
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@defaults = Smash.new
|
24
|
+
@sets = Smash.new
|
25
|
+
end
|
26
|
+
|
27
|
+
def []=(key, value)
|
28
|
+
assign(key, value)
|
29
|
+
end
|
30
|
+
|
31
|
+
def assign(key, value)
|
32
|
+
@sets[key] = value
|
33
|
+
self
|
34
|
+
end
|
35
|
+
|
36
|
+
def set_default(key, value)
|
37
|
+
@defaults[key] = value
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def keys
|
42
|
+
@sets.keys | @defaults.keys
|
43
|
+
end
|
44
|
+
|
45
|
+
def default?(key)
|
46
|
+
unless keys.include?(key)
|
47
|
+
raise KeyError,
|
48
|
+
"Unknown option key '#{key}'"
|
49
|
+
end
|
50
|
+
!@sets.keys.include?(key)
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s
|
54
|
+
"<OptionValues: #{composite.inspect}>"
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
"<OptionValues: #{@sets.inspect} | #{@defaults.inspect}>"
|
59
|
+
end
|
60
|
+
|
61
|
+
def is_a?(const)
|
62
|
+
super || composite.is_a?(const)
|
63
|
+
end
|
64
|
+
|
65
|
+
def respond_to?(method)
|
66
|
+
super || composite.respond_to?(method)
|
67
|
+
end
|
68
|
+
|
69
|
+
def composite
|
70
|
+
Smash.new.tap do |c|
|
71
|
+
keys.each do |k|
|
72
|
+
c[k] = @sets.fetch(k, @defaults[k])
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Modified option parser to include
|
79
|
+
# subcommand information
|
80
|
+
class OptionParser < ::OptionParser
|
81
|
+
attr_accessor :subcommands
|
82
|
+
|
83
|
+
def help
|
84
|
+
v = super
|
85
|
+
return v if Array(subcommands).empty?
|
86
|
+
v += "\n" + "Available Commands:\n\n"
|
87
|
+
Array(subcommands).each do |sc|
|
88
|
+
v += summary_indent + sc.name.to_s + "\t" + sc.description.to_s + "\n"
|
89
|
+
end
|
90
|
+
v + "\n" + 'See `<command> --help` for more information on a specific command.'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class Command
|
95
|
+
# @return [Array<Command>] list of subcommands
|
96
|
+
attr_reader :commands
|
97
|
+
# @return [String] name of command
|
98
|
+
attr_reader :name
|
99
|
+
# @return [Array<Flag>] flags for command
|
100
|
+
attr_reader :flags
|
101
|
+
# @return [Proc] callable to be executed
|
102
|
+
attr_reader :callable
|
103
|
+
# @return [OpenStruct] flag option values
|
104
|
+
attr_reader :options
|
105
|
+
# @return [OptionParser] command parser
|
106
|
+
attr_reader :parser
|
107
|
+
|
108
|
+
# Create a new command
|
109
|
+
#
|
110
|
+
# @param name [String, Symbol] name of command
|
111
|
+
# @return [Command]
|
112
|
+
def initialize(name)
|
113
|
+
@name = name.to_sym
|
114
|
+
@commands = []
|
115
|
+
@flags = []
|
116
|
+
@callable = nil
|
117
|
+
@options = OptionValues.new
|
118
|
+
end
|
119
|
+
|
120
|
+
# Add a new flag
|
121
|
+
#
|
122
|
+
# @param short [String, Symbol] short flag
|
123
|
+
# @param long [String, Symbol] long flag
|
124
|
+
# @param description [String] description of flag
|
125
|
+
# @param default [String] default flag value
|
126
|
+
def on(short, long, description=UNSET, opts={}, &block)
|
127
|
+
if short.to_s.size > 1
|
128
|
+
if description == UNSET
|
129
|
+
description = long
|
130
|
+
long = short
|
131
|
+
short = nil
|
132
|
+
elsif description.is_a?(Hash)
|
133
|
+
opts = description
|
134
|
+
description = long
|
135
|
+
long = short
|
136
|
+
short = nil
|
137
|
+
end
|
138
|
+
end
|
139
|
+
Flag.new(
|
140
|
+
short_name: short,
|
141
|
+
long_name: long,
|
142
|
+
description: description,
|
143
|
+
default: opts[:default],
|
144
|
+
callable: block,
|
145
|
+
).tap do |f|
|
146
|
+
@flags << f
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
# Add a new command
|
151
|
+
#
|
152
|
+
# @param name [String, Symbol] name of command
|
153
|
+
def command(name, &block)
|
154
|
+
Command.new(name).load(&block).tap do |c|
|
155
|
+
@commands << c
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [String] description of command
|
160
|
+
def description(v=UNSET)
|
161
|
+
@description = v unless v == UNSET
|
162
|
+
@description
|
163
|
+
end
|
164
|
+
|
165
|
+
# Register callable for command
|
166
|
+
def run(&block)
|
167
|
+
@callable = block
|
168
|
+
end
|
169
|
+
|
170
|
+
# Load a command configuration block
|
171
|
+
def load(&block)
|
172
|
+
instance_exec(&block)
|
173
|
+
self
|
174
|
+
end
|
175
|
+
|
176
|
+
# @return [String] help output
|
177
|
+
def help
|
178
|
+
parser.help
|
179
|
+
end
|
180
|
+
|
181
|
+
# Parse the arguments
|
182
|
+
#
|
183
|
+
# @param arguments [Array<String>] CLI arguments
|
184
|
+
# @return [OpenStruct, Array<String>]
|
185
|
+
def parse(arguments)
|
186
|
+
raise "Must call #generate before #parse" if
|
187
|
+
parser.nil?
|
188
|
+
flags.each do |f|
|
189
|
+
next if f.default.nil?
|
190
|
+
options.set_default(f.option_name, f.default)
|
191
|
+
end
|
192
|
+
init = OpenStruct.new
|
193
|
+
parser.parse!(arguments, into: init)
|
194
|
+
init.each_pair do |k, v|
|
195
|
+
options.assign(k, v)
|
196
|
+
end
|
197
|
+
[options, arguments]
|
198
|
+
end
|
199
|
+
|
200
|
+
# Generate command parsers
|
201
|
+
#
|
202
|
+
# @param parents [Array<String,Symbol>] ancestors of command
|
203
|
+
# @return [Hash<string,OptParser>]
|
204
|
+
def generate(parents=[], add_help: true)
|
205
|
+
Hash.new.tap { |cmds|
|
206
|
+
@parser = OptionParser.new
|
207
|
+
full_name = parents + [name]
|
208
|
+
parser.program_name = full_name.join(' ')
|
209
|
+
parser.banner = description unless
|
210
|
+
description == UNSET
|
211
|
+
if add_help
|
212
|
+
parser.on('-h', '--help', "Display help information") do
|
213
|
+
$stderr.puts parser.help
|
214
|
+
exit
|
215
|
+
end
|
216
|
+
end
|
217
|
+
flags.each { |f|
|
218
|
+
if !f.boolean? && f.long_name.end_with?('=')
|
219
|
+
short = "-#{f.short_name}" if f.short_name
|
220
|
+
long = "--#{f.long_name[0, f.long_name.size - 1]} VALUE"
|
221
|
+
else
|
222
|
+
short = "-#{f.short_name}" if f.short_name
|
223
|
+
long = "--#{f.long_name}"
|
224
|
+
end
|
225
|
+
parser.on(short, long, f.description, &f.callable)
|
226
|
+
}
|
227
|
+
|
228
|
+
commands.map { |c|
|
229
|
+
c.generate(full_name, add_help: add_help)
|
230
|
+
}.inject(cmds) { |memo, list|
|
231
|
+
memo.merge!(list)
|
232
|
+
}
|
233
|
+
|
234
|
+
parser.subcommands = commands
|
235
|
+
|
236
|
+
cmds[full_name.join(' ')] = self
|
237
|
+
}
|
238
|
+
end
|
239
|
+
|
240
|
+
def to_hash
|
241
|
+
options.to_h
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
class Flag
|
246
|
+
# @return [String] short flag
|
247
|
+
attr_reader :short_name
|
248
|
+
# @return [String] long flag
|
249
|
+
attr_reader :long_name
|
250
|
+
# @return [String] default value
|
251
|
+
attr_reader :default
|
252
|
+
# @return [String] flag description
|
253
|
+
attr_reader :description
|
254
|
+
# @return [Proc] block to execute on flag called
|
255
|
+
attr_reader :callable
|
256
|
+
|
257
|
+
# Create a new flag
|
258
|
+
#
|
259
|
+
# @param short_name [String, Symbol] Single character flag
|
260
|
+
# @param long_name [String, Symbol] Full flag name
|
261
|
+
# @param description [String] Description of flag
|
262
|
+
# @param default [Object] Default value for flag
|
263
|
+
# @return Flag
|
264
|
+
def initialize(long_name:,
|
265
|
+
short_name: nil,
|
266
|
+
description: nil,
|
267
|
+
default: nil,
|
268
|
+
callable: nil
|
269
|
+
)
|
270
|
+
if short_name
|
271
|
+
short_name = short_name.to_s
|
272
|
+
short_name = short_name[1, short_name.size] if
|
273
|
+
short_name.start_with?('-')
|
274
|
+
raise ArgumentError,
|
275
|
+
"Flag short name must be single character (flag: #{short_name})" if
|
276
|
+
short_name.size > 1
|
277
|
+
end
|
278
|
+
@short_name = short_name
|
279
|
+
@long_name = long_name.to_s.sub(/^-+/, '').gsub('_', '-')
|
280
|
+
@description = description
|
281
|
+
@default = default
|
282
|
+
@callable = callable
|
283
|
+
end
|
284
|
+
|
285
|
+
# @return [Symbol] option compatible name
|
286
|
+
def option_name
|
287
|
+
long_name.split('=').first.gsub('-', '_').to_sym
|
288
|
+
end
|
289
|
+
|
290
|
+
# @return [Boolean] flag is boolean value
|
291
|
+
def boolean?
|
292
|
+
!long_name.include?('=')
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# @return [Boolean] generate help content
|
297
|
+
attr_accessor :generate_help
|
298
|
+
|
299
|
+
# Parse a command setup block, process arguments
|
300
|
+
# and execute command if match found
|
301
|
+
#
|
302
|
+
# @param help [Boolean] generate help content
|
303
|
+
# @return [Object] result
|
304
|
+
def self.parse(help: true, &block)
|
305
|
+
parser = self.new
|
306
|
+
parser.generate_help = !!help
|
307
|
+
parser.load(&block)
|
308
|
+
parser.execute
|
309
|
+
end
|
310
|
+
|
311
|
+
# Create a new parser
|
312
|
+
#
|
313
|
+
# @param name [String, Symbol] name of root command
|
314
|
+
# @return [Parser]
|
315
|
+
def initialize(name: nil)
|
316
|
+
name = self.class.root_name unless name
|
317
|
+
@root = Command.new(name)
|
318
|
+
end
|
319
|
+
|
320
|
+
# Add a new command
|
321
|
+
#
|
322
|
+
# @param name [String, Symbol] name of command
|
323
|
+
def command(name, &block)
|
324
|
+
@root.command(name, &block)
|
325
|
+
end
|
326
|
+
|
327
|
+
# Add a new flag
|
328
|
+
#
|
329
|
+
# @param short [String, Symbol] short flag
|
330
|
+
# @param long [String, Symbol] long flag
|
331
|
+
# @param description [String] description of flag
|
332
|
+
# @param default [String] default flag value
|
333
|
+
def on(short, long, description, **options, &block)
|
334
|
+
@root.on(short, long, description, options, &block)
|
335
|
+
end
|
336
|
+
|
337
|
+
# Register callable for command
|
338
|
+
def run(&block)
|
339
|
+
@root.run(&block)
|
340
|
+
end
|
341
|
+
|
342
|
+
# Load a command configuration block
|
343
|
+
def load(&block)
|
344
|
+
@root.load(&block)
|
345
|
+
end
|
346
|
+
|
347
|
+
# Generate all parsers
|
348
|
+
#
|
349
|
+
# @return [Hash<String,Hash<Parser,Command>>]
|
350
|
+
def generate
|
351
|
+
@root.generate(add_help: generate_help)
|
352
|
+
end
|
353
|
+
|
354
|
+
# Execute command based on CLI arguments
|
355
|
+
def execute
|
356
|
+
cmds = @root.generate
|
357
|
+
base_args = arguments
|
358
|
+
line = base_args.join(' ')
|
359
|
+
cmd_key = cmds.keys.find_all { |k|
|
360
|
+
line.start_with?(k)
|
361
|
+
}.sort_by(&:size).last
|
362
|
+
if cmd_key.nil?
|
363
|
+
return cmds[@root.name].parser
|
364
|
+
end
|
365
|
+
base_args = base_args.slice(cmd_key.split(' ').size, base_args.size)
|
366
|
+
a = cmds[cmd_key].parse(base_args)
|
367
|
+
return cmds[cmd_key] unless cmds[cmd_key].callable
|
368
|
+
cmds[cmd_key].callable.call(*a)
|
369
|
+
exit 0
|
370
|
+
end
|
371
|
+
|
372
|
+
private
|
373
|
+
|
374
|
+
# @return [Array<String>]
|
375
|
+
def arguments
|
376
|
+
[self.class.root_name] + ARGV
|
377
|
+
end
|
378
|
+
|
379
|
+
def self.root_name
|
380
|
+
File.basename($0)
|
381
|
+
end
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|
data/lib/bogo-cli/setup.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Trigger shutdown on INT or TERM signals
|
2
2
|
o_int = Signal.trap("INT") {
|
3
3
|
o_int.call if o_int.respond_to?(:call)
|
4
|
-
if
|
4
|
+
if Bogo::Cli.exit_on_signal == false
|
5
5
|
Thread.main.raise SignalException.new("SIGINT")
|
6
6
|
else
|
7
7
|
exit 0
|
@@ -9,49 +9,30 @@ o_int = Signal.trap("INT") {
|
|
9
9
|
}
|
10
10
|
|
11
11
|
o_term = Signal.trap("TERM") {
|
12
|
-
|
13
|
-
if
|
12
|
+
o_term.call if o_term.respond_to?(:call)
|
13
|
+
if Bogo::Cli.exit_on_signal == false
|
14
14
|
Thread.main.raise SignalException.new("SIGTERM")
|
15
15
|
else
|
16
16
|
exit 0
|
17
17
|
end
|
18
18
|
}
|
19
19
|
|
20
|
-
require "bogo-cli"
|
21
|
-
|
22
|
-
class Slop
|
23
|
-
def bogo_cli_run(*args, &block)
|
24
|
-
slop_run(*args, &block)
|
25
|
-
old_runner = @runner
|
26
|
-
@runner = proc { |*args| old_runner.call(*args); exit 0 }
|
27
|
-
end
|
28
|
-
|
29
|
-
alias_method :slop_run, :run
|
30
|
-
alias_method :run, :bogo_cli_run
|
31
|
-
|
32
|
-
class Option
|
33
|
-
def default?
|
34
|
-
@value.nil?
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
20
|
module Bogo
|
40
21
|
module Cli
|
41
22
|
class Setup
|
42
23
|
class << self
|
43
24
|
|
44
|
-
# Wrap
|
25
|
+
# Wrap parsing setup for consistent usage
|
45
26
|
#
|
46
|
-
# @yield
|
27
|
+
# @yield CLI setup block
|
47
28
|
# @return [TrueClass]
|
48
29
|
def define(&block)
|
49
30
|
begin
|
50
|
-
|
31
|
+
result = Parser.parse(help: true) do
|
51
32
|
instance_exec(&block)
|
52
33
|
end
|
53
|
-
puts
|
54
|
-
exit
|
34
|
+
puts result.help
|
35
|
+
exit 255
|
55
36
|
rescue StandardError, ScriptError => err
|
56
37
|
err_msg = err.message
|
57
38
|
if err.respond_to?(:original) && err.original
|
data/lib/bogo-cli/version.rb
CHANGED
data/lib/bogo-cli.rb
CHANGED
@@ -1,17 +1,12 @@
|
|
1
|
-
require 'bogo'
|
2
|
-
require 'slop'
|
3
|
-
require 'bogo-config'
|
4
|
-
|
5
1
|
module Bogo
|
6
2
|
module Cli
|
7
3
|
autoload :Command, 'bogo-cli/command'
|
4
|
+
autoload :Parser, 'bogo-cli/parser'
|
8
5
|
autoload :Setup, 'bogo-cli/setup'
|
6
|
+
autoload :VERSION, 'bogo-cli/version'
|
9
7
|
|
10
8
|
class << self
|
11
9
|
attr_accessor :exit_on_signal
|
12
10
|
end
|
13
|
-
|
14
11
|
end
|
15
12
|
end
|
16
|
-
|
17
|
-
require 'bogo-cli/version'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bogo-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chris Roberts
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-12-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bogo
|
@@ -64,34 +64,20 @@ dependencies:
|
|
64
64
|
- - ">="
|
65
65
|
- !ruby/object:Gem::Version
|
66
66
|
version: '0'
|
67
|
-
- !ruby/object:Gem::Dependency
|
68
|
-
name: slop
|
69
|
-
requirement: !ruby/object:Gem::Requirement
|
70
|
-
requirements:
|
71
|
-
- - "~>"
|
72
|
-
- !ruby/object:Gem::Version
|
73
|
-
version: '3'
|
74
|
-
type: :runtime
|
75
|
-
prerelease: false
|
76
|
-
version_requirements: !ruby/object:Gem::Requirement
|
77
|
-
requirements:
|
78
|
-
- - "~>"
|
79
|
-
- !ruby/object:Gem::Version
|
80
|
-
version: '3'
|
81
67
|
- !ruby/object:Gem::Dependency
|
82
68
|
name: rake
|
83
69
|
requirement: !ruby/object:Gem::Requirement
|
84
70
|
requirements:
|
85
|
-
- - "
|
71
|
+
- - ">="
|
86
72
|
- !ruby/object:Gem::Version
|
87
|
-
version: '
|
73
|
+
version: '0'
|
88
74
|
type: :development
|
89
75
|
prerelease: false
|
90
76
|
version_requirements: !ruby/object:Gem::Requirement
|
91
77
|
requirements:
|
92
|
-
- - "
|
78
|
+
- - ">="
|
93
79
|
- !ruby/object:Gem::Version
|
94
|
-
version: '
|
80
|
+
version: '0'
|
95
81
|
- !ruby/object:Gem::Dependency
|
96
82
|
name: minitest
|
97
83
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,6 +105,7 @@ files:
|
|
119
105
|
- bogo-cli.gemspec
|
120
106
|
- lib/bogo-cli.rb
|
121
107
|
- lib/bogo-cli/command.rb
|
108
|
+
- lib/bogo-cli/parser.rb
|
122
109
|
- lib/bogo-cli/setup.rb
|
123
110
|
- lib/bogo-cli/version.rb
|
124
111
|
homepage: https://github.com/spox/bogo-cli
|
@@ -140,8 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
140
127
|
- !ruby/object:Gem::Version
|
141
128
|
version: '0'
|
142
129
|
requirements: []
|
143
|
-
|
144
|
-
rubygems_version: 2.7.6
|
130
|
+
rubygems_version: 3.4.0.dev
|
145
131
|
signing_key:
|
146
132
|
specification_version: 4
|
147
133
|
summary: CLI Helper libraries
|