Packages

An `Elixir` library to write command line apps in a cleaner and elegant way!

Current section

9 Versions

Jump to

Compare versions

7 files changed
+65 additions
-13 deletions
  @@ -40,9 +40,9 @@ defmodule MyCLI do
40 40 when input: Nexus.Command.Input.t()
41 41 def handle_input(:fizzbuzz, %{value: value}) do
42 42 cond do
43 - rem(value, 3) -> IO.puts("fizz")
44 - rem(value, 5) -> IO.puts("buzz")
45 - rem(value, 3) and rem(value, 5) -> IO.puts("fizzbuzz")
43 + rem(value, 3) == 0 -> IO.puts("fizz")
44 + rem(value, 5) == 0 -> IO.puts("buzz")
45 + rem(value, 3) == 0 and rem(value, 5) == 0 -> IO.puts("fizzbuzz")
46 46 true -> IO.puts value
47 47 end
48 48 end
  @@ -52,6 +52,8 @@ defmodule MyCLI do
52 52 end
53 53 ```
54 54
55 + More different ways to use this library can be found on the [examples](./examples) folder
56 +
55 57 ## Why "Nexus"
56 58
57 59 Nexus is a connection from two different worlds! This library connects the world of CLIs with the magic world of `Elixir`!
  @@ -16,4 +16,4 @@
16 16 {<<"links">>,[{<<"GitHub">>,<<"https://github.com/zoedsoupe/nexus">>}]}.
17 17 {<<"name">>,<<"nexus_cli">>}.
18 18 {<<"requirements">>,[]}.
19 - {<<"version">>,<<"0.3.1">>}.
19 + {<<"version">>,<<"0.4.0">>}.
  @@ -46,8 +46,9 @@ defmodule Nexus do
46 46 defmacro __using__(_opts) do
47 47 quote do
48 48 Module.register_attribute(__MODULE__, :commands, accumulate: true)
49 + Module.register_attribute(__MODULE__, :subcommands, accumulate: true)
49 50
50 - import Nexus, only: [defcommand: 2]
51 + import Nexus, only: [defcommand: 2, defcommand: 3]
51 52 require Nexus
52 53
53 54 @behaviour Nexus.CLI
  @@ -65,11 +66,33 @@ defmodule Nexus do
65 66 """
66 67 @spec defcommand(atom, keyword) :: Macro.t()
67 68 defmacro defcommand(cmd, opts) do
68 - quote do
69 + quote location: :keep do
69 70 @commands Nexus.__make_command__!(__MODULE__, unquote(cmd), unquote(opts))
70 71 end
71 72 end
72 73
74 + defmacro defcommand(cmd, opts, do: ast) do
75 + subcommands = build_subcommands(ast)
76 +
77 + quote location: :keep do
78 + @commands Nexus.__make_command__!(
79 + __MODULE__,
80 + unquote(cmd),
81 + Keyword.put(unquote(opts), :subcommands, unquote(subcommands))
82 + )
83 + end
84 + end
85 +
86 + defp build_subcommands({:__block__, _, subs}) do
87 + Enum.map(subs, &build_subcommands/1)
88 + end
89 +
90 + defp build_subcommands({:defcommand, _, [cmd, opts]}) do
91 + quote do
92 + Nexus.__make_command__!(__MODULE__, unquote(cmd), unquote(opts))
93 + end
94 + end
95 +
73 96 @doc """
74 97 Generates a default `help` command for your CLI. It uses the
75 98 optional `banner/0` callback from `Nexus.CLI` to complement
  @@ -12,11 +12,18 @@ defmodule Nexus.Command do
12 12 required: boolean,
13 13 name: atom,
14 14 default: term,
15 - doc: String.t()
15 + doc: String.t(),
16 + subcommands: [Nexus.Command.t()]
16 17 }
17 18
18 19 @enforce_keys ~w(module type name)a
19 - defstruct module: nil, required: true, type: :string, name: nil, default: nil, doc: ""
20 + defstruct module: nil,
21 + required: true,
22 + type: :string,
23 + name: nil,
24 + default: nil,
25 + doc: "",
26 + subcommands: []
20 27
21 28 @spec parse!(keyword) :: Nexus.Command.t()
22 29 def parse!(attrs) do
  @@ -4,10 +4,10 @@ defmodule Nexus.Command.Input do
4 4 on commands dispatched
5 5 """
6 6
7 - @type t :: %__MODULE__{value: term, raw: binary}
7 + @type t :: %__MODULE__{value: term, raw: binary, subcommand: atom}
8 8
9 9 @enforce_keys ~w(value raw)a
10 - defstruct value: nil, raw: nil
10 + defstruct value: nil, raw: nil, subcommand: nil
11 11
12 12 @spec parse!(term, binary) :: Nexus.Command.Input.t()
13 13 def parse!(value, raw) do
Loading more files…