defmodule Mix.Tasks.Ecsx.Gen.System do
@shortdoc "Generates a new ECSx System"
@moduledoc """
Generates a new System for an ECSx application.
$ mix ecsx.gen.system Foo
The only argument accepted is a module name for the System.
"""
use Mix.Task
alias Mix.Tasks.ECSx.Helpers
@doc false
def run([]) do
Mix.raise("""
Missing argument.
mix ecsx.gen.system expects a system module name (in PascalCase).
For example:
mix ecsx.gen.system MySystem
""")
end
def run([system_name | _] = _args) do
inject_system_module_into_manager(system_name)
create_system_file(system_name)
end
defp create_system_file(system_name) do
filename = Macro.underscore(system_name)
target = "lib/#{Helpers.otp_app()}/systems/#{filename}.ex"
source = Application.app_dir(:ecsx, "/priv/templates/system.ex")
binding = [app_name: Helpers.root_module(), system_name: system_name]
Mix.Generator.create_file(target, EEx.eval_file(source, binding))
end
defp inject_system_module_into_manager(system_name) do
manager_path = ECSx.manager_path()
{before_systems, after_systems, list} = parse_manager(manager_path)
new_list =
system_name
|> add_system_to_list(list)
|> ensure_list_format()
new_contents =
[before_systems, "def systems do\n ", new_list, "\n end\n", after_systems]
|> IO.iodata_to_binary()
|> Code.format_string!()
Mix.shell().info([:green, "* injecting ", :reset, manager_path])
File.write!(manager_path, [new_contents, "\n"])
end
defp parse_manager(path) do
file = Helpers.read_manager_file!(path)
[top, rest] = String.split(file, "def systems do", parts: 2)
[list, bottom] = String.split(rest, ~r"\send\n", parts: 2)
{top, bottom, list}
end
defp add_system_to_list(system_name, list_as_string) do
{result, _binding} = Code.eval_string(list_as_string)
system_name
|> full_system_module()
|> then(&[&1 | result])
|> inspect()
end
defp full_system_module(system_name) do
Module.concat([Helpers.root_module(), "Systems", system_name])
end
# Adds a newline to ensure the list is formatted with one system per line
defp ensure_list_format(list_as_string) do
["[" | rest] = String.graphemes(list_as_string)
["[\n" | rest]
end
end