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
data/lib/rodish/option_parser.rb
CHANGED
@@ -7,58 +7,11 @@ module Rodish
|
|
7
7
|
# Rodish::OptionPaser is a subclass of Ruby's standard OptionParser
|
8
8
|
# (from the optparse library).
|
9
9
|
class OptionParser < ::OptionParser
|
10
|
-
# A hash of subcommands for the option parser. If not empty,
|
11
|
-
# shows available subcommands when showing options.
|
12
|
-
attr_accessor :subcommands
|
13
|
-
|
14
10
|
# Don't add officious, which includes options that call exit.
|
15
11
|
# With Rodish, there are no secret options, only options you define.
|
16
12
|
def add_officious
|
17
13
|
end
|
18
14
|
|
19
|
-
# Add the available subcommands to the returned string if there are
|
20
|
-
# any subcommands.
|
21
|
-
def to_s
|
22
|
-
string = super
|
23
|
-
|
24
|
-
if subcommands.length > 6
|
25
|
-
string += "\nSubcommands:\n #{subcommands.keys.sort.join("\n ")}\n"
|
26
|
-
elsif !subcommands.empty?
|
27
|
-
string += "\nSubcommands: #{subcommands.keys.sort.join(" ")}\n"
|
28
|
-
end
|
29
|
-
|
30
|
-
string
|
31
|
-
end
|
32
|
-
|
33
|
-
# Helper method that takes an array of values, wraps them to the given
|
34
|
-
# limit, and adds each line as a separator. This is useful when you
|
35
|
-
# have a large amount of information you want to display and you want
|
36
|
-
# to wrap if for display to the user when showing options.
|
37
|
-
def wrap(prefix, values, separator: " ", limit: 80)
|
38
|
-
line = [prefix]
|
39
|
-
lines = [line]
|
40
|
-
prefix_length = length = prefix.length
|
41
|
-
sep_length = separator.length
|
42
|
-
indent = " " * prefix_length
|
43
|
-
|
44
|
-
values.each do |value|
|
45
|
-
value_length = value.length
|
46
|
-
new_length = sep_length + length + value_length
|
47
|
-
if new_length > limit
|
48
|
-
line = [indent, separator, value]
|
49
|
-
lines << line
|
50
|
-
length = prefix_length
|
51
|
-
else
|
52
|
-
line << separator << value
|
53
|
-
end
|
54
|
-
length += sep_length + value_length
|
55
|
-
end
|
56
|
-
|
57
|
-
lines.each do |line|
|
58
|
-
separator line.join
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
15
|
# Halt processing with a CommandExit using the given string.
|
63
16
|
# This can be used to implement early exits, by calling this
|
64
17
|
# method in a block:
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# _context_sensitive_help is an internal plugin to implement context
|
4
|
+
# sensitive help output.
|
5
|
+
|
6
|
+
#
|
7
|
+
module Rodish
|
8
|
+
module Plugins
|
9
|
+
module ContextSensitiveHelp_
|
10
|
+
# Object that wraps a block, which is instance execed in the provided
|
11
|
+
# context when called.
|
12
|
+
class ContextHelp
|
13
|
+
def initialize(block)
|
14
|
+
@block = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(context)
|
18
|
+
context.instance_exec(&@block)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
module CommandMethods
|
23
|
+
# Render help with context-sensitive information.
|
24
|
+
def context_help(context)
|
25
|
+
lines = help_lines(include_context_help: true)
|
26
|
+
lines.map! do |line|
|
27
|
+
if line.is_a?(ContextHelp)
|
28
|
+
line.call(context)
|
29
|
+
else
|
30
|
+
line
|
31
|
+
end
|
32
|
+
end
|
33
|
+
lines.flatten!
|
34
|
+
lines.join("\n")
|
35
|
+
end
|
36
|
+
|
37
|
+
# Exclude ContextHelp lines unless they are explicitly requested.
|
38
|
+
def help_lines(include_context_help: false)
|
39
|
+
lines = super()
|
40
|
+
lines.reject!{|l| l.is_a?(ContextHelp)} unless include_context_help
|
41
|
+
lines
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# _wrap is an an internal plugin module used by other plugins.
|
4
|
+
|
5
|
+
#
|
6
|
+
module Rodish
|
7
|
+
module Plugins
|
8
|
+
module Wrap_
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Return an array of strings, each no longer than limit,
|
12
|
+
# showing the prefix and all values.
|
13
|
+
public def wrap(prefix, values, separator: " ", limit: 80)
|
14
|
+
line = [prefix]
|
15
|
+
lines = [line]
|
16
|
+
prefix_length = length = prefix.length
|
17
|
+
sep_length = separator.length
|
18
|
+
indent = " " * prefix_length
|
19
|
+
|
20
|
+
values.each do |value|
|
21
|
+
value = value.to_s
|
22
|
+
value_length = value.length
|
23
|
+
new_length = sep_length + length + value_length
|
24
|
+
if new_length > limit
|
25
|
+
line = [indent, separator, value]
|
26
|
+
lines << line
|
27
|
+
length = prefix_length
|
28
|
+
else
|
29
|
+
line << separator << value
|
30
|
+
end
|
31
|
+
length += sep_length + value_length
|
32
|
+
end
|
33
|
+
|
34
|
+
lines.map{|l| l.join}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The after_options_hook plugin supports an after_options configuration
|
4
|
+
# method, specifying a block to execute in context after parsing options,
|
5
|
+
# before executing the command or any subcommands. It is passed the remaining
|
6
|
+
# argv and already parsed options:
|
7
|
+
#
|
8
|
+
# after_options do |argv, options|
|
9
|
+
# # ...
|
10
|
+
# end
|
11
|
+
|
12
|
+
#
|
13
|
+
module Rodish
|
14
|
+
module Plugins
|
15
|
+
module AfterOptionsHook
|
16
|
+
module DSLMethods
|
17
|
+
# Sets the after_options block. This block is executed in the same
|
18
|
+
# context as the run block would be executed, directly after
|
19
|
+
# option parsing.
|
20
|
+
def after_options(&block)
|
21
|
+
@command.after_options = block
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module CommandMethods
|
26
|
+
# A hook to execute after parsing options for the command.
|
27
|
+
attr_accessor :after_options
|
28
|
+
|
29
|
+
# Run after_options hook if present after parsing options.
|
30
|
+
def process_command_options(context, options, argv)
|
31
|
+
super
|
32
|
+
context.instance_exec(argv, options, &after_options) if after_options
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
register(:after_options_hook, AfterOptionsHook)
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The cache_help caches help output when the command is frozen, so
|
4
|
+
# it is only calculated once. This is useful if help output for
|
5
|
+
# the command does not depend on external state, and help for the
|
6
|
+
# command could be requested multiple times during program runtime.
|
7
|
+
|
8
|
+
#
|
9
|
+
module Rodish
|
10
|
+
module Plugins
|
11
|
+
module CacheHelpOutput
|
12
|
+
module CommandMethods
|
13
|
+
# Cache and help output when freezing the command.
|
14
|
+
def freeze
|
15
|
+
@help = help.freeze
|
16
|
+
super
|
17
|
+
end
|
18
|
+
|
19
|
+
# Return cached help if it is present.
|
20
|
+
def help
|
21
|
+
@help || super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
register(:cache_help_output, CacheHelpOutput)
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The help_examples plugin supports showing examples in help output.
|
4
|
+
# By default, examples are shown at the end of the help output, but you
|
5
|
+
# can change the order using the help_order method.
|
6
|
+
|
7
|
+
#
|
8
|
+
module Rodish
|
9
|
+
module Plugins
|
10
|
+
module HelpExamples
|
11
|
+
module DSLMethods
|
12
|
+
# Add an example to show in the help output for the command.
|
13
|
+
def help_example(example)
|
14
|
+
(@command.help_examples ||= []) << example
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
module CommandMethods
|
19
|
+
# An array of strings for any examples to display in the help.
|
20
|
+
attr_accessor :help_examples
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
# The string to use for the examples heading in help output.
|
25
|
+
def help_examples_heading
|
26
|
+
"Examples:"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Include examples at the end of the help text by default.
|
30
|
+
def default_help_order
|
31
|
+
super << :examples
|
32
|
+
end
|
33
|
+
|
34
|
+
def _help_examples(output)
|
35
|
+
if help_examples
|
36
|
+
output << help_examples_heading
|
37
|
+
help_examples.each do |example|
|
38
|
+
output << " #{example}"
|
39
|
+
end
|
40
|
+
output << ""
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
register(:help_examples, HelpExamples)
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Support showing allowed option values in help output. The allowed
|
4
|
+
# options are wrapped. The also allows for context-sensitive allowed
|
5
|
+
# options, where the allowed options may vary per-call.
|
6
|
+
|
7
|
+
require_relative "_context_sensitive_help"
|
8
|
+
require_relative "_wrap"
|
9
|
+
|
10
|
+
#
|
11
|
+
module Rodish
|
12
|
+
module Plugins
|
13
|
+
module HelpOptionValues
|
14
|
+
def self.before_load(app)
|
15
|
+
app.plugin(ContextSensitiveHelp_)
|
16
|
+
end
|
17
|
+
|
18
|
+
# Used to wrap context sensitive option values, when the allowed options
|
19
|
+
# differ depending on the context.
|
20
|
+
class ContextWrappedOptionValues < ContextSensitiveHelp_::ContextHelp
|
21
|
+
def initialize(name, block)
|
22
|
+
@name = name
|
23
|
+
super(block)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Get the allowed values using the provided context, then wrap the values.
|
27
|
+
def call(context)
|
28
|
+
Wrap_.wrap(" #{@name}", super)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
module DSLMethods
|
33
|
+
# Add allowed option values to show in help output.
|
34
|
+
def help_option_values(option_name, values=nil, &block)
|
35
|
+
values ||= ContextWrappedOptionValues.new(option_name, block)
|
36
|
+
(@command.help_option_values ||= {})[option_name] = values
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
module CommandMethods
|
41
|
+
# An hash with option name string keys, and keys that are either
|
42
|
+
# arrays of strings or ContextWrappedOptionValues instances.
|
43
|
+
attr_accessor :help_option_values
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
# The string to use for the allowed option values heading in help output.
|
48
|
+
def help_allowed_option_values_heading
|
49
|
+
"Allowed Option Values:"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Include option values after options.
|
53
|
+
def default_help_order
|
54
|
+
order = super
|
55
|
+
index = order.index(:options) || -2
|
56
|
+
order.insert(index+1, :option_values)
|
57
|
+
order
|
58
|
+
end
|
59
|
+
|
60
|
+
# Include allowed options in the help output, if there are any
|
61
|
+
# option values for this command.
|
62
|
+
def _help_option_values(output)
|
63
|
+
if help_option_values
|
64
|
+
output << help_allowed_option_values_heading
|
65
|
+
help_option_values.each do |name, values|
|
66
|
+
if values.is_a?(ContextWrappedOptionValues)
|
67
|
+
output << values
|
68
|
+
else
|
69
|
+
output.concat(Wrap_.wrap(" #{name}", values))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
output << ""
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
register(:help_option_values, HelpOptionValues)
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The help_order plugin allows overriding the order of help sections in
|
4
|
+
# commands:
|
5
|
+
#
|
6
|
+
# help_order(:desc, :options)
|
7
|
+
#
|
8
|
+
# You can provide the default order for help sections using the
|
9
|
+
# +default_help_order+ keyword argument:
|
10
|
+
#
|
11
|
+
# plugin :help_order, default_help_order: [:usage, :options]
|
12
|
+
|
13
|
+
#
|
14
|
+
module Rodish
|
15
|
+
module Plugins
|
16
|
+
module HelpOrder
|
17
|
+
def self.after_load(app, default_help_order: nil)
|
18
|
+
if default_help_order
|
19
|
+
app::DSL::Command.class_exec do
|
20
|
+
define_method(:default_help_order){default_help_order.dup}
|
21
|
+
alias_method(:default_help_order, :default_help_order)
|
22
|
+
private(:default_help_order)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
module DSLMethods
|
28
|
+
# Override the order of help sections for the command.
|
29
|
+
def help_order(*sections)
|
30
|
+
@command.help_order = sections
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module CommandMethods
|
35
|
+
# The order of sections in returned help. If not set for the
|
36
|
+
# command, uses the default order
|
37
|
+
attr_writer :help_order
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def help_order
|
42
|
+
@help_order || super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
register(:help_order, HelpOrder)
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The invalid_args_message plugin allows for using a specific
|
4
|
+
# error message when an invalid number of arguments has been
|
5
|
+
# passed to a command.
|
6
|
+
#
|
7
|
+
# You can pass the invalid_args_message keyword argument to the
|
8
|
+
# following configuration methods:
|
9
|
+
#
|
10
|
+
# * args
|
11
|
+
# * is
|
12
|
+
# * run_is
|
13
|
+
|
14
|
+
#
|
15
|
+
module Rodish
|
16
|
+
module Plugins
|
17
|
+
module InvalidArgsMessage
|
18
|
+
module DSLMethods
|
19
|
+
# Support setting +invalid_args_message+ when calling +args+.
|
20
|
+
def args(args, **kw)
|
21
|
+
_set_invalid_args_message(kw) do
|
22
|
+
super
|
23
|
+
@command
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Support setting +invalid_args_message+ when calling +is+.
|
28
|
+
def is(command_name, **kw, &block)
|
29
|
+
_set_invalid_args_message(kw) do
|
30
|
+
super
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Support setting +invalid_args_message+ when calling +run_is+.
|
35
|
+
def run_is(command_name, **kw, &block)
|
36
|
+
_set_invalid_args_message(kw) do
|
37
|
+
super
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Remove invalid_args_message from keyword hash, yield to get
|
44
|
+
# the command, then set the invalid_args_message on the command
|
45
|
+
# if it was set.
|
46
|
+
def _set_invalid_args_message(kw)
|
47
|
+
message = kw.delete(:invalid_args_message)
|
48
|
+
command = yield
|
49
|
+
command.invalid_args_message = message if message
|
50
|
+
command
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module CommandMethods
|
55
|
+
# The error message to use if an invalid number of
|
56
|
+
# arguments is provided.
|
57
|
+
attr_accessor :invalid_args_message
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Use invalid_args_message if it has been set.
|
62
|
+
def invalid_num_args_failure_error_message(argv)
|
63
|
+
if @invalid_args_message
|
64
|
+
"invalid arguments#{subcommand_name} (#{@invalid_args_message})"
|
65
|
+
else
|
66
|
+
super
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
register(:invalid_args_message, InvalidArgsMessage)
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The is plugin adds an +is+ method as a shortcut for calling the +on+ method
|
4
|
+
# and +run+ method.
|
5
|
+
#
|
6
|
+
# For example:
|
7
|
+
#
|
8
|
+
# is "hello" do
|
9
|
+
# :world
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# is equivalent to:
|
13
|
+
#
|
14
|
+
# on "hello" do
|
15
|
+
# run do
|
16
|
+
# :world
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# The +is+ method also takes +args+ keyword arguments to specify the number
|
21
|
+
# of arguments.
|
22
|
+
#
|
23
|
+
# This does not allow you to set a command description or usage, so it is
|
24
|
+
# not recommended in new code.
|
25
|
+
|
26
|
+
#
|
27
|
+
module Rodish
|
28
|
+
module Plugins
|
29
|
+
module Is
|
30
|
+
module DSLMethods
|
31
|
+
# A shortcut for calling +on+ and +run+.
|
32
|
+
#
|
33
|
+
# is "hello" do
|
34
|
+
# :world
|
35
|
+
# end
|
36
|
+
#
|
37
|
+
# is equivalent to:
|
38
|
+
#
|
39
|
+
# on "hello" do
|
40
|
+
# run do
|
41
|
+
# :world
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# The +args+ argument sets the number of arguments supported by
|
46
|
+
# the command.
|
47
|
+
def is(command_name, args: 0, &block)
|
48
|
+
_is(:on, command_name, args:, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# Internals of +is+.
|
54
|
+
def _is(meth, command_name, args:, &block)
|
55
|
+
public_send(meth, command_name) do
|
56
|
+
args(args)
|
57
|
+
run(&block)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
register(:is, Is)
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,160 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The post_commands plugin supports subcommands after arguments,
|
4
|
+
# instead of requiring subcommands before arguments. You can
|
5
|
+
# use Command#run to dispatch to post subcommands inside the
|
6
|
+
# Command's run block.
|
7
|
+
#
|
8
|
+
# run do |argv, opts, command|
|
9
|
+
# @something = argv.shift
|
10
|
+
# command.run(self, opts, argv)
|
11
|
+
# end
|
12
|
+
|
13
|
+
#
|
14
|
+
module Rodish
|
15
|
+
module Plugins
|
16
|
+
module PostCommands
|
17
|
+
def self.after_load(app)
|
18
|
+
app.command.instance_exec do
|
19
|
+
@post_subcommands ||= {}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
module DSLMethods
|
24
|
+
# Set the banner for post subcommand usage.
|
25
|
+
def post_banner(banner)
|
26
|
+
@command.post_banner = banner
|
27
|
+
end
|
28
|
+
|
29
|
+
# Similar to +options+, but sets the option parser for post
|
30
|
+
# subcommands. This option parser is only used when the
|
31
|
+
# command is executed and chooses to run a post subcommand.
|
32
|
+
def post_options(banner, key: nil, &block)
|
33
|
+
@command.post_banner = banner
|
34
|
+
@command.post_option_key = key
|
35
|
+
@command.post_option_parser = create_option_parser(&block)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Similar to +autoload_subcommand_dir+, but for post
|
39
|
+
# subcommands instead of normal subcommands.
|
40
|
+
def autoload_post_subcommand_dir(dir)
|
41
|
+
_autoload_subcommand_dir(@command.post_subcommands, dir)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Same as +on+, but for post subcommands instead of normal
|
45
|
+
# subcommands.
|
46
|
+
def run_on(command_name, &block)
|
47
|
+
_on(@command.post_subcommands, command_name, &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
module CommandMethods
|
52
|
+
# A hash of post subcommands for the command. Keys are
|
53
|
+
# post subcommand name strings.
|
54
|
+
attr_reader :post_subcommands
|
55
|
+
|
56
|
+
# The post option parser for the current command. Called
|
57
|
+
# only before dispatching to post subcommands.
|
58
|
+
attr_accessor :post_option_parser
|
59
|
+
|
60
|
+
# Similar to +option_key+, but for post options instead
|
61
|
+
# of normal subcommands.
|
62
|
+
attr_accessor :post_option_key
|
63
|
+
|
64
|
+
# A usage banner for any post subcommands.
|
65
|
+
attr_accessor :post_banner
|
66
|
+
|
67
|
+
def initialize(command_path)
|
68
|
+
super
|
69
|
+
@post_subcommands = {}
|
70
|
+
end
|
71
|
+
|
72
|
+
# Freeze all post subcommands and the post option parsers in
|
73
|
+
# addition to the command itself.
|
74
|
+
def freeze
|
75
|
+
@post_subcommands.each_value(&:freeze)
|
76
|
+
@post_subcommands.freeze
|
77
|
+
@post_option_parser.freeze
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
# Run a post subcommand using the given context (generally self),
|
82
|
+
# options, and argv. Usually called inside a run block, after
|
83
|
+
# shifting one or more values off the given argv:
|
84
|
+
#
|
85
|
+
# run do |argv, opts, command|
|
86
|
+
# @name = argv.shift
|
87
|
+
# command.run(self, opts, argv)
|
88
|
+
# end
|
89
|
+
def run(context, options, argv)
|
90
|
+
begin
|
91
|
+
process_options(argv, options, @post_option_key, @post_option_parser)
|
92
|
+
rescue ::OptionParser::InvalidOption => e
|
93
|
+
raise CommandFailure.new(e.message, self)
|
94
|
+
end
|
95
|
+
|
96
|
+
arg = argv[0]
|
97
|
+
if arg && @post_subcommands[arg]
|
98
|
+
process_subcommand(@post_subcommands, context, options, argv)
|
99
|
+
else
|
100
|
+
process_command_failure(arg, @post_subcommands, "post ")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
alias run_post_subcommand run
|
104
|
+
|
105
|
+
# Also yield each post subcommand, recursively.
|
106
|
+
def each_subcommand(names = [].freeze, &block)
|
107
|
+
super
|
108
|
+
_each_subcommand(names, @post_subcommands, &block)
|
109
|
+
end
|
110
|
+
|
111
|
+
# Also yield the post banner
|
112
|
+
def each_banner
|
113
|
+
super
|
114
|
+
yield post_banner if post_banner
|
115
|
+
nil
|
116
|
+
end
|
117
|
+
|
118
|
+
# Returns a Command instance for the named post subcommand.
|
119
|
+
# This will autoload the post subcommand if not already loaded.
|
120
|
+
def post_subcommand(name)
|
121
|
+
_subcommand(@post_subcommands, name)
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
# The string to use for the post commands heading in help output.
|
127
|
+
def help_post_commands_heading
|
128
|
+
"Post Commands:"
|
129
|
+
end
|
130
|
+
|
131
|
+
# The string to use for the post options heading in help output.
|
132
|
+
def help_post_options_heading
|
133
|
+
"Post Options:"
|
134
|
+
end
|
135
|
+
|
136
|
+
# Include post subcommands as separate help section.
|
137
|
+
def __help_command_hashes
|
138
|
+
hash = super
|
139
|
+
hash[help_post_commands_heading] = @post_subcommands
|
140
|
+
hash
|
141
|
+
end
|
142
|
+
|
143
|
+
# Include post option parser as separate help section.
|
144
|
+
def __help_option_parser_hashes
|
145
|
+
hash = super
|
146
|
+
hash[help_post_options_heading] = @post_option_parser
|
147
|
+
hash
|
148
|
+
end
|
149
|
+
|
150
|
+
# Also yield each local post subcommand to the block.
|
151
|
+
def each_local_subcommand(&block)
|
152
|
+
super
|
153
|
+
_each_local_subcommand(@post_subcommands, &block)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
register(:post_commands, PostCommands)
|
159
|
+
end
|
160
|
+
end
|