clim
Version, currently 0.1.431 versions
- 0.17.1latestApr 11, 2021
- 0.17.0not indexedApr 11, 2021
- 0.16.0not indexedApr 11, 2021
- 0.15.0not indexedApr 11, 2021
- 0.14.0not indexedApr 11, 2021
- 0.13.0not indexedApr 11, 2021
- 0.12.0not indexedApr 11, 2021
- 0.11.2not indexedApr 11, 2021
- 0.11.1not indexedApr 11, 2021
- 0.11.0not indexedApr 11, 2021
- 0.10.0not indexedApr 11, 2021
- 0.9.0not indexedApr 11, 2021
- 0.8.2not indexedApr 11, 2021
- 0.8.1not indexedApr 11, 2021
- 0.8.0not indexedApr 11, 2021
- 0.7.0not indexedApr 11, 2021
- 0.6.0not indexedApr 11, 2021
- 0.5.0not indexedApr 11, 2021
- 0.4.1not indexedApr 11, 2021
- 0.4.0not indexedApr 11, 2021
- 0.3.2not indexedApr 11, 2021
- 0.3.1not indexedApr 11, 2021
- 0.3.0not indexedApr 11, 2021
- 0.2.2not indexedApr 11, 2021
- 0.2.1not indexedApr 11, 2021
- 0.2.0not indexedApr 11, 2021
- 0.1.5not indexedApr 11, 2021
- 0.1.4not indexedApr 11, 2021
- 0.1.3not indexedApr 11, 2021
- 0.1.2not indexedApr 11, 2021
- 0.1.1not indexedApr 11, 2021
github.com/at-grandpa/clim
Slim command line interface builder for Crystal.
126 stars
7 dependents
License: MIT
Nothing has been indexed for 0.1.4 yet. The tag is recorded, its shard.yml has not been read, so the manifest and dependency list below are empty because they are unknown rather than because they are absent.
Installation
# Add this to your shard.yml
dependencies:
clim:
github: at-grandpa/clim
version: ~> 0.1.4Then run:
shards installshard.yml
No shard.yml has been indexed for 0.1.4. You can read it on the repository.
Dependencies
Unknown: the shard.yml for this version has not been read yet.
README
This README is the one indexed from the repository at its latest ref, not from the tag for this version.
# clim
"clim" is slim command line interface builder for Crystal.
_"clim" = "cli" + "slim"_







