Skip to content

Commit dd1a634

Browse files
authored
Merge pull request #32 from TTRPG-Dev/qmalcolm--better-cli-commands
Grab Bag of CLI refactorings
2 parents 267b236 + 9cb6c4b commit dd1a634

File tree

7 files changed

+139
-135
lines changed

7 files changed

+139
-135
lines changed

lib/cli.ex

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# credo:disable-for-this-file Credo.Check.Warning.IoInspect
22
defmodule ExTTRPGDev.CLI do
3+
alias ExTTRPGDev.CLI.Characters
34
alias ExTTRPGDev.CLI.Generate
45
alias ExTTRPGDev.CLI.Roll
56
alias ExTTRPGDev.CLI.RuleSystems
@@ -21,7 +22,8 @@ defmodule ExTTRPGDev.CLI do
2122
subcommands:
2223
Roll.commands() ++
2324
RuleSystems.commands() ++
24-
Generate.commands()
25+
Generate.commands() ++
26+
Characters.commands()
2527
)
2628

2729
case Optimus.parse!(optimus, argv) do
@@ -31,14 +33,14 @@ defmodule ExTTRPGDev.CLI do
3133
{[:roll], parse_result} ->
3234
Roll.handle(parse_result)
3335

34-
{[:list_systems], _} ->
35-
RuleSystems.handle_list_systems()
36+
{[:systems | sub_commands], parse_result} ->
37+
RuleSystems.handle_systems_subcommands(sub_commands, parse_result)
3638

37-
{[:system | sub_commands], parse_result} ->
38-
RuleSystems.handle_system_subcommands(sub_commands, parse_result)
39+
{[:characters | sub_commands], parse_result} ->
40+
Characters.handle_characters_subcommands(sub_commands, parse_result)
3941

40-
{[:gen | sub_commands], _} ->
41-
Generate.handle_generate_subcommands(sub_commands)
42+
{[:gen | sub_commands], parse_result} ->
43+
Generate.handle_generate_subcommands(sub_commands, parse_result)
4244

4345
{unhandled, _parse_result} ->
4446
str_command =

lib/cli/args.ex

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
defmodule ExTTRPGDev.CLI.Args do
2+
@moduledoc """
3+
Defines common CLI args
4+
"""
5+
alias ExTTRPGDev.CLI.CustomParsers
6+
7+
@doc """
8+
Argument spec for any command needing to take in the name of a rule system
9+
"""
10+
def system do
11+
[
12+
system: [
13+
value_name: "SYSTEM",
14+
help: "A supported system, e.g. basic_fantasy_4e",
15+
required: true,
16+
parser: &CustomParsers.system_parser(&1)
17+
]
18+
]
19+
end
20+
end

lib/cli/characters.ex

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# credo:disable-for-this-file Credo.Check.Warning.IoInspect
2+
defmodule ExTTRPGDev.CLI.Characters do
3+
@moduledoc """
4+
Defintions for dealing with character CLI commands
5+
"""
6+
alias ExTTRPGDev.Characters.Character
7+
alias ExTTRPGDev.CLI.Args
8+
9+
@doc """
10+
Command specifications for character CLI commands
11+
"""
12+
def commands do
13+
[
14+
characters: [
15+
name: "characters",
16+
about: "Top level command for characters",
17+
subcommands: [
18+
gen: [
19+
name: "gen",
20+
about: "Generate a character for a system",
21+
args: Args.system()
22+
]
23+
]
24+
]
25+
]
26+
end
27+
28+
@doc """
29+
Handle `characters` CLI command and sub commands
30+
"""
31+
def handle_characters_subcommands([:gen | _subcommands], %Optimus.ParseResult{
32+
args: %{system: system}
33+
}) do
34+
character = system |> Character.gen_character!()
35+
36+
IO.puts("-- Name: #{character.name}")
37+
38+
Enum.each(character.ability_scores, fn {ability, scores} ->
39+
IO.puts("#{ability}: #{Enum.sum(scores)}")
40+
end)
41+
end
42+
end

lib/cli/custom_parsers.ex

+20
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ defmodule ExTTRPGDev.CLI.CustomParsers do
22
@moduledoc """
33
Custom parsers to be used with Optimus args :parse
44
"""
5+
alias ExTTRPGDev.RuleSystems
56

