"clim" is slim command line interface builder for Crystal.
"clim" = "cli" + "slim"
- Slim implementation.
- Intuitive code.
- Option types
-
Int8
-
Int16
-
Int32
-
Int64
-
UInt8
-
UInt16
-
UInt32
-
UInt64
-
Float32
-
Float64
-
String
-
Bool
-
Array(Int8)
-
Array(Int16)
-
Array(Int32)
-
Array(Int64)
-
Array(UInt8)
-
Array(UInt16)
-
Array(UInt32)
-
Array(UInt64)
-
Array(Float32)
-
Array(Float64)
-
Array(String)
-
- Default values for option
- Required flag for option
- Nested sub commands
-
--help
option - Customizable help message
-
version
macro - Command name alias
Add this to your application's shard.yml
:
dependencies:
clim:
github: at-grandpa/clim
version: 0.8.1
src/minimum.cr
require "clim"
class MyCli < Clim
main do
run do |opts, args|
puts "#{args.join(", ")}!"
end
end
end
MyCli.start(ARGV)
$ crystal build -o ./minimum src/minimum.cr
$ ./minimum foo bar baz
foo, bar, baz!
src/hello.cr
require "clim"
module Hello
class Cli < Clim
main do
desc "Hello CLI tool."
usage "hello [options] [arguments] ..."
version "Version 0.1.0"
option "-g WORDS", "--greeting=WORDS", type: String, desc: "Words of greetings.", default: "Hello"
option "-n NAME", "--name=NAME", type: Array(String), desc: "Target name.", default: ["Taro"]
run do |opts, args|
print "#{opts.greeting}, "
print "#{opts.name.join(", ")}!"
print "\n"
end
end
end
end
Hello::Cli.start(ARGV)
$ crystal build src/hello.cr
$ ./hello --help
Hello CLI tool.
Usage:
hello [options] [arguments] ...
Options:
-g WORDS, --greeting=WORDS Words of greetings. [type:String] [default:"Hello"]
-n NAME, --name=NAME Target name. [type:Array(String)] [default:["Taro"]]
--help Show this help.
--version Show version.
$ ./hello -n Ichiro -n Miko -g 'Good night'
Good night, Ichiro, Miko!
src/fake-crystal-command.cr
require "clim"
module FakeCrystalCommand
class Cli < Clim
main do
desc "Fake Crystal command."
usage "fcrystal [sub_command] [arguments]"
run do |opts, args|
puts opts.help_string # => help string.
end
sub "tool" do
desc "run a tool"
usage "fcrystal tool [tool] [arguments]"
run do |opts, args|
puts "Fake Crystal tool!!"
end
sub "format" do
desc "format project, directories and/or files"
usage "fcrystal tool format [options] [file or directory]"
run do |opts, args|
puts "Fake Crystal tool format!!"
end
end
end
sub "spec" do
desc "build and run specs"
usage "fcrystal spec [options] [files]"
run do |opts, args|
puts "Fake Crystal spec!!"
end
end
end
end
end
FakeCrystalCommand::Cli.start(ARGV)
Build and run.
$ crystal build -o ./fcrystal src/fake-crystal-command.cr
$ ./fcrystal
Fake Crystal command.
Usage:
fcrystal [sub_command] [arguments]
Options:
--help Show this help.
Sub Commands:
tool run a tool
spec build and run specs
Show sub command help.
$ ./fcrystal tool --help
run a tool
Usage:
fcrystal tool [tool] [arguments]
Options:
--help Show this help.
Sub Commands:
format format project, directories and/or files
Run sub sub command.
$ ./fcrystal tool format
Fake Crystal tool format!!
require "clim"
class MyCli < Clim
# ...
end
Description of the command. It is displayed in Help.
class MyCli < Clim
main do
desc "My Command Line Interface."
run do |opts, args|
# ...
end
end
end
Usage of the command. It is displayed in Help.
class MyCli < Clim
main do
usage "mycli [sub-command] [options] ..."
run do |opts, args|
# ...
end
end
end
An alias for the command. It can be specified only for subcommand.
class MyCli < Clim
main do
run do |opts, args|
# ...
end
sub "sub" do
alias_name "alias1", "alias2"
run do |opts, args|
puts "sub_command run!!"
end
end
end
end
$ ./mycli sub
sub_command run!!
$ ./mycli alias1
sub_command run!!
$ ./mycli alias2
sub_command run!!
You can specify the string to be displayed with --version
.
class MyCli < Clim
main do
version "mycli version: 1.0.1"
run do |opts, args|
# ...
end
end
end
$ ./mycli --version
mycli version: 1.0.1
If you want to display it even with -v
, add short: "-v"
.
class MyCli < Clim
main do
version "mycli version: 1.0.1", short: "-v"
run do |opts, args|
# ...
end
end
end
$ ./mycli --version
mycli version: 1.0.1
$ ./mycli -v
mycli version: 1.0.1
The short help option is not set by default. If you want help to appear by specifying -h
, specify help short: "-h"
.
(However, it should not conflict with other options.)
class MyCli < Clim
main do
desc "help directive test."
usage "mycli [options] [arguments]"
help short: "-h"
run do |opts, args|
# ...
end
end
end
$ ./mycli -h
help directive test.
Usage:
mycli [options] [arguments]
Options:
-h, --help Show this help.
$ ./mycli --help
help directive test.
Usage:
mycli [options] [arguments]
Options:
-h, --help Show this help.
In addition to -h
, you can specify any single character. For example, help short: "-a"
.
You can specify multiple options for the command.
Argument | Description | Example | Required | Default |
---|---|---|---|---|
First argument | short or long name | -t TIMES , --times TIMES |
true | - |
Second argument | long name | --times TIMES |
false | - |
type |
option type | type: Array(Float32) |
false | String |
desc |
option description | desc: "option description." |
false | "Option description." |
default |
default value | default: [1.1_f32, 2.2_f32] |
false | nil |
required |
required flag | required: true |
false | false |
class MyCli < Clim
main do
option "--greeting=WORDS", desc: "Words of greetings.", default: "Hello"
option "-n NAME", "--name=NAME", type: Array(String), desc: "Target name.", default: ["Taro"]
run do |opts, args|
puts typeof(opts.greeting) # => String
puts typeof(opts.name) # => Array(String)
end
end
end
The type of the option is determined by the default
and required
patterns.
Number
For example Int8
.
default |
required |
Type |
---|---|---|
exist | true |
Int8 (default: Your specified value.) |
exist | false |
Int8 (default: Your specified value.) |
not exist | true |
Int8 |
not exist | false |
Int8 | Nil |
String
default |
required |
Type |
---|---|---|
exist | true |
String (default: Your specified value.) |
exist | false |
String (default: Your specified value.) |
not exist | true |
String |
not exist | false |
String | Nil |
Bool
default |
required |
Type |
---|---|---|
exist | true |
Bool (default: Your specified value.) |
exist | false |
Bool (default: Your specified value.) |
not exist | true |
Bool |
not exist | false |
Bool (default: false ) |
Array
default |
required |
Type |
---|---|---|
exist | true |
Array(T) (default: Your specified value.) |
exist | false |
Array(T) (default: Your specified value.) |
not exist | true |
Array(T) |
not exist | false |
Array(T) (default: [] of T ) |
For Bool, you do not need to specify arguments for short or long.
class MyCli < Clim
main do
option "-v", "--verbose", type: Bool, desc: "Verbose."
run do |opts, args|
puts typeof(opts.verbose) # => Bool
end
end
end
Option method names are long name if there is a long, and short name if there is only a short. Also, hyphens are replaced by underscores.
class MyCli < Clim
main do
option "-n", type: String, desc: "name." # => short name only.
option "--my-age", type: Int32, desc: "age." # => long name only.
run do |opts, args|
puts typeof(opts.n) # => (String | Nil)
puts typeof(opts.my_age) # => (Int32 | Nil)
end
end
end
You can customize the help message by help_template
block. It must be placed in main block. Also it needs to return String
. Block arguments are desc : String
, usage : String
, options : HelpOptionsType
and sub_commands : HelpSubCommandsType
.
help_template_test.cr
require "clim"
class MyCli < Clim
main do
help_template do |desc, usage, options, sub_commands|
options_help_lines = options.map do |option|
option[:names].join(", ") + "\n" + " #{option[:desc]}"
end
base = <<-BASE_HELP
#{usage}
#{desc}
options:
#{options_help_lines.join("\n")}
BASE_HELP
sub = <<-SUB_COMMAND_HELP
sub commands:
#{sub_commands.map(&.[](:help_line)).join("\n")}
SUB_COMMAND_HELP
sub_commands.empty? ? base : base + sub
end
desc "Your original command line interface tool."
usage <<-USAGE
usage: my_cli [--version] [--help] [-P PORT|--port=PORT]
[-h HOST|--host=HOST] [-p PASSWORD|--password=PASSWORD]
USAGE
version "version 1.0.0"
option "-P PORT", "--port=PORT", type: Int32, desc: "Port number.", default: 3306
option "-h HOST", "--host=HOST", type: String, desc: "Host name.", default: "localhost"
option "-p PASSWORD", "--password=PASSWORD", type: String, desc: "Password."
run do |opts, args|
end
sub "sub_command" do
desc "my_cli's sub_comand."
usage <<-USAGE
usage: my_cli sub_command [--help] [-t|--tree]
[--html-path=PATH]
USAGE
option "-t", "--tree", type: Bool, desc: "Tree."
option "--html-path=PATH", type: String, desc: "Html path."
run do |opts, args|
end
end
end
end
MyCli.start(ARGV)
$ crystal run src/help_template_test.cr -- --help
usage: my_cli [--version] [--help] [-P PORT|--port=PORT]
[-h HOST|--host=HOST] [-p PASSWORD|--password=PASSWORD]
Your original command line interface tool.
options:
-P PORT, --port=PORT
Port number.
-h HOST, --host=HOST
Host name.
-p PASSWORD, --password=PASSWORD
Password.
--help
Show this help.
--version
Show version.
sub commands:
sub_command my_cli's sub_comand.
options:
# `options` type
alias HelpOptionsType = Array(NamedTuple(
names: Array(String),
type: Int8.class | Int32.class | ... | String.class | Bool.clsss, # => Support Types
desc: String,
default: Int8 | Int32 | ... | String | Bool, # => Support Types,
required: Bool,
help_line: String
))
# `options` example
[
{
names: ["-g WORDS", "--greeting=WORDS"],
type: String,
desc: "Words of greetings.",
default: "Hello",
required: false,
help_line: " -g WORDS, --greeting=WORDS Words of greetings. [type:String] [default:\"Hello\"]",
},
{
names: ["-n NAME"],
type: Array(String),
desc: "Target name.",
default: ["Taro"],
required: true,
help_line: " -n NAME Target name. [type:Array(String)] [default:[\"Taro\"]] [required]",
},
{
names: ["--help"],
type: Bool,
desc: "Show this help.",
default: false,
required: false,
help_line: " --help Show this help.",
},
]
sub_commands:
# `sub_commands` type
alias HelpSubCommandsType = Array(NamedTuple(
names: Array(String),
desc: String,
help_line: String
))
# `sub_commands` example
[
{
names: ["abc", "def", "ghi"],
desc: "abc command.",
help_line: " abc, def, ghi abc command.",
},
{
names: ["abcdef", "ghijkl", "mnopqr"],
desc: "abcdef command.",
help_line: " abcdef, ghijkl, mnopqr abcdef command.",
},
]
class MyCli < Clim
main do
run do |opts, args|
opts.help_string # => help string
end
end
end
$ make spec
- Fork it ( https://github.com/at-grandpa/clim/fork )
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin my-new-feature)
- Create a new Pull Request
- at-grandpa - creator, maintainer