## Goals
* Slim implementation.
* Intuitive code.
## Support
- [x] Option types
- [x] `Int8`
- [x] `Int16`
- [x] `Int32`
- [x] `Int64`
- [x] `UInt8`
- [x] `UInt16`
- [x] `UInt32`
- [x] `UInt64`
- [x] `Float32`
- [x] `Float64`
- [x] `String`
- [x] `Bool`
- [x] `Array(Int8)`
- [x] `Array(Int16)`
- [x] `Array(Int32)`
- [x] `Array(Int64)`
- [x] `Array(UInt8)`
- [x] `Array(UInt16)`
- [x] `Array(UInt32)`
- [x] `Array(UInt64)`
- [x] `Array(Float32)`
- [x] `Array(Float64)`
- [x] `Array(String)`
- [x] Argument types
- [x] `Int8`
- [x] `Int16`
- [x] `Int32`
- [x] `Int64`
- [x] `UInt8`
- [x] `UInt16`
- [x] `UInt32`
- [x] `UInt64`
- [x] `Float32`
- [x] `Float64`
- [x] `String`
- [x] `Bool`
- [x] Default values for option & argument
- [x] Required flag for option & argument
- [x] Nested sub commands
- [x] `--help` option
- [x] Customizable help message
- [x] `version` macro
- [x] Command name alias
- [x] Bash completion
## Installation
Add this to your application's `shard.yml`:
```yaml
dependencies:
clim:
github: at-grandpa/clim
version: 0.17.1
```
## Samples
### Minimum sample
*src/minimum.cr*
```crystal
require "clim"
class MyCli < Clim
main do
run do |opts, args|
puts "#{args.all_args.join(", ")}!"
end
end
end
MyCli.start(ARGV)
```
```console
$ crystal build -o ./minimum src/minimum.cr
$ ./minimum foo bar baz
foo, bar, baz!
```
### Command information sample
*src/hello.cr*
```crystal
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"
argument "first_member", type: String, desc: "first member name.", default: "member1"
argument "second_member", type: String, desc: "second member name.", default: "member2"
run do |opts, args|
print "#{opts.greeting}, "
print "#{args.first_member} & #{args.second_member} !\n"
print "And #{args.unknown_args.join(", ")} !"
print "\n"
end
end
end
end
Hello::Cli.start(ARGV)
```
```console
$ 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"]
--help Show this help.
--version Show version.
Arguments:
01. first_member first member name. [type:String] [default:"member1"]
02. second_member second member name. [type:String] [default:"member2"]
$ ./hello -g 'Good night' Ichiro Miko Takashi Taro
Good night, Ichiro & Miko !
And Takashi, Taro !
```
### Sub commands sample
*src/fake-crystal-command.cr*
```crystal
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.
```console
$ 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.
```console
$ ./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.
```console
$ ./fcrystal tool format
Fake Crystal tool format!!
```
## How to use
### require & inherit
```crystal
require "clim"
class MyCli < Clim
# ...
end
```
### Command Informations
#### desc
Description of the command. It is displayed in Help.
```crystal
class MyCli < Clim
main do
desc "My Command Line Interface."
run do |opts, args|
# ...
end
end
end
```
#### usage
Usage of the command. It is displayed in Help.
```crystal
class MyCli < Clim
main do
usage "mycli [sub-command] [options] ..."
run do |opts, args|
# ...
end
end
end
```
#### alias_name
An alias for the command. It can be specified only for subcommand.
```crystal
require "clim"
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.start(ARGV)
```
```console
$ ./mycli sub
sub_command run!!
$ ./mycli alias1
sub_command run!!
$ ./mycli alias2
sub_command run!!
```
#### version
You can specify the string to be displayed with `--version`.
```crystal
require "clim"
class MyCli < Clim
main do
version "mycli version: 1.0.1"
run do |opts, args|
# ...
end
end
end
MyCli.start(ARGV)
```
```console
$ ./mycli --version
mycli version: 1.0.1
```
If you want to display it even with `-v`, add ` short: "-v" `.
```crystal
require "clim"
class MyCli < Clim
main do
version "mycli version: 1.0.1", short: "-v"
run do |opts, args|
# ...
end
end
end
MyCli.start(ARGV)
```
```console
$ ./mycli --version
mycli version: 1.0.1
$ ./mycli -v
mycli version: 1.0.1
```
#### Short option for help
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.)
```crystal
require "clim"
class MyCli < Clim
main do
desc "help directive test."
usage "mycli [options] [arguments]"
help short: "-h"
run do |opts, args|
# ...
end
end
end
MyCli.start(ARGV)
```
```console
$ ./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"` .
#### option
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` |
```crystal
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.
```crystal
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.
```crystal
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
```
#### argument
You can specify multiple arguments for the command.
| Argument | Description | Example | Required | Default |
| -------------- | -------------------- | ------------------------------- | -------- | ------------------------- |
| First argument | name | `my_argument` | true | - |
| `type` | argument type | `type: String` | false | `String` |
| `desc` | argument description | `desc: "argument description."` | false | `"Argument description."` |
| `default` | default value | `default: "default value"` | false | `nil` |
| `required` | required flag | `required: true` | false | `false` |
The order of the arguments is related to the order in which they are defined. Also, when calling a method, hyphens in the method name of the argument are converted to underscores. There are also `all_args`, `unknown_args` and `argv` methods.
```crystal
require "clim"
class MyCli < Clim
main do
desc "argument sample"
usage "command [options] [arguments]"
option "--dummy=WORDS",
desc: "dummy option"
argument "first-arg",
desc: "first argument!",
type: String,
default: "default value"
argument "second-arg",
desc: "second argument!",
type: Int32,
default: 999
run do |opts, args|
puts "typeof(args.first_arg) => #{typeof(args.first_arg)}"
puts " args.first_arg => #{args.first_arg}"
puts "typeof(args.second_arg) => #{typeof(args.second_arg)}"
puts " args.second_arg => #{args.second_arg}"
puts "typeof(args.all_args) => #{typeof(args.all_args)}"
puts " args.all_args => #{args.all_args}"
puts "typeof(args.unknown_args) => #{typeof(args.unknown_args)}"
puts " args.unknown_args => #{args.unknown_args}"
puts "typeof(args.argv) => #{typeof(args.argv)}"
puts " args.argv => #{args.argv}"
end
end
end
```
```console
$ crystal run src/argument.cr -- --help
argument sample
Usage:
command [options] [arguments]
Options:
--dummy=WORDS dummy option [type:String]
--help Show this help.
Arguments:
01. first-arg first argument! [type:String] [default:"default value"]
02. second-arg second argument! [type:Int32] [default:999]
$ crystal run src/argument.cr -- 000 111 --dummy dummy_words 222 333
typeof(args.first_arg) => String
args.first_arg => 000
typeof(args.second_arg) => Int32
args.second_arg => 111
typeof(args.all_args) => Array(String)
args.all_args => ["000", "111", "222", "333"]
typeof(args.unknown_args) => Array(String)
args.unknown_args => ["222", "333"]
typeof(args.argv) => Array(String)
args.argv => ["000", "111", "--dummy", "dummy_words", "222", "333"]
```
The type of the arguments 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 \| Nil` |
### help_template
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`, `argments : HelpArgumentsType` and `sub_commands : HelpSubCommandsType`.
*help_template_test.cr*
```crystal
require "clim"
class MyCli < Clim
main do
help_template do |desc, usage, options, arguments, sub_commands|
options_help_lines = options.map do |option|
option[:names].join(", ") + "\n" + " #{option[:desc]}"
end
arguments_help_lines = arguments.map do |argument|
("%02d: " % [argument[:sequence_number]]) +
argument[:display_name] +
"\n" +
" #{argument[:desc]}"
end
base = <<-BASE_HELP
#{usage}
#{desc}
options:
#{options_help_lines.join("\n")}
arguments:
#{arguments_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] [arguments]
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."
argument "image_name", type: String, desc: "The name of your favorite docker image."
argument "container_id", type: String, desc: "The ID of the running container."
run do |opts, args|
end
sub "sub_command" do
desc "my_cli's sub_comand."
run do |opts, args|
end
end
end
end
MyCli.start(ARGV)
```
```console
$ 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] [arguments]
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.
arguments:
01: image_name
The name of your favorite docker image.
02: container_id
The ID of the running container.
sub commands:
sub_command my_cli's sub_comand.
```
options:
```crystal
# `options` type
alias HelpOptionsType = Array(NamedTuple(
names: Array(String),
type: Int8.class | Int32.class | ... | String.class | Bool.class, # => 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.",
},
]
```
arguments:
```crystal
# `arguments` type
alias HelpArgumentsType = Array(NamedTuple(
method_name: String,
display_name: String,
type: Int8.class | Int32.class | ... | String.class | Bool.class, # => Support Types
desc: String,
default: Int8 | Int32 | ... | String | Bool, # => Support Types,
required: Bool,
sequence_number: Int32,
help_line: String
))
# `arguments` example
[
{
method_name: "argument1",
display_name: "argument1",
type: String,
desc: "first argument.",
default: "default value",
required: true,
sequence_number: 1,
help_line: " 01. argument1 first argument. [type:String] [default:\"default value\"] [required]",
},
{
method_name: "argument2foo",
display_name: "argument2foo",
type: Int32,
desc: "second argument.",
default: 1,
required: false,
sequence_number: 2,
help_line: " 02. argument2foo second argument. [type:Int32] [default:1]",
},
]
```
sub_commands:
```crystal
# `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.",
},
]
```
### help string
```crystal
class MyCli < Clim
main do
run do |opts, args|
opts.help_string # => help string
end
end
end
```
### `io` in run block
You can receive `io` in a run block by passing it as the second argument to the start method.
```crystal
require "clim"
class IoCommand < Clim
main do
run do |opts, args, io|
io.puts "in main"
end
end
end
io = IO::Memory.new
IoCommand.start([] of String, io: io)
puts io.to_s # => "in main\n"
```
### Bash completion
You can use bash completion.
*src/sample.cr*
```crystal
require "clim"
class Cli < Clim
main do
version "Version 1.0"
option "-p PORT", "--port=PORT", type: Int32, desc: "Port number."
option "-h HOST", "--host=HOST", type: String, desc: "Host name."
run do |opts, args|
# ...
end
sub "tool" do
option "-v", "--verbose", type: Bool
run do |opts, args|
# ...
end
end
sub "run" do
help short: "-h"
run do |opts, args|
# ...
end
end
end
end
Cli.start(ARGV)
```
- Step1: Build your program.
- Step2: Add ```eval "`{your_program} --bash-completion`"``` to `~/.bashrc`.
- Step3: Reload `~/.bashrc`.
- Step4: You can use bash completion for options and subcommands.
```console
$ crystal build src/sample.cr -o /usr/local/bin/sample
$ echo 'eval "`sample --bash-completion`"' >> ~/.bashrc
$ . ~/.bashrc
$ sample [TAB][TAB]
--help --host --port --version -h -p run tool
$ sample tool -[TAB][TAB]
--help --verbose -v
$ sample tool --[TAB][TAB]
--help --verbose
$ sample tool --help
Command Line Interface Tool.
Usage:
tool [options] [arguments]
Options:
-v, --verbose Option description. [type:Bool]
--help Show this help.
$
```
## Development
```
$ make spec
```
## Contributing
1. Fork it ( https://github.com/at-grandpa/clim/fork )
2. Create your feature branch (git checkout -b my-new-feature)
3. Commit your changes (git commit -am 'Add some feature')
4. Push to the branch (git push origin my-new-feature)
5. Create a new Pull Request
## Contributors
- [at-grandpa](https://github.com/at-grandpa) - creator, maintainer
Documentation
Built from the current release. The first visit to a release nobody has asked for starts its build.
Links
This release
- Version
0.1.4- Tagged
- Apr 11, 2021
- Commit
5290a53074c6- Indexed
- not yet
Dependents
Repository
github.com/at-grandpa/clim
Metadata
- Created
- Aug 12, 2026
- Updated
- Aug 12, 2026
- Synced
- Aug 12, 2026
- Versions
- 31