67
@doc """
78
Parses a string of dice specifications seperated by commas
@@ -17,4 +18,23 @@ defmodule ExTTRPGDev.CLI.CustomParsers do
1718
|> Enum.map(&String.trim(&1))
1819
|> Kernel.then(fn result -> {:ok, result} end)
1920
end
21+
22+
@doc """
23+
Loads the rule system for the given system name
24+
25+
## Examples
26+
27+
iex> ExTTRPGDev.CLI.CustomParsers.system_parser("dnd_5e_srd")
28+
{:ok, %ExTTRPGDev.RuleSystems.RuleSystem{}}
29+
"""
30+
def system_parser(system) when is_bitstring(system) do
31+
if RuleSystems.is_configured?(system) do
32+
system
33+
|> RuleSystems.load_system!()
34+
|> Kernel.then(fn result -> {:ok, result} end)
35+
else
36+
{:error,
37+
"\"#{system}\" is not configured, run `ex_ttrpg_dev systems list` to list configured systems"}
38+
end
39+
end
2040
end

lib/cli/generate.ex

+15-5
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ defmodule ExTTRPGDev.CLI.Generate do
33
@moduledoc """
44
Definitions for dealing with genenerate CLI commands
55
"""
6+
alias ExTTRPGDev.CLI.Args
7+
alias ExTTRPGDev.RuleSystems.RuleSystem
68

79
@doc """
810
Command specifications for generate commands
@@ -16,6 +18,11 @@ defmodule ExTTRPGDev.CLI.Generate do
1618
name: [
1719
name: "name",
1820
about: "Generate a random name"
21+
],
22+
stat_block: [
23+
name: "stat-block",
24+
about: "Generate stat blocks for characters of the system",
25+
args: Args.system()
1926
]
2027
]
2128
]
@@ -25,10 +32,13 @@ defmodule ExTTRPGDev.CLI.Generate do
2532
@doc """
2633
Handles generate sub commands
2734
"""
28-
def handle_generate_subcommands([command | _subcommands]) do
29-
case command do
30-
:name ->
31-
IO.inspect(Faker.Person.name())
32-
end
35+
def handle_generate_subcommands([:name | _subcommands], _parse_result),
36+
do: IO.inspect(Faker.Person.name())
37+
38+
def handle_generate_subcommands([:stat_block | _subcommands], %Optimus.ParseResult{
39+
args: %{system: system}
40+
}) do
41+
RuleSystem.gen_ability_scores_assigned(system)
42+
|> IO.inspect()
3343
end
3444
end

lib/cli/system.ex

