Benry-CmdApp
($Release: 0.1.0 $)
What's This?
Benry-CmdApp is a framework to create command-line application.
If you want create command-line application which takes sub-commands
like git
, docker
, or npm
, Benry-CmdApp is the solution.
Base idea:
- Sub-command (= action) is defined as a method in Ruby.
- Commnad-line arguments are passed to action method as positional arguments.
- Command-line options are passed to action method as keyword arguments.
For example:
<command> foo
in command-line invokes action methodfoo()
in Ruby.<command> foo arg1 arg2
invokesfoo("arg1", "arg2")
.<command> foo arg --opt=val
invokesfoo("arg", opt: "val")
.
Links:
- Document: https://kwatch.github.io/benry-ruby/benry-cmdapp.html
- GitHub: https://github.com/kwatch/benry-ruby/tree/main/benry-cmdapp
- Changes: https://github.com/kwatch/benry-ruby/tree/main/benry-cmdapp/CHANGES.md
Benry-CmdApp requires Ruby >= 2.3.
Table of Contents
- What's This?
- Install
- Usage
- Action
- Method Name and Action Name
- Parameter Name in Help Message of Action
- Options
- Option Definition Format
- Option Value Validation
- Callback for Option Value
- Boolean (On/Off) Option
- Prefix of Action Name
- Invoke Other Action
- Action Alias
- Default Action
- Default Help
- Private (Hidden) Action
- Private (Hidden) Option
- Configuratoin and Customization
- Q & A
- Q: How to Append Some Tasks to Existing Action?
- Q: How to Re-define Existing Action?
- Q: How to Delete Existing Action/Alias?
- Q: How to Show Entering Into or Exitting From Action?
- Q: How to Enable/Disable Color Mode?
- Q: How to Define Multiple Option, like
-I
Option of Ruby? - Q: How to Specify Detailed Description of Option?
- Q: How to Copy All Options from Other Action?
- Q: What is the Difference Between
prefix(alias_of:)
andprefix(action:)
? - Q: How to Change Order of Options in Help Message?
- Q: Is It Possible to Make Action Names Emphasised or Weaken?
- Q: Is It Possible to Add Metadata to Action or Option?
- Q: How to Make Error Messages I18Ned?
- License and Copyright
Install
$ gem install benry-cmdapp
Usage
Action
- Inherit action class and define action methods in it.
- An action class can have several action methods.
- It is ok to define multiple action classes.
- Command-line arguments are passed to action method as positional arguments.
File: ex01.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
## action
class MyAction < Benry::CmdApp::Action # !!!!
@action.("print greeting message") # !!!!
def hello(user="world") # !!!!
puts "Hello, #{user}!"
end
end
## configuration
config = Benry::CmdApp::Config.new("sample app", "1.0.0")
config.default_help = true
## run application
app = Benry::CmdApp::Application.new(config)
status_code = app.main()
exit status_code
Output:
[bash]$ ruby ex01.rb hello # action
Hello, world!
[bash]$ ruby ex01.rb hello Alice # action + argument
Hello, Alice!
Help message of command:
[bash]$ ruby ex01.rb -h # or `--help`
ex01.rb (1.0.0) -- sample app
Usage:
$ ex01.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
-V, --version : print version
Actions:
hello : print greeting message
Help message of action:
[bash]$ ruby ex01.rb -h hello
ex01.rb hello -- print greeting message
Usage:
$ ex01.rb hello [<user>]
Method Name and Action Name
- Method name
print_
results in action nameprint
. This is useful to define actions which name is same as Ruby keyword or popular functions. - Method name
foo_bar_baz
results in action namefoo-bar-baz
. - Method name
foo__bar__baz
results in action namefoo:bar:baz
.
File: ex02.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
## 'print_' => 'print'
@action.("sample #1")
def print_() # !!!!
puts __method__
end
## 'foo_bar_baz' => 'foo-bar-baz'
@action.("sample #2")
def () # !!!!
puts __method__
end
## 'foo__bar__baz' => 'foo:bar:baz'
@action.("sample #3")
def () # !!!!
puts __method__
end
end
config = Benry::CmdApp::Config.new("test app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message:
[bash]$ ruby ex02.rb --help
ex02.rb -- test app
Usage:
$ ex02.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions:
foo-bar-baz : sample #2
foo:bar:baz : sample #3
print : sample #1
Output:
[bash]$ ruby ex02.rb print # `print_` method
print_
[bash]$ ruby ex02.rb foo-bar-baz # `foo_bar_baz` method
foo_bar_baz
[bash]$ ruby ex02.rb foo:bar:baz # `foo__bar__baz` method
foo__bar__baz
Parameter Name in Help Message of Action
In help message of action, positional parameters of action methods are printed under the name conversion rule.
- Parameter
foo
is printed as<foo>
. - Parameter
foo_bar_baz
is printed as<foo-bar-baz>
. - Parameter
foo_or_bar_or_baz
is printed as<foo|bar|baz>
.
In addition, positional parameters are printed in different way according to its kind.
- If parameter
foo
is required (= doesn't have default value), it will be printed as<foo>
. - If parameter
foo
is optional (= has default value), it will be printed as[<foo>]
. - If parameter
foo
is variable length (=*foo
style), it will be printed as[<foo>...]
.
File: ex03.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("parameter names test")
def test1(aaa, bbb_or_ccc, ddd=nil, eee=nil, *fff) # !!!!
# ...
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message:
[bash]$ ruby ex03.rb -h test1
hoge.rb test1 -- parameter names test
Usage:
$ ex03.rb test1 <aaa> <bbb|ccc> [<ddd> [<eee> [<fff>...]]] # !!!!
Options
- Action can take command-line options.
- Option values specified in command-line are passed to actio method as keyword arguments.
File: ex04.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
## action
class MyAction < Benry::CmdApp::Action
@action.("print greeting message")
@option.(:lang, "-l, --lang=<en|fr|it>", "language") # !!!!
def hello(user="world", lang: "en") # !!!!
case lang
when "en" ; puts "Hello, #{user}!"
when "fr" ; puts "Bonjour, #{user}!"
when "it" ; puts "Ciao, #{user}!"
else
raise "#{lang}: unknown language."
end
end
end
## configuration
config = Benry::CmdApp::Config.new("sample app", "1.0.0")
config.default_help = true
## run application
app = Benry::CmdApp::Application.new(config)
status_code = app.main()
exit status_code
Output:
[bash]$ ruby ex04.rb hello
Hello, world!
[bash]$ ruby ex04.rb hello -l fr # !!!!
Bonjour, world!
[bash]$ ruby ex04.rb hello --lang=it # !!!!
Ciao, world!
- An action can have multiple options.
- Option format can have indentation spaces, for example
' --help'
.
File: ex05.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
## action
class MyAction < Benry::CmdApp::Action
@action.("print greeting message")
@option.(:lang , "-l, --lang=<en|fr|it>", "language")
@option.(:repeat, " --repeat=<N>", "repeat <N> times") # !!!!
def hello(user="world", lang: "en", repeat: "1")
#p repeat.class #=> String # !!!!
repeat.to_i.times do # !!!!
case lang
when "en" ; puts "Hello, #{user}!"
when "fr" ; puts "Bonjour, #{user}!"
when "it" ; puts "Ciao, #{user}!"
else
raise "#{lang}: unknown language."
end
end
end
end
## configuration
config = Benry::CmdApp::Config.new("sample app", "1.0.0")
config.default_help = true
## run application
app = Benry::CmdApp::Application.new(config)
status_code = app.main()
exit status_code
Output:
[bash]$ ruby ex05.rb hello Alice -l fr --repeat=3
Bonjour, Alice!
Bonjour, Alice!
Bonjour, Alice!
Help message:
[bash]$ ruby ex05.rb -h hello
ex05.rb hello -- print greeting message
Usage:
$ ex05.rb hello [<options>] [<user>]
Options:
-l, --lang=<en|fr|it> : language # !!!!
--repeat=<N> : repeat <N> times # !!!!
For usability reason, Benry::CmdApp supports --lang=<val>
style long option
and doesn't support --lang <val>
style option.
Benry::CmdApp regards --lang <val>
as 'long option without argument'
and 'argument for command'.
[bash]$ ruby ex05.rb hello --lang fr # ``--lang fr`` != ``--lang=fr``
[ERROR] --lang: argument required.
Option Definition Format
Option definition format should be one of:
- (short option)
-q
: no values. - (short option)
-f <file>
: value required. - (short option)
-i[<width>]
: value is optional. - (long option)
--quiet
: no values. - (long option)
--file=<file>
: value required. - (long option)
--indent[=<width>]
: value is optional. - (short & long)
-q, --quiet
: no values. - (short & long)
-f, --file=<file>
: value required. - (short & long)
-i, --indent[=<width>]
: value is optional.
File: ex06.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
## short options
@action.("short options")
@option.(:quiet , "-q" , "quiet mode") # none
@option.(:file , "-f <file>" , "filename") # required
@option.(:indent , "-i[<N>]" , "indent width") # optional
def test1(quiet: false, file: nil, indent: nil)
puts "quiet=#{quiet.inspect}, file=#{file.inspect}, indent=#{indent.inspect}"
end
## long options
@action.("long options")
@option.(:quiet , "--quiet" , "quiet mode") # none
@option.(:file , "--file=<file>" , "filename") # required
@option.(:indent , "--indent[=<N>]" , "indent width") # optional
def test2(quiet: false, file: nil, indent: nil)
puts "quiet=#{quiet.inspect}, file=#{file.inspect}, indent=#{indent.inspect}"
end
## short and long options
@action.("short and long options")
@option.(:quiet , "-q, --quiet" , "quiet mode") # none
@option.(:file , "-f, --file=<file>" , "filename") # required
@option.(:indent , "-i, --indent[=<N>]" , "indent width") # optional
def test3(quiet: false, file: nil, indent: nil)
puts "quiet=#{quiet.inspect}, file=#{file.inspect}, indent=#{indent.inspect}"
end
end
config = Benry::CmdApp::Config.new("test app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex06.rb test1 -q -f readme.txt -i4
quiet=true, file="readme.txt", indent="4"
[bash]$ ruby ex06.rb test2 --quiet --file=readme.txt --indent=4
quiet=true, file="readme.txt", indent="4"
[bash]$ ruby ex06.rb test3 -q -f readme.txt -i4
quiet=true, file="readme.txt", indent="4"
[bash]$ ruby ex06.rb test3 --quiet --file=readme.txt --indent=4
quiet=true, file="readme.txt", indent="4"
Optional argument example:
[bash]$ ruby ex06.rb test1 -i # ``-i`` results in ``true``
quiet=false, file=nil, indent=true
[bash]$ ruby ex06.rb test1 -i4 # ``-i4`` results in ``4``
quiet=false, file=nil, indent="4"
[bash]$ ruby ex06.rb test2 --indent # ``--indent`` results in ``true``
quiet=false, file=nil, indent=true
[bash]$ ruby ex06.rb test2 --indent=4 # ``--indent=4`` results in ``4``
quiet=false, file=nil, indent="4"
Help message:
[bash]$ ruby ex06.rb -h test1
ex06.rb test1 -- short options
Usage:
$ ex06.rb test1 [<options>]
Options:
-q : quiet mode
-f <file> : filename
-i[<N>] : indent width
[bash]$ ruby ex06.rb -h test2
ex06.rb test2 -- long options
Usage:
$ ex06.rb test2 [<options>]
Options:
--quiet : quiet mode
--file=<file> : filename
--indent[=<N>] : indent width
[bash]$ ruby ex06.rb -h test3
ex06.rb test3 -- short and long options
Usage:
$ ex06.rb test3 [<options>]
Options:
-q, --quiet : quiet mode
-f, --file=<file> : filename
-i, --indent[=<N>] : indent width
Option Value Validation
@option.()
can validate option value via keyword argument.
type: <class>
specifies option value class. Currently supportsInteger
,Float
,TrueClass
, andDate
.rexp: <rexp>
specifies regular expression of option value.enum: <array>
specifies available values as option value.range: <range>
specifies range of option value.
File: ex07.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
## action
class MyAction < Benry::CmdApp::Action
@action.("print greeting message")
@option.(:lang , "-l, --lang=<en|fr|it>", "language",
enum: ["en", "fr", "it"], # !!!!
rexp: /\A\w\w\z/) # !!!!
@option.(:repeat, " --repeat=<N>", "repeat <N> times",
type: Integer, range: 1..10) # !!!!
def hello(user="world", lang: "en", repeat: 1)
#p repeat.class #=> Integer
repeat.times do
case lang
when "en" ; puts "Hello, #{user}!"
when "fr" ; puts "Bonjour, #{user}!"
when "it" ; puts "Ciao, #{user}!"
else
raise "#{lang}: unknown language."
end
end
end
end
## configuration
config = Benry::CmdApp::Config.new("sample app", "1.0.0")
config.default_help = true
## run application
app = Benry::CmdApp::Application.new(config)
status_code = app.main()
exit status_code
Output:
[bash]$ ruby ex07.rb hello -l japan
[ERROR] -l japan: pattern unmatched.
[bash]$ ruby ex07.rb hello -l ja
[ERROR] -l ja: expected one of en/fr/it.
[bash]$ ruby ex07.rb hello --repeat=abc
[ERROR] --repeat=abc: integer expected.
[bash]$ ruby ex07.rb hello --repeat=100
[ERROR] --repeat=100: Too large (max: 10).
Callback for Option Value
@option.()
can take a block argument which is a callback for option value.
Callback can:
- Do custom validation of option value.
- Convert option value into other value.
File: ex08.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
## action
class MyAction < Benry::CmdApp::Action
@action.("print greeting message")
@option.(:lang , "-l, --lang=<en|fr|it>", "language",
enum: ["en", "fr", "it", "EN", "FR", "IT"],
rexp: /\A\w\w\z/) {|v| v.downcase } # !!!!
@option.(:repeat, " --repeat=<N>", "repeat <N> times",
type: Integer) {|v| # !!!!
v > 0 or raise "not positive value." # !!!!
v # !!!!
} # !!!!
def hello(user="world", lang: "en", repeat: 1)
repeat.times do
case lang
when "en" ; puts "Hello, #{user}!"
when "fr" ; puts "Bonjour, #{user}!"
when "it" ; puts "Ciao, #{user}!"
else
raise "#{lang}: unknown language."
end
end
end
end
## configuration
config = Benry::CmdApp::Config.new("sample app", "1.0.0")
config.default_help = true
## run application
app = Benry::CmdApp::Application.new(config)
status_code = app.main()
exit status_code
Output:
[bash]$ ruby ex08.rb hello -l FR # converted into lowercase
Bonjour, world!
[bash]$ ruby ex08.rb hello --repeat=0
[ERROR] --repeat=0: not positive value.
Boolean (On/Off) Option
Benry::CmdApp doesn't support --[no-]foobar
style option.
Instead, define boolean (on/off) option.
- Specify
type: TrueClass
to@option.()
. - Option value
true
,yes
, andon
are converted into true. - Option value
false
,no
, andoff
are converted into false.
File: ex09.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("flag test")
@option.(:verbose, "--verbose[=<on|off>]", # !!!!
"verbose mode",
type: TrueClass) # !!!!
def flagtest(verbose: false) # !!!!
puts "verbose=#{verbose}"
end
end
config = Benry::CmdApp::Config.new("sample app", "1.0.0")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex09.rb flagtest --verbose=on # on
verbose=true
[bash]$ ruby ex09.rb flagtest --verbose=off # off
verbose=false
[bash]$ ruby ex09.rb flagtest --verbose=true # on
verbose=true
[bash]$ ruby ex09.rb flagtest --verbose=false # off
verbose=false
[bash]$ ruby ex09.rb flagtest --verbose=yes # on
verbose=true
[bash]$ ruby ex09.rb flagtest --verbose=no # off
verbose=false
[bash]$ ruby ex09.rb flagtest --verbose=abc # error
[ERROR] --verbose=abc: boolean expected.
If you want default value of flag to true
, use value:
keyword argument.
value:
keyword argument in@option.()
specifies the substitute value instead oftrue
when no option value specified in command-line.
File: ex10.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("flag test")
@option.(:verbose, "-q, --quiet", "quiet mode",
value: false) # !!!!
def flagtest2(verbose: true) # !!!!
puts "verbose=#{verbose.inspect}"
end
end
config = Benry::CmdApp::Config.new("git helper")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex10.rb flagtest2 # true if '--quiet' NOT specified
verbose=true
[bash]$ ruby ex10.rb flagtest2 --quiet # false if '--quiet' specified
verbose=false
[bash]$ ruby ex10.rb flagtest2 --quiet=on # error
[ERROR] --quiet=on: unexpected argument.
In above example, --quiet=on
will be error because option is defined as
@option.(:verbose, "-q, --quiet", ...)
which means that this option takes no arguments.
If you want to allow --quiet=on
, specify option argument and type: TrueClass
.
...(snip)...
@action.("flag test")
@option.(:verbose, "-q, --quiet[=<on|off]", "quiet mode", # !!!!
type: TrueClass, value: false) # !!!!
def flagtest2(verbose: true)
puts "verbose=#{verbose.inspect}"
end
...(snip)...
Prefix of Action Name
prefix: "foo:bar"
in action class adds prefixfoo:bar:
to each action name.- Method name
def baz__test()
withprefix: "foo:bar"
results in action namefoo:bar:baz:test
.
File: ex11.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
prefix "foo:bar" # !!!!
@action.("test action #1")
def test1() # action name: 'foo:bar:test1'
puts __method__
end
@action.("test action #2")
def baz__test2() # action name: 'foo:bar:baz:test2'
puts __method__
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex11.rb foo:bar:test1
test1
[bash]$ ruby ex11.rb foo:bar:baz:test2
baz__test2
Help message:
[bash]$ ruby ex11.rb -h
ex11.rb -- sample app
Usage:
$ ex11.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions:
foo:bar:baz:test2 : test action #2
foo:bar:test1 : test action #1
prefix: "foo:bar", action: :test
definesfoo:bar
action (intead offoo:bar:test
) withtest()
method.
File: ex12.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
prefix "foo:bar", action: :test3_ # !!!!
## or:
#prefix "foo:bar", action: "test3" # !!!!
@action.("test action #1")
def test1() # action name: 'foo:bar:test1'
puts __method__
end
@action.("test action #3")
def test3_() # action name: 'foo:bar'
puts __method__
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex12.rb foo:bar:test1
test1
[bash]$ ruby ex12.rb foo:bar:test3
[ERROR] foo:bar:test2: unknown action.
[bash]$ ruby ex12.rb foo:bar
test3_
Help message:
[bash]$ ruby ex12.rb -h
ex12.rb -- sample app
Usage:
$ ex12.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions:
foo:bar : test action #3
foo:bar:test1 : test action #1
Invoke Other Action
run_action!()
invokes other action.run_action_once()
invokes other action only once. This is equivarent to 'prerequisite task' feature in task runner application.
File: ex13.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("create build dir")
def prepare()
puts "rm -rf build"
puts "mkdir build"
end
@action.("build something")
def build()
run_action_once("prepare") # !!!!
run_action_once("prepare") # skipped because already invoked
puts "echo 'README' > build/README.txt"
puts "zip -r build.zip build"
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex13.rb build
rm -rf build # invoked only once!!!!
mkdir build # invoked only once!!!!
echo 'README' > build/README.txt
zip -r build.zip build
- When looped action is detected, Benry::CmdApp aborts action.
File: ex14.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class LoopedAction < Benry::CmdApp::Action
@action.("test #1")
def test1()
run_action_once("test2")
end
@action.("test #2")
def test2()
run_action_once("test3")
end
@action.("test #3")
def test3()
run_action_once("test1") # !!!!
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex14.rb test1
[ERROR] test1: looped action detected.
[bash]$ ruby ex14.rb test3
[ERROR] test3: looped action detected.
Action Alias
- Alias of action provides alternative short name of action.
File: ex15.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
prefix "foo:bar"
@action.("test action #1")
def test1() # action name: 'foo:bar:test1'
puts __method__
end
end
Benry::CmdApp.action_alias "test", "foo:bar:test1" # !!!!
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex15.rb test # alias name
test1
[bash]$ ruby ex15.rb foo:bar:test1 # original action name
test1
Help message:
[bash]$ ruby ex15.rb -h
ex15.rb -- sample app
Usage:
$ ex15.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions:
foo:bar:test1 : test action #1
test : alias to 'foo:bar:test1' action
- Alias can include positional and keyword arguments in definition.
File: ex16.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class MyAction < Benry::CmdApp::Action
@action.("print greeting message")
@option.(:lang, "-l, --lang=<lang>", "language", enum: ["en", "fr", "it"])
def hello(user="world", lang: "en")
case lang
when "en" ; puts "Hello, #{user}!"
when "fr" ; puts "Bonjour, #{user}!"
when "it" ; puts "Ciao, #{user}!"
else
raise "#{lang}: unknown language."
end
end
end
Benry::CmdApp.action_alias("bonjour", "hello", "--lang=fr") # !!!!
Benry::CmdApp.action_alias("ciao" , "hello", "Bob", "-l", "it") # !!!!
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex16.rb hello
Hello, world!
[bash]$ ruby ex16.rb bonjour # !!!!
Bonjour, world!
[bash]$ ruby ex16.rb bonjour Alice # !!!!
Bonjour, Alice!
[bash]$ ruby ex16.rb ciao # !!!!
Ciao, Bob!
Default Action
config.default = "test1"
defines default action. In this case, actiontest1
will be invoked if action name not specified in command-line.- Default action name is shown in help message.
File: ex17.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action #1")
def test1()
puts __method__
end
end
config = Benry::CmdApp::Config.new("sample app")
config.default_action = "test1" # !!!!
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex17.rb test1
test1
[bash]$ ruby ex17.rb # no action name!!!!
test1
Help message:
[bash]$ ruby ex17.rb -h
ex17.rb -- sample app
Usage:
$ ex17.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions: (default: test1) # !!!!
test1 : test action #1
Default Help
config.default_help = true
prints help message if action not specified in command-line.- This is very useful when you don't have proper default action. It's recommended.
config.default_action
is prior thanconfig.default_help
.
File: ex18.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action #1")
def test1()
puts __method__
end
end
config = Benry::CmdApp::Config.new("sample app")
config.default_help = true # !!!!
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex18.rb # no action name!!!!
ex18.rb -- sample app
Usage:
$ ex18.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions:
test1 : test action #1
Private (Hidden) Action
- If action method is private, Benry::CmdApp regards that action as private.
- Private actions are hidden in help message.
- Private actions are shown when
-a
or--all
option enabled and specified.
File: ex20.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action #1")
def test1()
puts __method__
end
@action.("test action #2")
def test2()
puts __method__
end
private :test2 # !!!! private method !!!!
private # !!!! private method !!!!
@action.("test action #3")
def test3()
puts __method__
end
end
config = Benry::CmdApp::Config.new("sample app")
config.option_all = true # !!!! enable '-a, --all' option !!!!
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message (without -a
nor --all
):
[bash]$ ruby ex20.rb -h
ex20.rb -- sample app
Usage:
$ ex20.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
-a, --all : list all actions/options including private (hidden) ones
Actions:
test1 : test action #1
Help message (with -a
or --all
):
[bash]$ ruby ex20.rb -h --all # !!!!
ex20.rb -- sample app
Usage:
$ ex20.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
-a, --all : list all actions/options including private (hidden) ones
Actions:
test1 : test action #1
test2 : test action #2 # !!!!
test3 : test action #3 # !!!!
Private (Hidden) Option
- Options which name stars with
_
are treated as private option. - Private options are hidden in help message of action.
- Private options are shown when
-a
or--all
option enabled and specified.
File: ex21.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action")
@option.(:verbose, "-v", "verbose mode")
@option.(:_debug , "-D", "debug mode") # !!!!
def test1(verbose: false, _debug: false)
puts "verbose=#{verbose}, _debug=#{_debug}"
end
end
config = Benry::CmdApp::Config.new("sample app")
config.option_all = true # !!!! enable '-a, --all' option !!!!
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message (without -a
nor --all
):
[bash]$ ruby ex21.rb -h test1
ex21.rb test1 -- test action
Usage:
$ ex21.rb test1 [<options>]
Options:
-v : verbose mode
Help message (with -a
or --all
)
[bash]$ ruby ex21.rb -h --all test1 # !!!!
ex21.rb test1 -- test action
Usage:
$ ex21.rb test1 [<options>]
Options:
-v : verbose mode
-D : debug mode # !!!!
Configuratoin and Customization
Application Configuration
Benry::CmdApp::Config
class configures application behaviour.
config.app_desc = "..."
sets command description which is shown in help message. (required)config.app_version = "1.0.0"
enables-V
and--version
option, and prints version number if-V
or--version
option specified. (default:nil
)config.app_command = "<command>"
sets command name which is shown in help message. (default:File.basname($0)
)config.app_detail = "<text>"
sets detailed description of command which is showin in help message. (default:nil
)config.default_action = "<action>"
sets default action name. (default:nil
)config.default_help = true
prints help message if no action names specified in command-line. (default:false
)config.option_help = true
enables-h
and--help
options. (default:true
)config.option_all = true
enables-a
and--all
options which shows private (hidden) actions and options into help message. (default:false
)config.option_verbose = true
enables-v
and--verbose
options which sets$QUIET_MODE = false
. (default:false
)config.option_quiet = true
enables-q
and--quiet
options which sets$QUIET_MODE = true
. (default:false
)config.option_color = true
enables--color[=<on|off>]
option which sets$COLOR_MODE = true/false
. This affects to help message colorized or not. (default:false
)config.option_debug = true
enables-D
and--debug
options which sets$DEBUG_MODE = true
. (default:false
)config.option_trace = true
enables-T
and--trace
options which sets$TRACE_MODE = true
. Entering into and exitting from action are reported when trace mode is on. (default:false
)config.help_aliases = true
addsAliases:
section in help message. (default:false
)config.help_sections = [["<title>", "<text>"], ...]
adds section title and text into help message. (default:[]
)config.help_postamble = "<text>"
sets postamble text in help message, such as 'Examples:' or 'Tips:'. (default:nil
)config.feat_candidate = true
enables feature to list action names starting with 'foo:' when action name specified in command-line isfoo:
. (default:true
)config.format_help = " %-18s : %s"
sets format of options and actions in help message. (default:" \e[1m%-18s\e[0m : %s"
)config.format_usage = " $ %s %s"
sets format of usage in help message. (default:" $ \e[1m%s\e[0m %s"
)config.format_heading = "[%s]"
sets format of heading in help message. (default:"\e[34m%s\e[0m"
)
File: ex22.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
config = Benry::CmdApp::Config.new("sample app", "1.0.0")
#config.default_help = true
config.class.instance_methods(false).each do |name|
next if name =~ /=$/
next if ! config.class.method_defined?("#{name}=")
val = config.__send__(name)
puts "%-25s = %s" % ["config.#{name}", val.inspect]
end
Output:
[bash]$ ruby ex22.rb
config.app_desc = "sample app"
config.app_version = "1.0.0"
config.app_name = "ex22.rb"
config.app_command = "ex22.rb"
config.app_detail = nil
config.default_action = nil
config.default_help = false
config.option_help = true
config.option_all = false
config.option_verbose = false
config.option_quiet = false
config.option_color = false
config.option_debug = false
config.option_trace = false
config.help_aliases = false
config.help_sections = []
config.help_postamble = nil
config.feat_candidate = true
config.format_help = " \e[1m%-18s\e[0m : %s"
config.format_usage = " $ \e[1m%s\e[0m %s"
config.format_heading = "\e[34m%s\e[0m"
config.format_appname = "\e[1m%s\e[0m"
Customization of Global Options
To add custom global options:
- (1) Create global option schema object.
- (2) Add custom options to it.
- (3) Pass it to
Application.new()
.
File: ex23.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action")
def test1()
puts __method__
end
end
## (1) create global option shema
config = Benry::CmdApp::Config.new("sample app")
schema = Benry::CmdApp::AppOptionSchema.new(config) # !!!!
## (2) add custom options to it
schema.add(:logging, "--logging", "enable logging") # !!!!
## (3) pass it to ``Application.new()``
app = Benry::CmdApp::Application.new(config, schema) # !!!!
exit app.main()
Help message:
[bash]$ ruby ex23.rb -h
ex23.rb -- sample app
Usage:
$ ex23.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
--logging : enable logging # !!!!
Actions:
test1 : test action
To customize global options entirely:
- (1) Create empty
AppOptionSchema
object. - (2) Add global options as you want.
- (3) Create and execute Application object with it.
File: ex24.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
## (1) Create empty ``AppOptionSchema`` object.
schema = Benry::CmdApp::AppOptionSchema.new(nil) # !!!!
## (2) Add global options as you want.
schema.add(:help , "-h, --help" , "print help message")
schema.add(:version, "-V, --version", "print version")
schema.add(:all , "-a, --all" , "list all actions/options")
schema.add(:verbose, "-v, --verbose", "verbose mode")
schema.add(:quiet , "-q, --quiet" , "quiet mode")
schema.add(:color , "--color[=<on|off>]", "enable/disable color", type: TrueClass)
schema.add(:debug , "-D, --debug" , "set $DEBUG_MODE to true")
schema.add(:trace , "-T, --trace" , "report enter into and exit from action")
## (3) Create and execute Application object with it.
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config, schema) # !!!!
exit app.main()
Customization of Global Option Behaviour
- (1) Define subclass of
Application
class. - (2) Override
#do_toggle_global_switches()
method. - (3) Create and execute subclass object of
Application
.
File: ex25.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
## (1) Define subclass of ``Application`` class.
class MyApplication < Benry::CmdApp::Application
## (2) Override ``#do_toggle_global_switches()`` method.
def do_toggle_global_switches(_args, global_opts)
super
## here is original behaviour
#global_opts.each do |key, val|
# case key
# when :verbose ; $QUIET_MODE = ! val
# when :quiet ; $QUIET_MODE = val
# when :color ; $COLOR_MODE = val
# when :debug ; $DEBUG_MODE = val
# when :trace ; $TRACE_MODE = val
# else ; # do nothing
# end
#end
end
end
## (3) Create and execute subclass object of ``Application``.
config = Benry::CmdApp::Config.new("sample app")
app = MyApplication.new(config) # !!!!
exit app.main()
Of course, prepending custom module to Application class is also effective way.
File: ex26.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
module MyApplicationMod
def do_toggle_global_switches(_args, global_opts)
# ....
end
end
Benry::CmdApp::Application.prepend(MyApplicationMod) # !!!!
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Custom Hook of Application
- (1) Define subclass of Application class.
- (2) Override callback method.
- (3) Create and execute custom application object.
File: ex27.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action")
def test1()
$logger.info("logging message") if $logger
end
end
## (1) Define subclass of Application class
class MyApplication < Benry::CmdApp::Application # !!!!
## (2) Override callback method
def do_callback(args, global_opts) # !!!!
#p @config
#p @schema
if global_opts[:logging]
require 'logger'
$logger = Logger.new(STDOUT)
end
## if return :SKIP, action skipped (not invoked).
#return :SKIP
end
## or:
#def do_handle_global_options(args, global_opts)
# if global_opts[:logging]
# require 'logger'
# $logger = Logger.new(STDOUT)
# end
# super
#end
end
## (3) create and execute custom application object
config = Benry::CmdApp::Config.new("sample app")
schema = Benry::CmdApp::AppOptionSchema.new(config)
schema.add(:logging, "--logging", "enable logging")
app = MyApplication.new(config, schema) # !!!!
exit app.main()
- [EXPERIMENTAL] Instead of defining subclass of Application, you can pass callback block to Application object.
File: ex28.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action")
def test1()
$logger.info("logging message") if $logger
end
end
config = Benry::CmdApp::Config.new("sample app")
schema = Benry::CmdApp::AppOptionSchema.new(config)
schema.add(:logging, "--logging", "enable logging")
app = Benry::CmdApp::Application.new(config, schema) do # !!!!
|args, global_opts, config| # !!!!
if global_opts[:logging] # !!!!
require 'logger' # !!!!
$logger = Logger.new(STDOUT) # !!!!
end # !!!!
#:SKIP # !!!!
end # !!!!
exit app.main()
Customization of Command Help Message
If you want to just add more text into command help message,
set config.app_detail
, config.help_sections
, and/or config.help_postamble
.
File: ex29.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action #1")
def hello(user="world")
puts "Hello, #{user}!"
end
end
config = Benry::CmdApp::Config.new("sample app")
config.app_detail = "Document: https://...." # !!!!
config.help_sections = [ # !!!!
["Example:", " $ <command> hello Alice"], # !!!!
] # !!!!
config.help_postamble = "(Tips: ....)" # !!!!
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message:
[bash]$ ruby ex29.rb -h
ex29.rb -- sample app
Document: https://.... # !!!! app.detail !!!!
Usage:
$ ex29.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions:
hello : test action #1
Example: # !!!! help_sections !!!!
$ <command> hello Alice # !!!! help_sections !!!!
(Tips: ....) # !!!! help_postamble !!!!
If you want to change behaviour of building command help message:
- (1) Define subclass of
Benry::CmdApp::AppHelpBuilder
class. - (2) Override methods.
- (3) Create an instance object of the class.
- (4) Pass it to Application object.
File: ex30.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("greeting message")
def hello(user="world")
puts "Hello, #{user}!"
end
end
## (1) Define subclass of ``Benry::CmdApp::AppHelpBuilder`` class.
class MyAppHelpBuilder < Benry::CmdApp::AppHelpBuilder
## (2) Override methods.
def (all=false, format=nil)
super
end
def build_preamble(all=false)
super
end
def build_usage(all=false)
super
end
def (all=false, format=nil)
super
end
def build_actions(all=false, format=nil)
super
end
def build_postamble(all=false)
super
end
def heading(str)
super
end
end
## (3) Create an instance object of the class.
config = Benry::CmdApp::Config.new("sample app")
schema = Benry::CmdApp::AppOptionSchema.new(config)
schema.add(:logging, "--logging", "enable logging")
help_builder = MyAppHelpBuilder.new(config, schema) # !!!!
## (4) Pass it to Application object.
app = Benry::CmdApp::Application.new(config, schema, help_builder) # !!!!
exit app.main()
More simple way:
- (1) Create a module and override methods of
Benry::CmdApp::AppHelpBuilder
class. - (2) Prepend it to
Benry::CmdApp::AppHelpBuilder
class. - (3) Create and execute Application object.
File: ex31.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("greeting message")
def hello(user="world")
puts "Hello, #{user}!"
end
end
## (1) Create a module and override methods of ``AppHelpBuilder`` class.
module MyHelpBuilderMod
def (all=false, format=nil)
super
end
def build_preamble(all=false)
super
end
def build_usage(all=false)
super
end
def (all=false, format=nil)
super
end
def build_actions(all=false, format=nil)
super
end
def build_postamble(all=false)
super
end
def heading(str)
super
end
end
## (2) Prepend it to ``Benry::CmdApp::AppHelpBuilder`` class.
Benry::CmdApp::AppHelpBuilder.prepend(MyHelpBuilderMod)
## (3) Create and execute Application object.
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Customization of Action Help Message
If you want to just add more text into action help message,
pass detail:
and/or postamble:
keyword arguments to @action.()
.
File: ex32.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action #1",
detail: "Document: https://....", # !!!!
postamble: "(Tips: ....)") # !!!!
def hello(user="world")
puts "Hello, #{user}!"
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message:
[bash]$ ruby ex32.rb -h
ex32.rb hello -- test action #1
Document: https://.... # !!!!
Usage:
$ ex32.rb hello [<user>]
(Tips: ....) # !!!!
If you want to change behaviour of building action help message:
- (1) Create a module and override methods of
Benry::CmdApp::ActionHelpBuilder
class. - (2) Prepend it to
Benry::CmdApp::ActionHelpBuilder
class. - (3) Create and execute Application object.
File: ex33.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("greeting message")
def hello(user="world")
puts "Hello, #{user}!"
end
end
## (1) Create a module and override methods of ``ActionHelpBuilder`` class.
module MyActionHelpBuilderMod
def (command, all=false)
super
end
def build_preamble(command, all=false)
super
end
def build_usage(command, all=false)
super
end
def (command, all=false)
super
end
def build_postamble(command, all=false)
super
end
def heading(str)
super
end
end
## (2) Prepend it to ``Benry::CmdApp::ActionHelpBuilder`` class.
Benry::CmdApp::ActionHelpBuilder.prepend(MyActionHelpBuilderMod) # !!!!
## (3) Create and execute Application object.
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Another way:
- (1) Define subclass of
ActionHelpBuilder
class. - (2) Set it to
ACTION_HELP_BUILDER_CLASS
constant value. - (3) Create and execute Application object.
File: ex34.rb
#!/usr/bin/env ruby
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("greeting message")
def hello(user="world")
puts "Hello, #{user}!"
end
end
## (1) Define subclass of ``ActionHelpBuilder`` class.
class MyActionHelpBuilder < Benry::CmdApp::ActionHelpBuilder
def (command, all=false)
super
end
def build_preamble(command, all=false)
super
end
def build_usage(command, all=false)
super
end
def (command, all=false)
super
end
def build_postamble(command, all=false)
super
end
def heading(str)
super
end
end
## (2) Set it to ``ACTION_HELP_BUILDER_CLASS`` constant value.
Benry::CmdApp.module_eval do
remove_const :ACTION_HELP_BUILDER_CLASS
const_set :ACTION_HELP_BUILDER_CLASS, MyActionHelpBuilder
end
## (3) Create and execute Application object.
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Q & A
Q: How to Append Some Tasks to Existing Action?
A: (a) Use method alias, or (b) use prepend.
File: ex41.rb
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action #1")
def hello(user="world")
puts "Hello, #{user}!"
end
@action.("test action #2")
def hi(user="world")
puts "Hi, #{user}!"
end
end
## (a) use method alias
class SampleAction # open existing class
alias __old_hello hello # alias of existing method
def hello(user="world") # override existing method
puts "---- >8 ---- >8 ----"
__old_hello(user) # call original method
puts "---- 8< ---- 8< ----"
end
end
## (b) use prepend
module SampleMod # define new module
def hi(user="world") # override existing method
puts "~~~~ >8 ~~~~ >8 ~~~~"
super # call original method
puts "~~~~ 8< ~~~~ 8< ~~~~"
end
end
SampleAction.prepend(SampleMod) # prepend it to existing class
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex41.rb hello
---- >8 ---- >8 ----
Hello, world!
---- 8< ---- 8< ----
[bash]$ ruby ex41.rb hi Alice
~~~~ >8 ~~~~ >8 ~~~~
Hi, Alice!
~~~~ 8< ~~~~ 8< ~~~~
Q: How to Re-define Existing Action?
A: Remove existing action at first, and re-define action.
File: ex42.rb
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("sample action")
def hello() # !!!!
puts "Hello, world!"
end
end
Benry::CmdApp.delete_action("hello") # !!!!
class OtherAction < Benry::CmdApp::Action
@action.("other action") # !!!!
def hello() # !!!!
puts "Ciao, world!"
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message:
[bash]$ ruby ex42.rb -h
ex42.rb -- sample app
Usage:
$ ex42.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions:
hello : other action # !!!!
Q: How to Delete Existing Action/Alias?
A: Call Benry::CmdApp.delete_action("<action>")
or Benry::CmdApp.delete_alias("<alias>")
.
Q: How to Show Entering Into or Exitting From Action?
A: Set config.option_trace = true
and pass -T
(or --trace
) option.
File: ex43.rb
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("preparation")
def prepare()
puts "... prepare something ..."
end
@action.("build")
def build()
run_action_once("prepare")
puts "... build something ..."
end
end
config = Benry::CmdApp::Config.new("sample app")
config.option_trace = true # !!!!
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex43.rb -T build # !!!!
## enter: build
## enter: prepare
... prepare something ...
## exit: prepare
... build something ...
## exit: build
Q: How to Enable/Disable Color Mode?
A: Set config.option_color = true
and pass --color=on
or --color=off
option.
File: ex44.rb
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("greeting message")
def hello(user="world")
puts "Hello, #{user}!"
end
end
config = Benry::CmdApp::Config.new("sample app")
config.option_color = true # !!!!
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message:
[bash]$ ruby ex44.rb -h
ex44.rb -- sample app
Usage:
$ ex44.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
--color[=<on|off>] : enable/disable color # !!!!
Actions:
hello : greeting message
[bash]$ ruby ex44.rb -h --color=off # !!!!
[bash]$ ruby ex44.rb -h --color=on # !!!!
Q: How to Define Multiple Option, like -I
Option of Ruby?
A: Provide block parameter on @option.()
.
File: ex45.rb
require 'benry/cmdapp'
class TestAction < Benry::CmdApp::Action
@action.("multiple option test")
@option.(:path, "-I <path>", "path") {|, key, val| # !!!!
arr = [key] || [] # !!!!
arr << val # !!!!
arr # !!!!
## or: # !!!!
#(options[key] || []) << val # !!!!
} # !!!!
def test(path: [])
puts "path=#{path.inspect}" #=> path=["/tmp", "/var/tmp"]
end
end
config = Benry::CmdApp::Config.new("test app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Output:
[bash]$ ruby ex45.rb test -I /tmp -I /var/tmp # !!!!
path=["/tmp", "/var/tmp"] # !!!!
Q: How to Specify Detailed Description of Option?
A: Add detail:
keyword argument to @option.()
.
File: ex46.rb
require 'benry/cmdapp'
class TestAction < Benry::CmdApp::Action
@action.("detailed description test")
@option.(:mode, "-m <mode>", "output mode", detail: <<"END")
v, verbose: print many output
q, quiet: print litte output
c, compact: print summary output
END
def test(mode: nil)
puts "mode=#{mode.inspect}"
end
end
config = Benry::CmdApp::Config.new("test app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message:
[bash]$ ruby ex46.rb -h test
ex46.rb test -- detailed description test
Usage:
$ ex46.rb test [<options>]
Options:
-m <mode> : output mode
v, verbose: print many output
q, quiet: print litte output
c, compact: print summary output
Q: How to Copy All Options from Other Action?
A: Use @copy_options.()
.
File: ex47.rb
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("test action #1")
@option.(:verbose, "-v, --verbose", "verbose mode")
@option.(:file, "-f, --file=<file>", "filename")
@option.(:indent, "-i, --indent[=<N>]", "indent")
def test1(verbose: false, file: nil, indent: nil)
puts "verbose=#{verbose}, file=#{file}, indent=#{indent}"
end
@action.("test action #2")
@copy_options.("test1") # !!!! copy options from test1 !!!!
@option.(:debug, "-D, --debug", "debug mode")
def test2(verbose: false, file: nil, indent: nil, debug: false)
puts "verbose=#{verbose}, file=#{file}, indent=#{indent}, debug=#{debug}"
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message of test2
action:
[bash]$ ruby ex47.rb -h test2
ex47.rb test2 -- test action #2
Usage:
$ ex47.rb test2 [<options>]
Options:
-v, --verbose : verbose mode # copied!!
-f, --file=<file> : filename # copied!!
-i, --indent[=<N>] : indent # copied!!
-D, --debug : debug mode
Q: What is the Difference Between prefix(alias_of:)
and prefix(action:)
?
A: The former defines an alias, and the latter doesn't.
File: ex48.rb
require 'benry/cmdapp'
class AaaAction < Benry::CmdApp::Action
prefix "aaa", alias_of: :print_ # (or) alias_of: "print"
@action.("test #1")
def print_()
puts "test"
end
end
class BbbAction < Benry::CmdApp::Action
prefix "bbb", action: :print_ # (or) action: "print"
@action.("test #2")
def print_()
puts "test"
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message:
[bash]$ ruby ex48.rb
ex48.rb -- sample app
Usage:
$ ex48.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions:
aaa : alias of 'aaa:print' action # !!!!
aaa:print : test #1
bbb : test #2 # !!!!
In the above example, alias aaa
is defined due to prefix(alias_of:)
,
and action bbb
is not an alias due to prefix(action:)
.
Q: How to Change Order of Options in Help Message?
A: Call AppOptionSchema#sort_options_in_this_order()
.
File: ex49.rb
require 'benry/cmdapp'
config = Benry::CmdApp::Config.new("sample app", "1.0.0",
option_all: true,
option_quiet: true,
option_color: true,
)
schema = Benry::CmdApp::AppOptionSchema.new(config)
keys = [:all, :quiet, :color, :help, :version] # !!!!
schema.(*keys) # !!!!
app = Benry::CmdApp::Application.new(config, schema)
## or:
#app = Benry::CmdApp::Application.new(config)
#app.schema.sort_options_in_this_order(*keys) # !!!!
exit app.main()
Help message:
[bash]$ ruby ex49.rb -h
ex49.rb (1.0.0) -- sample app
Usage:
$ ex49.rb [<options>] [<action> [<arguments>...]]
Options:
-a, --all : list all actions/options including private (hidden) ones
-q, --quiet : quiet mode
--color[=<on|off>] : enable/disable color
-h, --help : print help message (of action if action specified)
-V, --version : print version
Actions:
Q: Is It Possible to Make Action Names Emphasised or Weaken?
A: Yes. When you pass important: true
to @action.()
, that action will be printed with unerline in help message. When you pass important: false
, that action will be printed in gray color.
File: ex50.rb
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("empasized", important: true) # !!!!
def test1()
end
@action.("weaken", important: false) # !!!!
def test2()
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Help message:
[bash]$ ruby ex50.rb -h
ex50.rb -- sample app
Usage:
$ ex50.rb [<options>] [<action> [<arguments>...]]
Options:
-h, --help : print help message (of action if action specified)
Actions:
test1 : empasized # !!!! printed with underline !!!!
test2 : weaken # !!!! printed in gray color !!!!
Q: Is It Possible to Add Metadata to Action or Option?
A: Yes. Pass tag:
keyword argument to @action.()
or @option.()
.
tag:
keyword argument accept any type of value such as symbol, string, array, and so on.- Currenty, Benry::CmdApp doesn't provide the good way to use it effectively. This feature may be used by command-line application or framework based on Benry::CmdApp.
File: ex51.rb
require 'benry/cmdapp'
class SampleAction < Benry::CmdApp::Action
@action.("print greeting message", tag: :important) # !!!!
@option.(:repeat, "-r <N>", "repeat N times", tag: :important) # !!!!
def hello(user="world", repeat: nil)
(repeat || 1).times do
puts "Hello, #{user}!"
end
end
end
config = Benry::CmdApp::Config.new("sample app")
app = Benry::CmdApp::Application.new(config)
exit app.main()
Q: How to Make Error Messages I18Ned?
A: Currently not supported. May be supported in the future release.
License and Copyright
- $License: MIT License $
- $Copyright: copyright(c) 2023 [email protected] $