Current section
Files
Jump to
Current section
Files
lib/arguments.ex
defmodule Arguments do
@moduledoc """
Arguments provides a module with argument parsing through `YourArguments.parse(incoming)`
`use Arguments`
There are two styles of arguments allowed
- `command` - `$ cmd new project`
- `flag` - `$ cmd --dir /etc`
These two styles can be mixed, but the flags will always take priority
## Full Example:
```elixir
module MyArguments do
use Arguments
command "new", do: [
arguments: [:name, :dir]
]
flag "name", do: [
type: :string,
alias: :n,
defaults: fn (n) -> [
dir: "./#\{n\}"
] end
]
flag "more", do: %{
type: :boolean,
alias: :m
}
flag "dir", do: [
type: :string
]
end
```
```elixir
iex> MyArguments.parse(["--name", "myname"])
%{name: "myname", dir: "./myname"}
iex> MyArguments.parse(["new", "myname", "dirhere"])
%{new: true, name: "myname", dir: "dirhere"}
iex> MyArguments.parse(["--more"])
%{more: true}
iex> MyArguments.parse(["-m"])
%{more: true}
```
"""
alias Arguments.{Builder, Parser}
defmacro __using__(_opts) do
quote do
import Arguments
@arguments []
@before_compile Arguments
end
end
@doc """
Defines a flag style argument
## Required Options:
- `type:` (atom) Argument type from `OptionParser.parse/1`
- `:string` parses the value as a string
- `:boolean` sets the value to true when given
- `:count` counts the number of times the switch is given
- `:integer` parses the value as an integer
- `:float` parses the value as a float
## Optional Common Options:
- `alias:` (atom) Single dash name, e.g. `:d` -> `-d`
- `defaults:` (fn(value) | list) If the flag is set, the defaults will be applied
- The end result must be a keyword list. The function form may NOT use anything
from outside, but will be passed in the value of the flag.
- Example:
- `defaults: fn(name) -> [dir: "./#\{name\}"] end`
- `$ cmd --name myname`
- `%{name: "myname", dir: "./myname"}`
## Optional Uncommon Options:
- `name:` (atom) Double dash name, e.g. `:dir` -> `--dir` (defaults to flag [name])
"""
defmacro flag(name, do: block) do
default_fn = case Builder.get_default_fn(block) do
nil -> nil
f -> Macro.escape(f)
end
quote bind_quoted: [name: name, block: block, default_fn: default_fn] do
# flags need to be after command for defaults to apply
@arguments @arguments
++ [Builder.create_arg_map(name, block, :flag, default_fn)]
end
end
@doc """
Defines a command style argument
A command is an ordered set of flags with a boolean flag for itself
## Required Options:
- `arguments:` (list of atoms) [:arg0, arg1] e.g. [:name, :dir]
- Example
- `command "new", do [arguments: [:name, :dir]]`
- `$ cmd new MyName YourDir`
- `%{new: true, name: "MyName", dir: "YourDir"}`
## Optional Uncommon Options:
- `name:` (atom) Double dash name, e.g. `:dir` -> `--dir` (defaults to command [name])
"""
defmacro command(name, do: block) do
quote bind_quoted: [name: name, block: block] do
# commands need to be first for defaults to apply
@arguments [Builder.create_arg_map(name, block, :command) | @arguments]
end
end
@doc false
defmacro __before_compile__(_env) do
quote do
def arguments, do: @arguments
def parse(incoming), do: Parser.parse(incoming, @arguments)
end
end
end