From f1e233635811ee2889757067287dd6761df27568 Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Wed, 12 Jun 2024 19:37:32 -0400 Subject: [PATCH] docs: more docs --- documentation/writing-generators.md | 50 +++++++++++++++++++++++++++++ lib/igniter.ex | 2 ++ lib/mix/task.ex | 6 ++++ mix.exs | 3 +- 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 documentation/writing-generators.md diff --git a/documentation/writing-generators.md b/documentation/writing-generators.md new file mode 100644 index 0000000..8c605f2 --- /dev/null +++ b/documentation/writing-generators.md @@ -0,0 +1,50 @@ +# Writing Generators + +In `Igniter`, generators are done as a wrapper around `Mix.Task`, allowing them to be called individually or composed as part of a task. Since an example is worth a thousand words, lets take a look at an example that generates a file and ensures a configuration is set in the user's `config.exs`. + +```elixir +# lib/mix/tasks/your_lib.gen.your_thing.ex +defmodule Mix.Tasks.YourLib.Gen.YourThing do + use Igniter.Mix.Task + + def igniter(igniter, [module_name | _ ] = argv) do + module_name = Igniter.Module.parse(module_name) + path = Igniter.Module.proper_location(module_name) + app_name = Igniter.Application.app_name() + + igniter + |> Igniter.create_new_elixir_file(igniter, path, """ + defmodule #{inspect(module_name)} do + use YourLib.Thing + + ...some_code + end + """) + |> Igniter.Config.configure( + "config.exs", + app_name, + [:list_of_things], + [module_name], + &Igniter.Code.List.prepend_new_to_list(&1, module_name) + ) + end +end +``` + +Now, your users can run + +`mix your_lib.gen.your_thing MyApp.MyModuleName` + +and it will present them with a diff, creating a new file and updating their `config.exs`. + +Additionally, other generators can "compose" this generator using `Igniter.compose_task/3` + +```elixir +igniter +|> Igniter.compose_task(Mix.Tasks.YourLib.Gen.YourThing, ["MyApp.MyModuleName"]) +|> Igniter.compose_task(Mix.Tasks.YourLib.Gen.YourThing, ["MyApp.SomeOtherName"]) +``` + +## Writing a library installer + +Igniter will look for a mix task called `your_library.install` when a user runs `mix igniter.install your_library`. As long as it has the correct name, it will be run automatically as part of installation! diff --git a/lib/igniter.ex b/lib/igniter.ex index fffc784..414a1f5 100644 --- a/lib/igniter.ex +++ b/lib/igniter.ex @@ -96,6 +96,8 @@ defmodule Igniter do end @doc "Finds the `Igniter.Mix.Task` task by name and composes it (calls its `igniter/2`) into the current igniter." + def compose_task(igniter, task, argv \\ []) + def compose_task(igniter, task, argv) when is_atom(task) do Code.ensure_compiled!(task) diff --git a/lib/mix/task.ex b/lib/mix/task.ex index 1e89456..b69a671 100644 --- a/lib/mix/task.ex +++ b/lib/mix/task.ex @@ -1,6 +1,12 @@ defmodule Igniter.Mix.Task do @moduledoc "A behaviour for implementing a Mix task that is enriched to be composable with other Igniter tasks." + @doc """ + Whether or not it supports being run in the root of an umbrella project + + At the moment, this is still experimental and we suggest not turning it on. + """ @callback supports_umbrella?() :: boolean() + @doc "All the generator behavior happens here, you take an igniter and task arguments, and return an igniter." @callback igniter(igniter :: Igniter.t(), argv :: list(String.t())) :: Igniter.t() defmacro __using__(_opts) do diff --git a/mix.exs b/mix.exs index 78f591d..c4a4769 100644 --- a/mix.exs +++ b/mix.exs @@ -29,7 +29,8 @@ defmodule Igniter.MixProject do logo: "logos/igniter-logo-small.png", extra_section: "GUIDES", extras: [ - {"README.md", title: "Home"} + {"README.md", title: "Home"}, + "documentation/writing-generators.md" # "CHANGELOG.md" ], before_closing_head_tag: fn type ->