Getting Started With CliMate
View SourceThis guide demonstrates how to use CliMate to create command-line applications in Elixir. We'll walk through defining a simple command that outputs an integer in base 2 or base 8.
Defining a Command
A command in CliMate consists of options, arguments, and metadata. First, declare your module as a Mix task and alias the CliMate.CLI module:
defmodule Mix.Tasks.Example do
alias CliMate.CLI
use Mix.Task
# ...
endThen define your command structure:
@command name: "mix example",
module: __MODULE__,
options: [
verbose: [
short: :v,
type: :boolean,
default: false,
doc: "Output debug info about the command."
]
],
arguments: [
n: [type: :integer, doc: "The value to convert."],
base: [
cast: &__MODULE__.cast_base/1,
doc: "A numeric base. Accepts 'two' or 'eight' only!"
]
]The name should reflect how the command is invoked. This will be displayed in the help text.
Parsing Command Arguments
Use the CliMate.CLI.parse_or_halt!/2 function to parse command arguments:
@impl true
def run(argv) do
%{options: opts, arguments: args} = CLI.parse_or_halt!(argv, @command)
formatted = Integer.to_string(args.n, args.base)
if opts.verbose do
IO.puts("#{args.n} in base #{args.base} is #{formatted}")
else
IO.puts(formatted)
end
end
def cast_base("two"), do: {:ok, 2}
def cast_base("eight"), do: {:ok, 8}
def cast_base(_), do: {:error, :invalid_base}The parse_or_halt!/2 function returns a map with :options and :arguments keys. Values are automatically cast according to the specified :type or :cast functions. If parsing fails, it will display the usage information and halt with an error message.
Argument Types and Options
Argument Types
CliMate supports the following argument types:
:string(default):integer:float
arguments: [
count: [type: :integer, doc: "A count parameter"],
rate: [type: :float, doc: "A floating point value"],
name: [type: :string, doc: "A name"]
]Arguments Configuration
Arguments support the following parameters:
:required- Default istrue. Set tofalsefor optional arguments.:cast- A function or MFA tuple that casts the value.:doc- Documentation string shown in help text.
arguments: [
required_arg: [],
custom_arg: [cast: &MyModule.custom_cast/1]
optional_arg: [required: false],
]Non-required arguments must be defined after required ones.
Option Types
Options support the following types:
:boolean- Flags that don't need values (--verbose):count- Counts the number of times an option appears:integer- Integer values:float- Floating point values:string- String values (default)
options: [
verbose: [type: :boolean],
count: [type: :count],
port: [type: :integer, default: 8080],
rate: [type: :float],
name: [] # :string is default
]Options Configuration
Options can be configured with:
:short- Single letter alias (:vfor-v):default- Default value or function:keep- Keep all values when an option is repeated:doc_arg- Custom display name for the argument:doc- Option description
options: [
names: [short: :n, keep: true, doc: "Collects names (can be repeated)"],
port: [short: :p, default: 4000, doc: "Port number"],
type: [doc_arg: "db-type", doc: "Database type to use"]
]Automatic Help Option
All commands automatically include a --help option. When used, it displays command usage and halts the program with a success code (0).
%> mix example --help
mix example version 0.7.1
Synopsis
mix example [options] <n> <base>
Arguments
n
The value to convert.
base
A numeric base. Accepts 'two' or 'eight' only!
Options
-v, --verbose
Output debug info about the command. Defaults to false.
--help
Displays this help.Providing Documentation for mix help
You can include command usage in your module documentation:
@shortdoc "Formats an integer in base two or eight"
@moduledoc """
#{@shortdoc}
#{CliMate.CLI.format_usage(@command, format: :moduledoc)}
"""Sub-commands
A command can declare :subcommands instead of :arguments to dispatch to nested commands (think git remote add). Each sub-command is a keyword list with the same shape as a top-level command, or a module implementing the CliMate.CLI.Command behaviour.
@command name: "mix myapp",
options: [verbose: [type: :boolean, default: false]],
subcommands: [
build: [
options: [target: [type: :string, default: "dev"]],
execute: &MyApp.Build.run/1
],
deploy: MyApp.Tasks.Deploy
]Options declared on the parent are inherited by sub-commands and can be passed at any level (mix myapp --verbose build or mix myapp build --verbose). A value explicitly passed on the command line always wins over defaults. See CliMate.CLI.Command for the full merging rules.
The parsed map exposes :path (the resolved sub-command keys) and :execute (a zero-arity closure when the selected command defines an :execute function, or nil otherwise):
def run(argv) do
parsed = CLI.parse_or_halt!(argv, @command)
case parsed.execute do
nil -> IO.puts("path: #{inspect(parsed.path)}")
run -> run.()
end
endWhen using a module-based sub-command, implement the execute/1 callback on the module and it will be wired automatically.
Advanced Usage
For more detailed information on configuring options and arguments, see:
CliMate.CLI.Argumentfor advanced argument configurationCliMate.CLI.Optionfor advanced option configuration