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
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The run_is plugin adds a +run_is+ method that is similar to +is+,
|
4
|
+
# but adds a post subcommand instead of a regular subcommand.
|
5
|
+
#
|
6
|
+
# This does not allow you to set a command description or usage, so it is
|
7
|
+
# not recommended in new code.
|
8
|
+
#
|
9
|
+
# This plugin depends on the is and post_commands plugins.
|
10
|
+
|
11
|
+
#
|
12
|
+
module Rodish
|
13
|
+
module Plugins
|
14
|
+
module RunIs
|
15
|
+
def self.before_load(app)
|
16
|
+
app.plugin :is
|
17
|
+
app.plugin :post_commands
|
18
|
+
end
|
19
|
+
|
20
|
+
module DSLMethods
|
21
|
+
# Similar to +is+, but for post subcommands instead of normal
|
22
|
+
# subcommands.
|
23
|
+
def run_is(command_name, args: 0, &block)
|
24
|
+
_is(:run_on, command_name, args:, &block)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
register(:run_is, RunIs)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The skip_option_parsing plugin allows skipping option parsing
|
4
|
+
# for a command, treating all elements of argv as arguments instead
|
5
|
+
# of options. This is different than the default behavior, where
|
6
|
+
# all options use will fail by default (as no options are supported
|
7
|
+
# by default.
|
8
|
+
#
|
9
|
+
# After loading the plugin, when configuring the command, you can
|
10
|
+
# call skip_options_parsing with the usage banner:
|
11
|
+
#
|
12
|
+
# skip_options_parsing("usage banner")
|
13
|
+
|
14
|
+
#
|
15
|
+
module Rodish
|
16
|
+
module Plugins
|
17
|
+
module SkipOptionParsing
|
18
|
+
module DSLMethods
|
19
|
+
# Skip option parsing for the command. This is different
|
20
|
+
# then the default option parsing, which will error if any
|
21
|
+
# options are given. A banner must be provided, setting
|
22
|
+
# the usage for the command.
|
23
|
+
#
|
24
|
+
# The main reason to use this is if you are going to pass
|
25
|
+
# the entire remaining argv as the argv to another
|
26
|
+
# program.
|
27
|
+
def skip_option_parsing(banner)
|
28
|
+
@command.banner = banner
|
29
|
+
@command.option_parser = :skip
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module CommandMethods
|
34
|
+
private
|
35
|
+
|
36
|
+
# Do not process options if the option parser is set to skip.
|
37
|
+
def process_options(argv, options, option_key, option_parser)
|
38
|
+
super unless option_parser == :skip
|
39
|
+
end
|
40
|
+
|
41
|
+
# Whether the given option parser should be ommitted from the
|
42
|
+
# command help output.
|
43
|
+
def omit_option_parser_from_help?(parser)
|
44
|
+
super || parser == :skip
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
register(:skip_option_parsing, SkipOptionParsing)
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The usages plugin adds the #usages method to the Rodish processor.
|
4
|
+
# This returns a hash for the command help for all commands and subcommands
|
5
|
+
# of the processor.
|
6
|
+
|
7
|
+
#
|
8
|
+
module Rodish
|
9
|
+
module Plugins
|
10
|
+
module Usages
|
11
|
+
module ProcessorMethods
|
12
|
+
# Return a hash of usage strings for the root command and all subcommands,
|
13
|
+
# recursively. The hash has string keys for the command name, and
|
14
|
+
# string values for the help for the command.
|
15
|
+
def usages
|
16
|
+
usages = {}
|
17
|
+
|
18
|
+
command.each_subcommand do |names, command|
|
19
|
+
usages[names.join(" ")] = command.help
|
20
|
+
end
|
21
|
+
|
22
|
+
usages
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
register(:usages, Usages)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The wrapped_options_separator plugin adds wrap to the option
|
4
|
+
# parser, which includes a separator with wrapped content.
|
5
|
+
|
6
|
+
require_relative "_wrap"
|
7
|
+
|
8
|
+
#
|
9
|
+
module Rodish
|
10
|
+
module Plugins
|
11
|
+
module WrappedOptionsSeparator
|
12
|
+
module OptionParserMethods
|
13
|
+
include Wrap_
|
14
|
+
|
15
|
+
# Helper method that takes an array of values, wraps them to the given
|
16
|
+
# limit, and adds each line as a separator. This is useful when you
|
17
|
+
# have a large amount of information you want to display and you want
|
18
|
+
# to wrap if for display to the user when showing options.
|
19
|
+
def wrap(prefix, values, separator: " ", limit: 80)
|
20
|
+
super.each do |line|
|
21
|
+
separator line
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
register(:wrapped_options_separator, WrappedOptionsSeparator)
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rodish
|
4
|
+
MUTEX = Mutex.new
|
5
|
+
private_constant :MUTEX
|
6
|
+
|
7
|
+
# Hash of symbol keys to module values for registered rodish plugins.
|
8
|
+
PLUGINS = {}
|
9
|
+
private_constant :PLUGINS
|
10
|
+
|
11
|
+
# Namespace for Rodish plugins. Plugins do not have to be in this
|
12
|
+
# namespace, but this is what plugins that ship with Rodish use.
|
13
|
+
module Plugins
|
14
|
+
# Load a Rodish plugin. +name+ should be a symbol.
|
15
|
+
def self.fetch(name)
|
16
|
+
MUTEX.synchronize{PLUGINS[name]}
|
17
|
+
end
|
18
|
+
|
19
|
+
# Register a Rodish plugin. +name+ should be a symbol, and +mod+
|
20
|
+
# should be a module.
|
21
|
+
def self.register(name, mod)
|
22
|
+
MUTEX.synchronize{PLUGINS[name] = mod}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/rodish/processor.rb
CHANGED
@@ -1,11 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative "dsl"
|
4
|
+
require_relative "plugins"
|
4
5
|
|
5
6
|
module Rodish
|
6
7
|
module Processor
|
8
|
+
# The root command for the processor.
|
7
9
|
attr_reader :command
|
8
10
|
|
11
|
+
# Load a plugin into the current processor.
|
12
|
+
def plugin(name, ...)
|
13
|
+
mod = load_plugin(name)
|
14
|
+
|
15
|
+
unless mod.respond_to?(:before_load) || mod.respond_to?(:after_load)
|
16
|
+
_plugin_without_before_or_after_load_check(...)
|
17
|
+
end
|
18
|
+
|
19
|
+
mod.before_load(self, ...) if mod.respond_to?(:before_load)
|
20
|
+
extend(mod::ProcessorMethods) if defined?(mod::ProcessorMethods)
|
21
|
+
self::DSL.include(mod::DSLMethods) if defined?(mod::DSLMethods)
|
22
|
+
self::DSL::Command.include(mod::CommandMethods) if defined?(mod::CommandMethods)
|
23
|
+
self::DSL::OptionParser.include(mod::OptionParserMethods) if defined?(mod::OptionParserMethods)
|
24
|
+
mod.after_load(self, ...) if mod.respond_to?(:after_load)
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
9
28
|
# Process an argv array using a new instance of the class that is
|
10
29
|
# extended with Rodish::Processor. Additional arguments are passed to
|
11
30
|
# new when creating the instance.
|
@@ -16,8 +35,6 @@ module Rodish
|
|
16
35
|
# Deliberately do not pass a block here, to reserve
|
17
36
|
# block handling for future use.
|
18
37
|
@command.process(new(*a, **kw), {}, argv)
|
19
|
-
rescue ::OptionParser::InvalidOption => e
|
20
|
-
@command.raise_failure(e.message)
|
21
38
|
end
|
22
39
|
|
23
40
|
# Without a block, returns the Command instance for related subcommand
|
@@ -28,8 +45,11 @@ module Rodish
|
|
28
45
|
# block.
|
29
46
|
def on(*command_names, &block)
|
30
47
|
if block
|
31
|
-
command_name = command_names.pop
|
32
|
-
|
48
|
+
if command_name = command_names.pop
|
49
|
+
dsl(command_names).on(command_name, &block)
|
50
|
+
else
|
51
|
+
dsl(command_names).instance_exec(&block)
|
52
|
+
end
|
33
53
|
else
|
34
54
|
dsl(command_names)
|
35
55
|
end
|
@@ -37,43 +57,55 @@ module Rodish
|
|
37
57
|
|
38
58
|
# Uses the last command name to create a subcommand under the other
|
39
59
|
# named commands, with the block being the commands
|
40
|
-
def is(*command_names, command_name,
|
41
|
-
dsl(command_names).is(command_name,
|
60
|
+
def is(*command_names, command_name, **kw, &block)
|
61
|
+
dsl(command_names).is(command_name, **kw, &block)
|
42
62
|
end
|
43
63
|
|
44
|
-
# Freeze the command when freezing the
|
64
|
+
# Freeze the command and classes related to the processor when freezing the processor.
|
45
65
|
def freeze
|
46
66
|
command.freeze
|
67
|
+
self::DSL.freeze
|
68
|
+
self::DSL::Command.freeze
|
69
|
+
self::DSL::OptionParser.freeze
|
47
70
|
super
|
48
71
|
end
|
49
72
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
73
|
+
private
|
74
|
+
|
75
|
+
def _plugin_without_before_or_after_load_check
|
76
|
+
raise ArgumentError, "plugin doesn't support block" if defined?(yield)
|
77
|
+
end
|
55
78
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
79
|
+
# Load the rodish plugin with the given name, which can be either a module
|
80
|
+
# (used directly), or a symbol (which will load a registered plugin), requiring
|
81
|
+
# the related plugin file if it is not already registered.
|
82
|
+
def load_plugin(name)
|
83
|
+
case name
|
84
|
+
when Module
|
85
|
+
name
|
86
|
+
when Symbol
|
87
|
+
unless mod = Rodish::Plugins.fetch(name)
|
88
|
+
require "rodish/plugins/#{name}"
|
89
|
+
unless mod = Rodish::Plugins.fetch(name)
|
90
|
+
raise RuntimeError, "rodish plugin did not properly register itself: #{name.inspect}"
|
91
|
+
end
|
60
92
|
end
|
61
|
-
end
|
62
93
|
|
63
|
-
|
94
|
+
mod
|
95
|
+
else
|
96
|
+
raise ArgumentError, "invalid argument to plugin: #{name.inspect}"
|
97
|
+
end
|
64
98
|
end
|
65
99
|
|
66
|
-
private
|
67
|
-
|
68
100
|
# Use the array of command names to find the appropriate subcommand
|
69
101
|
# (which may be empty to use the root command), and return a DSL instance
|
70
102
|
# for it.
|
71
103
|
def dsl(command_names)
|
72
104
|
command = self.command
|
73
105
|
command_names.each do |name|
|
74
|
-
command = command.
|
106
|
+
command = command.subcommand(name)
|
75
107
|
end
|
76
|
-
DSL.new(command)
|
108
|
+
self::DSL.new(command)
|
77
109
|
end
|
78
110
|
end
|
79
111
|
end
|
data/lib/rodish.rb
CHANGED
@@ -9,7 +9,22 @@ module Rodish
|
|
9
9
|
# using Rodish::DSL.
|
10
10
|
def self.processor(klass, &block)
|
11
11
|
klass.extend(Processor)
|
12
|
-
|
12
|
+
|
13
|
+
dsl_class = Class.new(DSL)
|
14
|
+
klass.const_set(:DSL, dsl_class)
|
15
|
+
|
16
|
+
command_class = Class.new(Command)
|
17
|
+
dsl_class.const_set(:Command, command_class)
|
18
|
+
|
19
|
+
option_parser_class = Class.new(OptionParser)
|
20
|
+
dsl_class.const_set(:OptionParser, option_parser_class)
|
21
|
+
|
22
|
+
option_parser = option_parser_class.new
|
23
|
+
option_parser.set_banner("")
|
24
|
+
option_parser.freeze
|
25
|
+
command_class.const_set(:DEFAULT_OPTION_PARSER, option_parser)
|
26
|
+
|
27
|
+
klass.instance_variable_set(:@command, dsl_class.command([].freeze, &block))
|
13
28
|
klass
|
14
29
|
end
|
15
30
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rodish
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-03-
|
10
|
+
date: 2025-03-26 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: optparse
|
@@ -60,21 +60,31 @@ email: code@jeremyevans.net
|
|
60
60
|
executables: []
|
61
61
|
extensions: []
|
62
62
|
extra_rdoc_files:
|
63
|
-
- README.rdoc
|
64
|
-
- CHANGELOG
|
65
63
|
- MIT-LICENSE
|
66
64
|
files:
|
67
|
-
- CHANGELOG
|
68
65
|
- MIT-LICENSE
|
69
|
-
- README.rdoc
|
70
66
|
- lib/rodish.rb
|
71
67
|
- lib/rodish/command.rb
|
72
68
|
- lib/rodish/dsl.rb
|
73
69
|
- lib/rodish/errors.rb
|
74
70
|
- lib/rodish/option_parser.rb
|
71
|
+
- lib/rodish/plugins.rb
|
72
|
+
- lib/rodish/plugins/_context_sensitive_help.rb
|
73
|
+
- lib/rodish/plugins/_wrap.rb
|
74
|
+
- lib/rodish/plugins/after_options_hook.rb
|
75
|
+
- lib/rodish/plugins/cache_help_output.rb
|
76
|
+
- lib/rodish/plugins/help_examples.rb
|
77
|
+
- lib/rodish/plugins/help_option_values.rb
|
78
|
+
- lib/rodish/plugins/help_order.rb
|
79
|
+
- lib/rodish/plugins/invalid_args_message.rb
|
80
|
+
- lib/rodish/plugins/is.rb
|
81
|
+
- lib/rodish/plugins/post_commands.rb
|
82
|
+
- lib/rodish/plugins/run_is.rb
|
83
|
+
- lib/rodish/plugins/skip_option_parsing.rb
|
84
|
+
- lib/rodish/plugins/usages.rb
|
85
|
+
- lib/rodish/plugins/wrapped_options_separator.rb
|
75
86
|
- lib/rodish/processor.rb
|
76
|
-
|
77
|
-
homepage: http://github.com/jeremyevans/rodish
|
87
|
+
homepage: https://rodish.jeremyevans.net/
|
78
88
|
licenses:
|
79
89
|
- MIT
|
80
90
|
metadata:
|
@@ -87,8 +97,6 @@ rdoc_options:
|
|
87
97
|
- "--inline-source"
|
88
98
|
- "--title"
|
89
99
|
- 'Rodish: Routing tree argv parser'
|
90
|
-
- "--main"
|
91
|
-
- README.rdoc
|
92
100
|
require_paths:
|
93
101
|
- lib
|
94
102
|
required_ruby_version: !ruby/object:Gem::Requirement
|
data/CHANGELOG
DELETED
data/README.rdoc
DELETED
@@ -1,265 +0,0 @@
|
|
1
|
-
= Rodish
|
2
|
-
|
3
|
-
Rodish parses an argv array using a routing tree approach. It is
|
4
|
-
designed to make it easy to implement command line applications
|
5
|
-
that support multiple levels of subcommands, with options at each
|
6
|
-
level.
|
7
|
-
|
8
|
-
= Installation
|
9
|
-
|
10
|
-
gem install rodish
|
11
|
-
|
12
|
-
= Source Code
|
13
|
-
|
14
|
-
Source code is available on GitHub at https://github.com/jeremyevans/rodish
|
15
|
-
|
16
|
-
= Simple Example
|
17
|
-
|
18
|
-
Here's a simple commented example with a single subcommand:
|
19
|
-
|
20
|
-
require "rodish"
|
21
|
-
|
22
|
-
# This just creates a normal Ruby class. For each argv parse, Rodish will
|
23
|
-
# create an instance of this class
|
24
|
-
class CliExample
|
25
|
-
|
26
|
-
# This allows instances of the class to be instantiated with or without
|
27
|
-
# a default person.
|
28
|
-
def initialize(default_person=nil)
|
29
|
-
@default_person = default_person
|
30
|
-
end
|
31
|
-
|
32
|
-
# This installs the Rodish processor into CliExample. It also extends the
|
33
|
-
# CliExample class with the Rodish::Processor module). The block provided
|
34
|
-
# is evaluated in the context of a Rodish::DSL instance.
|
35
|
-
Rodish.processor(self) do
|
36
|
-
|
37
|
-
# This method call creates a hello subcommand of the current/root command.
|
38
|
-
# If the given argv is for the hello subcommand, the block will be
|
39
|
-
# executed in the context of the CliExample instance.
|
40
|
-
on "hello" do
|
41
|
-
|
42
|
-
# This adds a usage string and a -p options for the hello subcommand.
|
43
|
-
# The block passed is used to set the options via the optparse library.
|
44
|
-
options("cli-example hello [options]") do
|
45
|
-
on("-p", "--person=name", "say hello to specific person")
|
46
|
-
end
|
47
|
-
|
48
|
-
run do |opts|
|
49
|
-
"Hello #{opts[:person] || @default_person || 'World'}"
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# This requests Rodish to process the provided argv. Rodish will determine
|
56
|
-
# the related command block to execute and execute it. The return value of
|
57
|
-
# that block will be returned to the caller.
|
58
|
-
CliExample.process(["hello"])
|
59
|
-
# => "Hello World"
|
60
|
-
|
61
|
-
# Additional arguments passed to .process are passed to .new. In this
|
62
|
-
# example, this sets the default person.
|
63
|
-
CliExample.process(["hello"], "Adol")
|
64
|
-
# => "Hello Adol"
|
65
|
-
|
66
|
-
# This shows an example of passing an option to a subcommand, and using
|
67
|
-
# the option value when returning a response.
|
68
|
-
CliExample.process(["hello", "-p", "Feena"], "Adol")
|
69
|
-
# => "Hello Feena"
|
70
|
-
|
71
|
-
= Rodish DSL
|
72
|
-
|
73
|
-
Inside the <tt>Rodish.processor</tt> block, you are in the context of the root
|
74
|
-
command. The following methods are available for configuring the processing of
|
75
|
-
the command.
|
76
|
-
|
77
|
-
== +on+
|
78
|
-
|
79
|
-
The +on+ method adds a subcommand of the current command, and yields to the
|
80
|
-
block to configure the subcommand. All of the methods described in the Rodish
|
81
|
-
DSL section can be executed inside the +on+ block, and arbitrary levels of
|
82
|
-
subcommands are supported.
|
83
|
-
|
84
|
-
== +options+
|
85
|
-
|
86
|
-
The +options+ method sets up an options parser for the current command. The
|
87
|
-
default options parser disallows any options. Options are parsed into a hash,
|
88
|
-
which is yielded to commands (as in the above example).
|
89
|
-
|
90
|
-
This method requires a String argument for the usage for the current command.
|
91
|
-
You can also provide a +key+ keyword argument, to put parsed options into
|
92
|
-
a subhash of the main options hash, which can be useful when options are
|
93
|
-
parsed at multiple levels.
|
94
|
-
|
95
|
-
If a block is provided, it is executed in the context of a Rodish::OptionParser
|
96
|
-
instance. Rodish::OptionParser is a subclass of Ruby's standard OptionParser
|
97
|
-
(from +optparse+), with a few additional methods.
|
98
|
-
|
99
|
-
== +args+
|
100
|
-
|
101
|
-
The +args+ method sets the number of arguments accepted when running the command.
|
102
|
-
The default for +args+ is +0+. You can provide either an Integer to accept a
|
103
|
-
fixed number of arguments, or a Range to allow any number of arguments in that
|
104
|
-
range.
|
105
|
-
|
106
|
-
The method also accepts an +invalid_args_message+ keyword argument for the
|
107
|
-
message, to set the message to display if an invalid number of arguments is
|
108
|
-
provided.
|
109
|
-
|
110
|
-
== +run+
|
111
|
-
|
112
|
-
The +run+ method sets the block to run for the current command. If the
|
113
|
-
command accepts a fixed number of arguments, those arguments are yielded
|
114
|
-
as the first arguments to the command. If the command accepts a range of
|
115
|
-
argument numbers, then the remaining argv array will be passed as the
|
116
|
-
first argument.
|
117
|
-
|
118
|
-
The block will be passed two additional arguments, the options already
|
119
|
-
parsed, and the current Rodish::Command object.
|
120
|
-
|
121
|
-
== +is+
|
122
|
-
|
123
|
-
The +is+ method is a shortcut for calling the +on+ method and +run+ method.
|
124
|
-
For example:
|
125
|
-
|
126
|
-
is "hello" do
|
127
|
-
:world
|
128
|
-
end
|
129
|
-
|
130
|
-
is equivalent to:
|
131
|
-
|
132
|
-
on "hello" do
|
133
|
-
run do
|
134
|
-
:world
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
The +is+ method also takes +args+ and +invalid_args_message+ keyword arguments.
|
139
|
-
|
140
|
-
== +before+
|
141
|
-
|
142
|
-
The +before+ method takes a block, and this block is executed before command
|
143
|
-
or subcommand execution, in the same context that the +run+ block would be
|
144
|
-
executed in. It is passed the remaining argv array and the already parsed
|
145
|
-
options. This is not called if an invalid subcommand is requested and there
|
146
|
-
is no run block for the command.
|
147
|
-
|
148
|
-
== +after_options+
|
149
|
-
|
150
|
-
The +after_options+ method takes a block, and this block is executed
|
151
|
-
directly after options parsing, in the same context that the +run+ block would be
|
152
|
-
executed in. It is passed the remaining argv array and the already parsed
|
153
|
-
options.
|
154
|
-
|
155
|
-
== +skip_option_parsing+
|
156
|
-
|
157
|
-
The +skip_option_parsing+ method makes the command do no option parsing,
|
158
|
-
treating all elements of the remaining argv as options. It requires a
|
159
|
-
usage string for the command, similar to +options+.
|
160
|
-
|
161
|
-
== +run_on+
|
162
|
-
|
163
|
-
The +run_on+ method is similar to +on+, except it creates a post subcommand
|
164
|
-
instead of a normal subcommand. Post subcommands allow the +run+ block
|
165
|
-
to parse part of the remaining argv array, and then call a subcommand with
|
166
|
-
the modified (or a new) argv array. You dispatch to post subcommands
|
167
|
-
inside the +run+ block by calling +run+ on the command argument:
|
168
|
-
|
169
|
-
on "hello" do
|
170
|
-
args(2...)
|
171
|
-
|
172
|
-
run do |argv, opts, command|
|
173
|
-
@name = argv.shift
|
174
|
-
command.run(self, opts, argv)
|
175
|
-
end
|
176
|
-
|
177
|
-
run_on "world" do
|
178
|
-
run do
|
179
|
-
"Hello #{@name.upcase} World!"
|
180
|
-
end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
# process(%w[hello foo world])
|
185
|
-
# => "Hello FOO World!"
|
186
|
-
|
187
|
-
== +run_is+
|
188
|
-
|
189
|
-
The +run_is+ method operates similarly to +is+, but adds a post subcommand
|
190
|
-
instead of a normal subcommand.
|
191
|
-
|
192
|
-
== +post_options+
|
193
|
-
|
194
|
-
The +post_options+ method sets an option parser that is used for post
|
195
|
-
subcommands. This parses options from the argv array that passed to
|
196
|
-
+command.run+, before calling the related subcommand. Example:
|
197
|
-
|
198
|
-
on "hello" do
|
199
|
-
args(2...)
|
200
|
-
|
201
|
-
post_options("Usage: hello name [options] subcommand ...") do
|
202
|
-
on("-c", "--cap", "capitalize instead of uppercase")
|
203
|
-
end
|
204
|
-
|
205
|
-
run do |argv, opts, command|
|
206
|
-
@name = argv.shift
|
207
|
-
command.run(self, opts, argv)
|
208
|
-
end
|
209
|
-
|
210
|
-
run_is "world" do |opts|
|
211
|
-
name = opts[:cap] ? @name.capitalize : @name.upcase
|
212
|
-
"Hello #{name} World!"
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
# process(%w[hello foo world])
|
217
|
-
# => "Hello FOO World!"
|
218
|
-
# process(%w[hello foo -c world])
|
219
|
-
# => "Hello Foo World!"
|
220
|
-
|
221
|
-
== +autoload_subcommand_dir+
|
222
|
-
|
223
|
-
The +autoload_subcommand_dir+ takes a directory, and will autoload
|
224
|
-
subcommands from the given directory. Filenames ending in +.rb+ in
|
225
|
-
this directory will be treated as subcommands, and requiring the
|
226
|
-
file should add the appropriate subcommand.
|
227
|
-
|
228
|
-
This allows you to design complex command line programs where only
|
229
|
-
the parts of the program needed to handle the given argv are loaded.
|
230
|
-
|
231
|
-
== +autoload_post_subcommand_dir+
|
232
|
-
|
233
|
-
The +autoload_post_subcommand_dir+ operates the same as
|
234
|
-
+autoload_subcommand_dir+, but it handles post subcommands instead of
|
235
|
-
normal subcommands.
|
236
|
-
|
237
|
-
= Examples
|
238
|
-
|
239
|
-
The tests that ship with Rodish fully cover all of Rodish's functionality.
|
240
|
-
|
241
|
-
If you would like to view a production example using Rodish, which
|
242
|
-
uses most of Rodish's features, please see UbiCli, which is part of
|
243
|
-
Ubicloud:
|
244
|
-
|
245
|
-
* Main class: https://github.com/ubicloud/ubicloud/blob/main/lib/ubi_cli.rb
|
246
|
-
* Commands (separate command per file): https://github.com/ubicloud/ubicloud/tree/main/cli-commands
|
247
|
-
|
248
|
-
= History
|
249
|
-
|
250
|
-
Rodish was extracted from Ubicloud (https://github.com/ubicloud/ubicloud),
|
251
|
-
and is the argv processor used in Ubicloud's command line interface.
|
252
|
-
|
253
|
-
= Naming
|
254
|
-
|
255
|
-
The name Rodish was chosen because Rodish uses an API similar (-ish) to the Roda
|
256
|
-
web framework (http://roda.jeremyevans.net), and the library is designed for
|
257
|
-
use in applications executed from a shell (sh).
|
258
|
-
|
259
|
-
= License
|
260
|
-
|
261
|
-
MIT
|
262
|
-
|
263
|
-
= Author
|
264
|
-
|
265
|
-
Jeremy Evans <code@jeremyevans.net>
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Rodish
|
4
|
-
# Rodish::SkipOptionParser is used when option parsing should be
|
5
|
-
# skipped, treating all entries in argv as arguments.
|
6
|
-
class SkipOptionParser
|
7
|
-
# A usage banner to use for the related command.
|
8
|
-
attr_reader :banner
|
9
|
-
|
10
|
-
# The same as banner, but ending in a newline, similarly
|
11
|
-
# to how OptionParser#to_s works.
|
12
|
-
attr_reader :to_s
|
13
|
-
|
14
|
-
def initialize(banner)
|
15
|
-
@banner = "Usage: #{banner}".freeze
|
16
|
-
@to_s = (@banner + "\n").freeze
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|