+18-122
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ defmodule ExTTRPGDev.CLI.RuleSystems do
33
@moduledoc """
44
Defintions for dealing with rule system CLI commands
55
"""
6-
alias ExTTRPGDev.Characters.Character
6+
alias ExTTRPGDev.CLI.Args
77
alias ExTTRPGDev.RuleSystems.Abilities
88
alias ExTTRPGDev.RuleSystems.Languages
99
alias ExTTRPGDev.RuleSystems.RuleSystem
@@ -14,43 +14,13 @@ defmodule ExTTRPGDev.CLI.RuleSystems do
1414
"""
1515
def commands do
1616
[
17-
list_systems: [
18-
name: "list-systems",
19-
about: "List systems that are setup to be used with ExTTRPGDev"
20-
],
21-
system: [
22-
name: "system",
17+
systems: [
18+
name: "systems",
2319
about: "Top level command fo systems",
2420
subcommands: [
25-
gen: [
26-
name: "gen",
27-
about: "Used for generating things for the system",
28-
subcommands: [
29-
stat_block: [
30-
name: "stat-block",
31-
about: "Generate stat blocks for characters of the system",
32-
args: [
33-
system: [
34-
value_name: "SYSTEM",
35-
help: "A supported system, e.g. dnd5e",
36-
required: true,
37-
parser: :string
38-
]
39-
]
40-
],
41-
character: [
42-
name: "character",
43-
about: "Generate characters for system",
44-
args: [
45-
system: [
46-
value_name: "SYSTEM",
47-
help: "A supported system, e.g. dnd5e",
48-
required: true,
49-
parser: :string
50-
]
51-
]
52-
]
53-
]
21+
list: [
22+
name: "list",
23+
about: "List systems that ex_ttrpg_dev knows about"
5424
],
5525
show: [
5626
name: "show",
@@ -59,50 +29,22 @@ defmodule ExTTRPGDev.CLI.RuleSystems do
5929
abilities: [
6030
name: "abilities",
6131
about: "Show the rule systems character abilities",
62-
args: [
63-
system: [
64-
value_name: "SYSTEM",
65-
help: "A supported system, e.g. dnd5e",
66-
required: true,
67-
parser: :string
68-
]
69-
]
32+
args: Args.system()
7033
],
7134
languages: [
7235
name: "languages",
7336
about: "Show the rule systems languages",
74-
args: [
75-
system: [
76-
value_name: "SYSTEM",
77-
help: "A supported system, e.g. dnd5e",
78-
required: true,
79-
parser: :string
80-
]
81-
]
37+
args: Args.system()
8238
],
8339
metadata: [
8440
name: "metadata",
8541
about: "Show system metadata",
86-
args: [
87-
system: [
88-
value_name: "SYSTEM",
89-
help: "A supported system, e.g. dnd5e",
90-
required: true,
91-
parser: :string
92-
]
93-
]
42+
args: Args.system()
9443
],
9544
skills: [
9645
name: "skills",
9746
about: "Show rule system skills",
98-
args: [
99-
system: [
100-
value_name: "SYSTEM",
101-
help: "A supported system, e.g. dnd5e",
102-
required: true,
103-
parser: :string
104-
]
105-
]
47+
args: Args.system()
10648
]
10749
]
10850
]
@@ -112,74 +54,28 @@ defmodule ExTTRPGDev.CLI.RuleSystems do
11254
end
11355

11456
@doc """
115-
Handle list-systems CLI command
57+
Handle `systems` CLI command and sub commands
11658
"""
117-
def handle_list_systems() do
59+
def handle_systems_subcommands([:list], _) do
11860
ExTTRPGDev.RuleSystems.list_systems()
11961
|> IO.inspect(label: "Configured Systems")
12062
end
12163

122-
@doc """
123-
Handle `system` CLI command and sub commands
124-
"""
125-
def handle_system_subcommands([command | subcommands], %Optimus.ParseResult{
64+
def handle_systems_subcommands([:show | subcommands], %Optimus.ParseResult{
12665
args: %{system: system}
12766
}) do
128-
loaded_system =
129-
system
130-
|> ExTTRPGDev.RuleSystems.assert_configured!()
131-
|> ExTTRPGDev.RuleSystems.load_system!()
132-
133-
case command do
134-
:gen ->
135-
handle_system_generation_subcommands(subcommands, loaded_system)
136-
137-
:show ->
138-
handle_system_show_subcommands(subcommands, loaded_system)
139-
end
140-
end
141-
142-
@doc """
143-
Handle generation commands for a rule system
144-
"""
145-
def handle_system_generation_subcommands(
146-
[command | _subcommands],
147-
%RuleSystem{} = system
148-
) do
149-
case command do
150-
:stat_block ->
151-
RuleSystem.gen_ability_scores_assigned(system)
152-
|> IO.inspect()
153-
154-
:character ->
155-
character = Character.gen_character!(system)
156-
IO.puts("-- Name: #{character.name}")
157-
158-
Enum.each(character.ability_scores, fn {ability, scores} ->
159-
IO.puts("#{ability}: #{Enum.sum(scores)}")
160-
end)
161-
end
162-
end
163-
164-
@doc """
165-
Hand showing a rule system's components
166-
"""
167-
def handle_system_show_subcommands(
168-
[command | _subcommands],
169-
%RuleSystem{} = system
170-
) do
171-
case command do
172-
:abilities ->
67+
case subcommands do
68+
[:abilities] ->
17369
show_abilities(system)
17470

175-
:languages ->
71+
[:languages] ->
17672
show_languages(system)
17773

178-
:metadata ->
74+
[:metadata] ->
17975
Map.get(system, :metadata)
18076
|> IO.inspect()
18177

182-
:skills ->
78+
[:skills] ->
18379
show_skills(system)
18480
end
18581
end

test/custom_parsers_test.exs

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,19 @@
11
defmodule ExTTRPGDevTest.CLI.CustomParsers do
22
use ExUnit.Case
33

4-
doctest ExTTRPGDev.CLI.CustomParsers
4+
alias ExTTRPGDev.CLI.CustomParsers
5+
alias ExTTRPGDev.RuleSystems.RuleSystem
6+
7+
doctest ExTTRPGDev.CLI.CustomParsers,
8+
except: [
9+
system_parser: 1
10+
]
11+
12+
def system_parser_test do
13+
# If no error was raised, then all is good
14+
{:ok, %RuleSystem{}} = CustomParsers.system_parser("dnd_5e_srd")
15+
16+
# Should raise an error
17+
assert_raise RuntimeError, CustomParsers.system_parser("unknown_system")
18+
end
519
end

0 commit comments

Comments
 (0)