Skip to content

Commit

Permalink
feat: add support to enum values as strings
Browse files Browse the repository at this point in the history
  • Loading branch information
zoedsoupe committed Sep 11, 2023
1 parent edbcbb2 commit 86d88f5
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 9 deletions.
2 changes: 1 addition & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
import Config

config :nexus, supported_types: ~w(string atom integer float null)a
config :nexus, supported_types: ~w(string atom integer float null enum)a
23 changes: 16 additions & 7 deletions lib/nexus.ex
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ defmodule Nexus do
To define a command you need to name it and pass some options:
- `:type`: the argument type to be parsed to. It can be `:string` (default),
`:integer`, `:float` or `:atom`. The absense of this option
- `:type`: the argument type to be parsed to. The absense of this option
will define a command without arguments, which can be used to define a subcommand
group.
group. See more on the [Types](#types) section.
- `:required`: defines if the presence of the command is required or not. All commands are required by default. If you define a command as not required, you also need to define a default value.
- `:default`: defines a default value for the command. It can be any term, but it must be of the same type as the `:type` option.
Expand All @@ -31,6 +30,15 @@ defmodule Nexus do
__MODULE__.run(System.argv())
end
## Types
Nexus supports the following types:
- `:string`: parses the argument as a string. This is the default type.
- `:integer`: parses the argument as an integer.
- `:float`: parses the argument as a float.
- `:null`: parses the argument as a null value. This is useful to define subcommands.
- `{:enum, values_list}`: parses the argument as a literal, but only if it is included into the `values_list` list. Note that current it only support string values.
"""

@type command :: Nexus.Command.t()
Expand Down Expand Up @@ -72,7 +80,7 @@ defmodule Nexus do
"""
defmacro help do
quote do
Nexus.defcommand(:help, type: :string, required?: false)
Nexus.defcommand(:help, type: :null)

@impl Nexus.CLI
def handle_input(:help, _args) do
Expand Down Expand Up @@ -145,16 +153,17 @@ defmodule Nexus do

"""
#{banner}
COMMANDS:\n
#{Enum.map_join(cmds, "\n", &" #{elem(&1, 0)} - ")}
COMMANDS:
#{Enum.map_join(cmds, "\n", &" #{&1.name} - ")}
"""
end

def __make_command__!(module, cmd_name, opts) do
opts
|> Keyword.put(:name, cmd_name)
|> Keyword.put(:module, module)
|> Keyword.put_new(:required?, false)
|> Keyword.put_new(:required, false)
|> Keyword.put_new(:type, :string)
|> Nexus.Command.parse!()
end
end
4 changes: 3 additions & 1 deletion lib/nexus/command/validation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ defmodule Nexus.Command.Validation do
@supported_types Application.compile_env!(:nexus, :supported_types)

@spec validate_type(map) :: map
def validate_type(%{type: {:enum, _}} = attrs), do: attrs

def validate_type(%{type: type} = attrs) do
if type in @supported_types do
attrs
Expand All @@ -33,7 +35,7 @@ defmodule Nexus.Command.Validation do
default = Map.get(attrs, :default)

cond do
!default ->
!default and type != :null ->
raise ArgumentError, "Non required commands must have a default value"

!is_same_type(default, type) ->
Expand Down
7 changes: 7 additions & 0 deletions lib/nexus/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ defmodule Nexus.Parser do
end
end

defp parse_command(input, %Command{type: {:enum, values}} = cmd) do
with {:ok, {_, rest}} <- literal(input, cmd.name),
{:ok, value} <- maybe_parse_required(cmd, fn -> enum(rest, values) end) do
{:ok, Input.parse!(value, input)}
end
end

defp parse_command(input, %Command{type: :null} = cmd) do
with {:ok, {_, rest}} <- literal(input, cmd.name) do
{:ok, Input.parse!(nil, rest)}
Expand Down
4 changes: 4 additions & 0 deletions lib/nexus/parser/dsl.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ defmodule Nexus.Parser.DSL do
consume(input, ~r/\b#{lit}\b/)
end

def enum(input, values) do
consume(input, ~r/\b(#{Enum.join(values, "|")})\b/)
end

defp consume(input, regex) do
if Regex.match?(regex, input) do
cap = hd(Regex.run(regex, input, capture: :first))
Expand Down

0 comments on commit 86d88f5

Please sign in to comment.