cli~amberframework
Crystal CLI
Yet another Crystal library for building command-line interface applications.
Installation
Add this to your application's shard.yml
:
dependencies:
cli:
github: mosop/cli
Features
Option Parser (Integrated with optarg)
class Command < Cli::Command
class Options
string "--hello"
end
def run
puts "Hello, #{options.hello}!"
end
end
Command.run %w(--hello world) # prints "Hello, world!"
Access to Options
class Command < Cli::Command
class Options
string "--option"
end
def run
puts "#{options.option} #{args[0]} #{unparsed_args[0]}"
end
end
Command.run %w(--option foo bar -- baz) # prints "foo bar baz"
Access from Options
class Command < Cli::Command
class Options
on("--go") { command.go(with: "the Wind") }
end
def go(with some)
puts "Gone with #{some}"
exit
end
end
Command.run %w(--go) # prints "Gone with the Wind"
Exit
class Command < Cli::Command
class Options
on("--exit") { command.exit! }
on("--abort") { command.error! }
end
end
Command.run %w(--exit) # => 0
Command.run %w(--abort) # => 1
For more detail, see Handling Exit.
Subcommand
class Polygon < Cli::Supercommand
command "triangle", default: true
command "square"
command "hexagon"
module Commands
class Triangle < Cli::Command
def run
puts 3
end
end
class Square < Cli::Command
def run
puts 4
end
end
class Hexagon < Cli::Command
def run
puts 6
end
end
end
end
Polygon.run %w(triangle) # prints "3"
Polygon.run %w(square) # prints "4"
Polygon.run %w(hexagon) # prints "6"
Polygon.run %w() # prints "3"
Aliasing
class Command < Cli::Supercommand
command "loooooooooong"
command "l", aliased: "loooooooooong"
module Commands
class Loooooooooong < Cli::Command
def run
sleep 1000
end
end
end
end
Command.run %w(l) # sleeps
Inheritance
class Role < Cli::Command
class Options
string "--name"
end
end
class Chase < Cli::Supercommand
command "mouse"
command "cat"
module Commands
class Mouse < Role
def run
puts "#{options.name} runs away."
end
end
class Cat < Role
def run
puts "#{options.name} runs into a wall."
end
end
end
end
Chase.run %w(mouse --name Jerry) # prints "Jerry runs away."
Chase.run %w(cat --name Tom) # prints "Tom runs into a wall."
Help
class Lang < Cli::Command
class Help
header "Converts a language to other languages."
footer "(C) 20XX mosop"
end
class Options
arg "from", desc: "source language", required: true
array "--to", var: "LANG", desc: "target language", default: %w(crystal)
string "--indent", var: "NUM", desc: "set number of tab size", default: "2"
bool "--std", not: "--Std", desc: "use standard library", default: true
help
end
end
Lang.run %w(--help)
# lang [OPTIONS] FROM
#
# Converts a language to other languages.
#
# Arguments:
# FROM (required) source language
#
# Options:
# --indent NUM set number of tab size
# (default: 2)
# --std use standard library
# (enabled as default)
# --Std disable --std
# --to LANG (multiple) target language
# (default: crystal)
# -h, --help show this help
#
# (C) 20XX mosop
Help for Subcommands
class Package < Cli::Supercommand
command "install", default: true
command "update"
command "remove"
command "uninstall", aliased: "remove"
class Help
title "#{global_name} [SUBCOMMAND] | [OPTIONS]"
end
class Options
help
end
class Base < Cli::Command
class Options
arg "package_name", desc: "specify package's name", required: true
help
end
end
module Commands
class Install < Base
class Help
caption "install package"
end
class Options
string "-v", var: "VERSION", desc: "specify package's version"
end
end
class Update < Base
class Help
caption "update package"
end
class Options
bool "--break", desc: "update major version if any"
end
end
class Remove < Base
class Help
caption "remove package"
end
class Options
bool "-f", desc: "force to remove"
end
end
end
end
Package.run %w(--help)
# package [SUBCOMMAND] | [OPTIONS]
#
# Subcommands:
# install (default) install package
# remove remove package
# uninstall alias for remove
# update update package
#
# Options:
# -h, --help show this help
Package.run %w(install --help)
# package install [OPTIONS] PACKAGE_NAME
#
# Arguments:
# PACKAGE_NAME specify package's name
#
# Options:
# -v VERSION specify package's version
# -h, --help show this help
end
Package.run %w(update --help)
# package update [OPTIONS] PACKAGE_NAME
#
# Arguments:
# PACKAGE_NAME specify package's name
#
# Options:
# --major update major version if any
# -h, --help show this help
end
Package.run %w(remove --help)
# package remove [OPTIONS] PACKAGE_NAME
#
# Arguments:
# PACKAGE_NAME specify package's name
#
# Options:
# -f force to remove
# -h, --help show this help
Package.run %w(uninstall --help)
# package remove [OPTIONS] PACKAGE_NAME
#
# Arguments:
# PACKAGE_NAME specify package's name
#
# Options:
# -f force to remove
# -h, --help show this help
Usage
require "cli"
and see Features.
Fundamentals
Crystal CLI provides 4 fundamental classes, Command
, Supercommand
, Options
and Help
.
Both Command
and Supercommand
inherit the CommandBase
class that has several features commonly used.
Once you make a class inherit Command
or Supercommand
, then Options
and Help
is automatically defined into the class.
class AncientCommand < Cli::Command
end
This code seems that it simply defines the AncientCommand
class. But, actually, it also makes AncientCommand::Options
and AncientCommand::Help
defined internally.
Parsing Options
The Options
class is used for parsing command-line options. Options
inherits the Optarg::Model
class provided from the optarg library. So you can define options in it.
class AncientCommand < Cli::Command
class Options
string "--message"
end
end
Running a Command
The virtual CommandBase#run
method is the entry point for running your command.
Your command's class will be instantiated and its #run
method will be invoked after calling the static .run
method.
class AncientCommand < Cli::Command
def run
puts "We the Earth"
end
end
AncientCommand.run
This prints as:
We the Earth
A command's instance is also accessible with the command
method in an option parser's scope.
class AncientCommand < Cli::Command
class Options
on("--understand") { command.understand }
end
def understand
puts "We know"
end
def run
puts "We the Earth"
end
end
AncientCommand.run %w(--understand)
This prints as:
We know
We the Earth
Handling Exit
When a command normally ends, it returns 0.
class Command < Cli::Command
def run
end
end
Command.run # => 0
When you want to abort your command, you may raise an exception:
class Command < Cli::Command
def run
raise "ERROR!"
end
end
Command.run # => raises error
Or, instead, you can have more control of exit with one of the 3 methods: help!
, exit!
and error!
.
help!
class Command < Cli::Command
def run
help!
end
end
Command.run # => 0
This command just ends after printing its help message. Command.run
returns 0 as exit code.
To print message to STDERR and exit with an error code, use error
option.
help! error: true
If the :error
option is true, run
method returns 1 as exit code. To specify a number, use the :code
option.
help! code: 22
You can also let it exit with an additional message:
help! message: "You passed an illegal option! See help!"
Or simply:
help! "You passed an illegal option! See help!"
Calling help!
with the :message
argument implies that the :error
option is true. To exit normally, set false to :error
.
exit! and error!
exit!
is more general than help!
.
class Command < Cli::Command
def run
exit!
end
end
Command.run # => 0
It just ends and returns 0 as exit code without printing.
To print a message:
exit! "bye."
Or more variations:
exit! help: true # same as help!
exit! error: true # returns 1 as exit code
exit! "message", error: true, help: true # same as help!("message")
error!
is similar to exit!
, but the :error
option is true as default.
error! # ends with 1 as exit code
error! "message" # same as exit!("message", error: true)
error! code: 22 # specifies exit code
error! help: true # same as help!(error: true)
error! "message", help: true # same as help!("message")
Formatting Help [WIP]
To format help texts, use the Help
class.
class Ancient < Cli::Command
class Help
title global_name
footer "(C) 1977 mosop"
end
def run
help!
end
end
Wish List
- Application-Level Logger
- Documentation for Formatting Help
- Auto-Title
Releases
- v0.1.9
- CommandBase.run returns 0 when #run normally returns.
- v0.1.4
- help!, exit! and error!
- v0.1.2
- Array
- v0.1.1
- Aliasing
Development
[WIP]
Contributing
- Fork it ( https://github.com/mosop/cli/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
Contributors
- mosop - creator, maintainer