rodish 1.1.0 → 2.0.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/lib/rodish/command.rb +167 -110
- data/lib/rodish/dsl.rb +22 -107
- data/lib/rodish/errors.rb +7 -5
- data/lib/rodish/option_parser.rb +0 -47
- data/lib/rodish/plugins/_context_sensitive_help.rb +46 -0
- data/lib/rodish/plugins/_wrap.rb +38 -0
- data/lib/rodish/plugins/after_options_hook.rb +39 -0
- data/lib/rodish/plugins/cache_help_output.rb +28 -0
- data/lib/rodish/plugins/help_examples.rb +48 -0
- data/lib/rodish/plugins/help_option_values.rb +80 -0
- data/lib/rodish/plugins/help_order.rb +49 -0
- data/lib/rodish/plugins/invalid_args_message.rb +74 -0
- data/lib/rodish/plugins/is.rb +65 -0
- data/lib/rodish/plugins/post_commands.rb +160 -0
- data/lib/rodish/plugins/run_is.rb +32 -0
- data/lib/rodish/plugins/skip_option_parsing.rb +51 -0
- data/lib/rodish/plugins/usages.rb +29 -0
- data/lib/rodish/plugins/wrapped_options_separator.rb +29 -0
- data/lib/rodish/plugins.rb +25 -0
- data/lib/rodish/processor.rb +54 -22
- data/lib/rodish.rb +16 -1
- metadata +18 -10
- data/CHANGELOG +0 -7
- data/README.rdoc +0 -265
- data/lib/rodish/skip_option_parser.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe9eb4dc1a9f6cc1e7582a9b24dcbc3491f47e3a3aa24def4ff3f94a241d1dbc
|
4
|
+
data.tar.gz: 90748c4035108090d6576a824e6a6e1699079a755bbf405ce0484d238cd6ee1b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01030a76bc9a5db02ae2b78ddd9bcdb24b18d0b32d9421dffc41f92041700a062a2f2c13260656cce79521f07abccb3ed5da7b4efeb3e93b5de06c246f2dfdfa
|
7
|
+
data.tar.gz: fe7ea63452c88a46dbe528c33b8f2a54d965f93c47ebc9a4984cd985c5a4ec73c777c4f4fc8c08973783ee0f6eb0957fc0b9804485d91d35dc41fee0e51620f3
|
data/lib/rodish/command.rb
CHANGED
@@ -1,35 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "option_parser"
|
4
|
-
require_relative "skip_option_parser"
|
5
4
|
require_relative "errors"
|
6
5
|
|
7
6
|
module Rodish
|
8
7
|
# Rodish::Command is the main object in Rodish's processing.
|
9
8
|
# It handles a single command, and may have one or more
|
10
|
-
# subcommands
|
9
|
+
# subcommands, forming a tree.
|
11
10
|
#
|
12
11
|
# Rodish's argv processing starts with the root command,
|
13
12
|
# processing options and deleting appropriately to subcommands,
|
14
13
|
# until the requested command or subcommand is located,
|
15
14
|
# which is then executed.
|
16
15
|
class Command
|
17
|
-
option_parser = OptionParser.new
|
18
|
-
option_parser.set_banner("")
|
19
|
-
option_parser.freeze
|
20
|
-
|
21
|
-
# The default option parser if no options are given for
|
22
|
-
# the command.
|
23
|
-
DEFAULT_OPTION_PARSER = option_parser
|
24
|
-
|
25
16
|
# A hash of subcommands for the command. Keys are
|
26
17
|
# subcommand name strings.
|
27
18
|
attr_reader :subcommands
|
28
19
|
|
29
|
-
# A hash of post subcommands for the command. Keys are
|
30
|
-
# post subcommand name strings.
|
31
|
-
attr_reader :post_subcommands
|
32
|
-
|
33
20
|
# The block to execute if this command is the requested
|
34
21
|
# subcommand. May be nil if this subcommand cannot be
|
35
22
|
# executed, and can only dispatch to subcommands.
|
@@ -48,36 +35,20 @@ module Rodish
|
|
48
35
|
# are placed directly in the options hash.
|
49
36
|
attr_accessor :option_key
|
50
37
|
|
51
|
-
# The post option parser for the current command. Called
|
52
|
-
# only before dispatching to post subcommands.
|
53
|
-
attr_accessor :post_option_parser
|
54
|
-
|
55
|
-
# Similar to +option_key+, but for post options instead
|
56
|
-
# of normal subcommands.
|
57
|
-
attr_accessor :post_option_key
|
58
|
-
|
59
|
-
# A hook to execute after parsing options for the command.
|
60
|
-
attr_accessor :after_options
|
61
|
-
|
62
|
-
# A hook to execute before executing the current
|
63
|
-
# command or dispatching to subcommands. This will not
|
64
|
-
# be called if an invalid subcommand is given and no
|
65
|
-
# run block is present.
|
66
|
-
attr_accessor :before
|
67
|
-
|
68
38
|
# The number of arguments the run block will accept.
|
69
39
|
# Should be either an integer or a range of integers.
|
70
40
|
attr_accessor :num_args
|
71
41
|
|
72
|
-
#
|
73
|
-
|
74
|
-
|
42
|
+
# A description for the command
|
43
|
+
attr_accessor :desc
|
44
|
+
|
45
|
+
# A usage banner for the command or subcommands.
|
46
|
+
attr_accessor :banner
|
75
47
|
|
76
48
|
def initialize(command_path)
|
77
49
|
@command_path = command_path
|
78
|
-
@command_name = command_path
|
50
|
+
@command_name = _command_name(command_path)
|
79
51
|
@subcommands = {}
|
80
|
-
@post_subcommands = {}
|
81
52
|
@num_args = 0
|
82
53
|
end
|
83
54
|
|
@@ -86,93 +57,72 @@ module Rodish
|
|
86
57
|
def freeze
|
87
58
|
@subcommands.each_value(&:freeze)
|
88
59
|
@subcommands.freeze
|
89
|
-
@post_subcommands.each_value(&:freeze)
|
90
|
-
@post_subcommands.freeze
|
91
60
|
@option_parser.freeze
|
92
|
-
@post_option_parser.freeze
|
93
61
|
super
|
94
62
|
end
|
95
63
|
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
# run do |argv, opts, command|
|
101
|
-
# @name = argv.shift
|
102
|
-
# command.run(self, opts, argv)
|
103
|
-
# end
|
104
|
-
def run(context, options, argv)
|
105
|
-
begin
|
106
|
-
process_options(argv, options, @post_option_key, @post_option_parser)
|
107
|
-
rescue ::OptionParser::InvalidOption => e
|
108
|
-
raise CommandFailure.new(e.message, @post_option_parser)
|
109
|
-
end
|
64
|
+
# Return a help string for the command.
|
65
|
+
def help
|
66
|
+
help_lines.join("\n")
|
67
|
+
end
|
110
68
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
69
|
+
# Return an array of help strings for the command.
|
70
|
+
def help_lines
|
71
|
+
output = []
|
72
|
+
help_order.each do |type|
|
73
|
+
send(:"_help_#{type}", output)
|
116
74
|
end
|
75
|
+
output
|
76
|
+
end
|
77
|
+
|
78
|
+
# Process options for the command using the option key and parser.
|
79
|
+
def process_command_options(context, options, argv)
|
80
|
+
process_options(argv, options, @option_key, @option_parser)
|
117
81
|
end
|
118
|
-
alias run_post_subcommand run
|
119
82
|
|
120
83
|
# Process the current command. This first processes the options.
|
121
84
|
# After processing the options, it checks if the first argument
|
122
85
|
# in the remaining argv is a subcommand. If so, it dispatches to
|
123
86
|
# that subcommand. If not, it dispatches to the run block.
|
124
87
|
def process(context, options, argv)
|
125
|
-
|
126
|
-
context.instance_exec(argv, options, &after_options) if after_options
|
88
|
+
process_command_options(context, options, argv)
|
127
89
|
|
128
90
|
arg = argv[0]
|
129
91
|
if argv && @subcommands[arg]
|
130
92
|
process_subcommand(@subcommands, context, options, argv)
|
131
93
|
elsif run_block
|
132
94
|
if valid_args?(argv)
|
133
|
-
context.instance_exec(argv, options, &before) if before
|
134
|
-
|
135
95
|
if @num_args.is_a?(Integer)
|
136
96
|
context.instance_exec(*argv, options, self, &run_block)
|
137
97
|
else
|
138
98
|
context.instance_exec(argv, options, self, &run_block)
|
139
99
|
end
|
140
|
-
elsif @invalid_args_message
|
141
|
-
raise_failure("invalid arguments#{subcommand_name} (#{@invalid_args_message})")
|
142
100
|
else
|
143
|
-
|
101
|
+
raise_invalid_args_failure(argv)
|
144
102
|
end
|
145
103
|
else
|
146
|
-
process_command_failure(arg, @subcommands,
|
104
|
+
process_command_failure(arg, @subcommands, "")
|
147
105
|
end
|
148
106
|
rescue ::OptionParser::InvalidOption => e
|
149
|
-
|
150
|
-
raise_failure(e.message)
|
151
|
-
else
|
152
|
-
raise
|
153
|
-
end
|
107
|
+
raise_failure(e.message)
|
154
108
|
end
|
155
109
|
|
156
|
-
# This yields the current command and all subcommands
|
157
|
-
# post subcommands, recursively.
|
110
|
+
# This yields the current command and all subcommands, recursively.
|
158
111
|
def each_subcommand(names = [].freeze, &block)
|
159
112
|
yield names, self
|
160
113
|
_each_subcommand(names, @subcommands, &block)
|
161
|
-
_each_subcommand(names, @post_subcommands, &block)
|
162
114
|
end
|
163
115
|
|
164
|
-
#
|
165
|
-
|
166
|
-
|
167
|
-
|
116
|
+
# Yield each banner string (if any) to the block.
|
117
|
+
def each_banner
|
118
|
+
yield banner if banner
|
119
|
+
nil
|
168
120
|
end
|
169
121
|
|
170
|
-
#
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
_options_text(option_parsers)
|
175
|
-
end
|
122
|
+
# Raise a CommandFailure with the given error and the given
|
123
|
+
# option parsers.
|
124
|
+
def raise_failure(message)
|
125
|
+
raise CommandFailure.new(message, self)
|
176
126
|
end
|
177
127
|
|
178
128
|
# Returns a Command instance for the named subcommand.
|
@@ -181,19 +131,114 @@ module Rodish
|
|
181
131
|
_subcommand(@subcommands, name)
|
182
132
|
end
|
183
133
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
134
|
+
private
|
135
|
+
|
136
|
+
# The string to use for the usage heading in help output.
|
137
|
+
def help_usage_heading
|
138
|
+
"Usage:"
|
188
139
|
end
|
189
140
|
|
190
|
-
#
|
191
|
-
|
192
|
-
|
193
|
-
[@option_parser, @post_option_parser].compact
|
141
|
+
# The string to use for the command heading in help output.
|
142
|
+
def help_command_heading
|
143
|
+
"Commands:"
|
194
144
|
end
|
195
145
|
|
196
|
-
|
146
|
+
# The string to use for the options heading in help output.
|
147
|
+
def help_options_heading
|
148
|
+
"Options:"
|
149
|
+
end
|
150
|
+
|
151
|
+
# Use default help order by default.
|
152
|
+
def help_order
|
153
|
+
default_help_order
|
154
|
+
end
|
155
|
+
|
156
|
+
# The default order of help sections
|
157
|
+
def default_help_order
|
158
|
+
[:desc, :banner, :commands, :options]
|
159
|
+
end
|
160
|
+
|
161
|
+
# Add description to help output.
|
162
|
+
def _help_desc(output)
|
163
|
+
if desc
|
164
|
+
output << desc << ""
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Add banner to help output.
|
169
|
+
def _help_banner(output)
|
170
|
+
if each_banner{break true}
|
171
|
+
output << help_usage_heading
|
172
|
+
each_banner do |banner|
|
173
|
+
output << " #{banner}"
|
174
|
+
end
|
175
|
+
output << ""
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
# Add commands to help output.
|
180
|
+
def _help_commands(output)
|
181
|
+
name_len = 0
|
182
|
+
each_local_subcommand do |name|
|
183
|
+
len = name.length
|
184
|
+
name_len = len if len > name_len
|
185
|
+
end
|
186
|
+
|
187
|
+
__help_command_hashes.each do |heading, hash|
|
188
|
+
next if hash.empty?
|
189
|
+
output << heading
|
190
|
+
command_output = []
|
191
|
+
_each_local_subcommand(hash) do |name, command|
|
192
|
+
command_output << " #{name.ljust(name_len)} #{command.desc}"
|
193
|
+
end
|
194
|
+
command_output.sort!
|
195
|
+
output.concat(command_output)
|
196
|
+
output << ""
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
# Hash with hash of subcommand values to potentially show help output for.
|
201
|
+
def __help_command_hashes
|
202
|
+
{help_command_heading => @subcommands}
|
203
|
+
end
|
204
|
+
|
205
|
+
# Add options to help output.
|
206
|
+
def _help_options(output)
|
207
|
+
__help_option_parser_hashes.each do |heading, parser|
|
208
|
+
next if omit_option_parser_from_help?(parser)
|
209
|
+
output << heading
|
210
|
+
output << parser.summarize(String.new)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
# Hash with option parser values to potentially show help output for.
|
215
|
+
def __help_option_parser_hashes
|
216
|
+
{help_options_heading => @option_parser}
|
217
|
+
end
|
218
|
+
|
219
|
+
# Whether the given option parser should be ommitted from the
|
220
|
+
# command help output.
|
221
|
+
def omit_option_parser_from_help?(parser)
|
222
|
+
parser.nil?
|
223
|
+
end
|
224
|
+
|
225
|
+
# Raise a error when an invalid number of arguments has been provided.
|
226
|
+
def raise_invalid_args_failure(argv)
|
227
|
+
raise_failure(invalid_num_args_failure_error_message(argv))
|
228
|
+
end
|
229
|
+
|
230
|
+
# Yield each local subcommand to the block. This does not
|
231
|
+
# yield the current command or nested subcommands.
|
232
|
+
def each_local_subcommand(&block)
|
233
|
+
_each_local_subcommand(@subcommands, &block)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Internals of each_local_subcommand.
|
237
|
+
def _each_local_subcommand(subcommands)
|
238
|
+
subcommands.each_key do |name|
|
239
|
+
yield name, _subcommand(subcommands, name)
|
240
|
+
end
|
241
|
+
end
|
197
242
|
|
198
243
|
# Yield to the block for each subcommand in the given
|
199
244
|
# subcommands. Internals of #each_subcommand.
|
@@ -220,32 +265,37 @@ module Rodish
|
|
220
265
|
subcommand
|
221
266
|
end
|
222
267
|
|
223
|
-
#
|
224
|
-
def
|
225
|
-
option_parsers.join("\n\n")
|
226
|
-
end
|
227
|
-
|
228
|
-
# Handle command failures for both subcommands and post subcommands.
|
229
|
-
def process_command_failure(arg, subcommands, option_parser, prefix)
|
268
|
+
# Handle command failures for subcommands.
|
269
|
+
def process_command_failure(arg, subcommands, prefix)
|
230
270
|
if subcommands.empty?
|
231
271
|
raise ProgramBug, "program bug, no run block or #{prefix}subcommands defined#{subcommand_name}"
|
232
272
|
elsif arg
|
233
|
-
raise_failure(
|
273
|
+
raise_failure(invalid_subcommand_error_message(arg, subcommands, prefix))
|
234
274
|
else
|
235
|
-
raise_failure(
|
275
|
+
raise_failure(no_subcommand_provided_error_message(arg, subcommands, prefix))
|
236
276
|
end
|
237
277
|
end
|
238
278
|
|
279
|
+
# The error message to use when an invalid number of arguments is provided.
|
280
|
+
def invalid_num_args_failure_error_message(argv)
|
281
|
+
"invalid number of arguments#{subcommand_name} (requires: #{@num_args}, given: #{argv.length})"
|
282
|
+
end
|
283
|
+
|
284
|
+
# Error message for cases where an invalid subcommand is provided.
|
285
|
+
def invalid_subcommand_error_message(arg, subcommands, prefix)
|
286
|
+
"invalid #{prefix}subcommand: #{arg}"
|
287
|
+
end
|
288
|
+
|
289
|
+
# Error message for cases where a subcommand is required and not provided.
|
290
|
+
def no_subcommand_provided_error_message(arg, subcommands, prefix)
|
291
|
+
"no #{prefix}subcommand provided"
|
292
|
+
end
|
293
|
+
|
239
294
|
# Process options for the given command. If option_key is set,
|
240
295
|
# parsed options are added as a options subhash under the given key.
|
241
296
|
# Otherwise, parsed options placed directly into options.
|
242
297
|
def process_options(argv, options, option_key, option_parser)
|
243
|
-
|
244
|
-
when SkipOptionParser
|
245
|
-
# do nothing
|
246
|
-
when nil
|
247
|
-
DEFAULT_OPTION_PARSER.order!(argv)
|
248
|
-
else
|
298
|
+
if option_parser
|
249
299
|
command_options = option_key ? {} : options
|
250
300
|
|
251
301
|
option_parser.order!(argv, into: command_options)
|
@@ -253,6 +303,8 @@ module Rodish
|
|
253
303
|
if option_key
|
254
304
|
options[option_key] = command_options
|
255
305
|
end
|
306
|
+
else
|
307
|
+
self.class::DEFAULT_OPTION_PARSER.order!(argv)
|
256
308
|
end
|
257
309
|
end
|
258
310
|
|
@@ -261,7 +313,6 @@ module Rodish
|
|
261
313
|
def process_subcommand(subcommands, context, options, argv)
|
262
314
|
subcommand = _subcommand(subcommands, argv[0])
|
263
315
|
argv.shift
|
264
|
-
context.instance_exec(argv, options, &before) if before
|
265
316
|
subcommand.process(context, options, argv)
|
266
317
|
end
|
267
318
|
|
@@ -274,6 +325,12 @@ module Rodish
|
|
274
325
|
end
|
275
326
|
end
|
276
327
|
|
328
|
+
# Set the command name for the command. The command name is used
|
329
|
+
# in error messages.
|
330
|
+
def _command_name(command_path)
|
331
|
+
command_path.join(" ").freeze
|
332
|
+
end
|
333
|
+
|
277
334
|
# Return whether the given argv has a valid number of arguments.
|
278
335
|
def valid_args?(argv)
|
279
336
|
if @num_args.is_a?(Integer)
|
data/lib/rodish/dsl.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require_relative "command"
|
4
4
|
require_relative "option_parser"
|
5
|
-
require_relative "skip_option_parser"
|
6
5
|
|
7
6
|
module Rodish
|
8
7
|
# The Rodish::DSL class implements Rodish's DSL. Blocks
|
@@ -18,8 +17,8 @@ module Rodish
|
|
18
17
|
# the given block in the context of a new instance using
|
19
18
|
# that command.
|
20
19
|
def self.command(command_path, &block)
|
21
|
-
command = Command.new(command_path)
|
22
|
-
new(command).instance_exec(&block)
|
20
|
+
command = self::Command.new(command_path)
|
21
|
+
new(command).instance_exec(&block) if block
|
23
22
|
command
|
24
23
|
end
|
25
24
|
|
@@ -27,16 +26,14 @@ module Rodish
|
|
27
26
|
@command = command
|
28
27
|
end
|
29
28
|
|
30
|
-
#
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
def skip_option_parsing(banner)
|
39
|
-
@command.option_parser = SkipOptionParser.new(banner)
|
29
|
+
# Set the description for the command.
|
30
|
+
def desc(description)
|
31
|
+
@command.desc = description
|
32
|
+
end
|
33
|
+
|
34
|
+
# Set the banner for the command execution and subcommand usage.
|
35
|
+
def banner(banner)
|
36
|
+
@command.banner = banner
|
40
37
|
end
|
41
38
|
|
42
39
|
# Set the option parser for the command to based on the
|
@@ -49,46 +46,18 @@ module Rodish
|
|
49
46
|
#
|
50
47
|
# If +key+ is given, parsed options
|
51
48
|
# will be placed in a subhash using that key.
|
52
|
-
#
|
53
|
-
# The block is optional, allowing you to set a usage banner for
|
54
|
-
# commands without allowing any options.
|
55
49
|
def options(banner, key: nil, &block)
|
50
|
+
@command.banner = banner
|
56
51
|
@command.option_key = key
|
57
|
-
@command.option_parser = create_option_parser(
|
58
|
-
end
|
59
|
-
|
60
|
-
# Similar to +options+, but sets the option parser for post
|
61
|
-
# subcommands. This option parser is only used when the
|
62
|
-
# command is executed and chooses to run a post subcommand.
|
63
|
-
def post_options(banner, key: nil, &block)
|
64
|
-
@command.post_option_key = key
|
65
|
-
@command.post_option_parser = create_option_parser(banner, @command.post_subcommands, &block)
|
66
|
-
end
|
67
|
-
|
68
|
-
# Sets the after_options block. This block is executed in the same
|
69
|
-
# context as the run block would be executed, directly after
|
70
|
-
# option parsing.
|
71
|
-
def after_options(&block)
|
72
|
-
@command.after_options = block
|
73
|
-
end
|
74
|
-
|
75
|
-
# Sets the before block. This block is executed in the same
|
76
|
-
# context as the run block would be executed, before either
|
77
|
-
# subcommand execution or execution of the current command.
|
78
|
-
# It is not called on invalid or missing subcommands.
|
79
|
-
def before(&block)
|
80
|
-
@command.before = block
|
52
|
+
@command.option_parser = create_option_parser(&block)
|
81
53
|
end
|
82
54
|
|
83
55
|
# Set the number of arguments supported by this command.
|
84
56
|
# The default is 0. To support a fixed number of arguments,
|
85
57
|
# pass an Integer. To support a variable number of arguments,
|
86
|
-
# pass a Range.
|
87
|
-
|
88
|
-
# passed.
|
89
|
-
def args(args, invalid_args_message: nil)
|
58
|
+
# pass a Range.
|
59
|
+
def args(args)
|
90
60
|
@command.num_args = args
|
91
|
-
@command.invalid_args_message = invalid_args_message
|
92
61
|
end
|
93
62
|
|
94
63
|
# Autoload subcommands from the given directory. Filenames
|
@@ -101,24 +70,12 @@ module Rodish
|
|
101
70
|
_autoload_subcommand_dir(@command.subcommands, dir)
|
102
71
|
end
|
103
72
|
|
104
|
-
# Similar to +autoload_subcommand_dir+, but for post
|
105
|
-
# subcommands instead of normal subcommands.
|
106
|
-
def autoload_post_subcommand_dir(dir)
|
107
|
-
_autoload_subcommand_dir(@command.post_subcommands, dir)
|
108
|
-
end
|
109
|
-
|
110
73
|
# Create a new subcommand with the given name and yield to
|
111
74
|
# the block to configure the subcommand.
|
112
75
|
def on(command_name, &block)
|
113
76
|
_on(@command.subcommands, command_name, &block)
|
114
77
|
end
|
115
78
|
|
116
|
-
# Same as +on+, but for post subcommands instead of normal
|
117
|
-
# subcommands.
|
118
|
-
def run_on(command_name, &block)
|
119
|
-
_on(@command.post_subcommands, command_name, &block)
|
120
|
-
end
|
121
|
-
|
122
79
|
# Set the block to run for subcommand execution. Commands
|
123
80
|
# should have subcommands and/or a run block, otherwise it
|
124
81
|
# is not possible to use the command successfully.
|
@@ -126,38 +83,9 @@ module Rodish
|
|
126
83
|
@command.run_block = block
|
127
84
|
end
|
128
85
|
|
129
|
-
# A shortcut for calling +on+ and +run+.
|
130
|
-
#
|
131
|
-
# is "hello" do
|
132
|
-
# :world
|
133
|
-
# end
|
134
|
-
#
|
135
|
-
# is equivalent to:
|
136
|
-
#
|
137
|
-
# on "hello" do
|
138
|
-
# run do
|
139
|
-
# :world
|
140
|
-
# end
|
141
|
-
# end
|
142
|
-
#
|
143
|
-
# The +args+ argument sets the number of arguments supported by
|
144
|
-
# the command.
|
145
|
-
#
|
146
|
-
# The +invalid_args_message+ arguments set the error message to
|
147
|
-
# use if an invalid number of arguments is provided.
|
148
|
-
def is(command_name, args: 0, invalid_args_message: nil, &block)
|
149
|
-
_is(:on, command_name, args:, invalid_args_message:, &block)
|
150
|
-
end
|
151
|
-
|
152
|
-
# Similar to +is+, but for post subcommands instead of normal
|
153
|
-
# subcommands.
|
154
|
-
def run_is(command_name, args: 0, invalid_args_message: nil, &block)
|
155
|
-
_is(:run_on, command_name, args:, invalid_args_message:, &block)
|
156
|
-
end
|
157
|
-
|
158
86
|
private
|
159
87
|
|
160
|
-
# Internals of autoloading of
|
88
|
+
# Internals of autoloading of subcommands.
|
161
89
|
# This sets the value of the subcommand as a string instead of a
|
162
90
|
# Command instance, and the Command#_subcommand method recognizes
|
163
91
|
# this and handles the autoloading.
|
@@ -167,30 +95,17 @@ module Rodish
|
|
167
95
|
end
|
168
96
|
end
|
169
97
|
|
170
|
-
# Internals of +
|
171
|
-
def _is(meth, command_name, args:, invalid_args_message: nil, &block)
|
172
|
-
public_send(meth, command_name) do
|
173
|
-
args(args, invalid_args_message:)
|
174
|
-
run(&block)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
# Internals of +on+ and +run_on+.
|
98
|
+
# Internals of +on+.
|
179
99
|
def _on(hash, command_name, &block)
|
180
100
|
command_path = @command.command_path + [command_name]
|
181
|
-
hash[command_name] =
|
101
|
+
hash[command_name] = self.class.command(command_path.freeze, &block)
|
182
102
|
end
|
183
103
|
|
184
|
-
# Internals of +options
|
185
|
-
def create_option_parser(
|
186
|
-
option_parser = OptionParser.new
|
187
|
-
option_parser.
|
188
|
-
|
189
|
-
option_parser.separator ""
|
190
|
-
option_parser.separator "Options:"
|
191
|
-
option_parser.instance_exec(&block)
|
192
|
-
end
|
193
|
-
option_parser.subcommands = subcommands
|
104
|
+
# Internals of +options+.
|
105
|
+
def create_option_parser(&block)
|
106
|
+
option_parser = self.class::OptionParser.new
|
107
|
+
option_parser.banner = "" # Avoids issues when parser is frozen
|
108
|
+
option_parser.instance_exec(&block)
|
194
109
|
option_parser
|
195
110
|
end
|
196
111
|
end
|
data/lib/rodish/errors.rb
CHANGED
@@ -26,9 +26,10 @@ module Rodish
|
|
26
26
|
# * Invalid subcommands
|
27
27
|
# * No subcommand given for a command that only supports subcommands
|
28
28
|
class CommandFailure < CommandExit
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
attr_reader :command
|
30
|
+
|
31
|
+
def initialize(message, command=nil)
|
32
|
+
@command = command
|
32
33
|
super(message)
|
33
34
|
end
|
34
35
|
|
@@ -41,10 +42,11 @@ module Rodish
|
|
41
42
|
# parsers. This can be used to show usage an options along with
|
42
43
|
# error messages for failing commands.
|
43
44
|
def message_with_usage
|
44
|
-
|
45
|
+
help = @command&.help || ''
|
46
|
+
if help.empty?
|
45
47
|
message
|
46
48
|
else
|
47
|
-
"#{message}\n\n#{
|
49
|
+
"#{message}\n\n#{help}"
|
48
50
|
end
|
49
51
|
end
|
50
52
|
end
|