Skip to content

Commit 898b2c2

Browse files
committed
Add membrane.gen.ex task
1 parent 709e0ad commit 898b2c2

3 files changed

Lines changed: 95 additions & 64 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
tmp/
2+
13
.elixir_ls
24
/priv/plts/*
35
!/priv/plts/.gitkeep
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
[Filter, Endpoint, Sink, Source, Bin, Pipeline]
2+
|> Enum.map(fn component_type ->
3+
component_name = inspect(component_type)
4+
5+
defmodule Module.concat(Mix.Tasks.Membrane.Gen, component_type) do
6+
@shortdoc "Generates a template for a Membrane #{component_name}"
7+
@moduledoc """
8+
Generates a template for a Membrane #{component_name} with the provided module name.
9+
10+
$ mix membrane.gen.#{String.downcase(component_name)} module_name [-l target_location]
11+
12+
## Options
13+
* `-l, --location` - If a target location is provided, the #{component_name} will be created there, relative to the `lib` directory.
14+
The filename must also be present and most likely have an `.ex` extension. If location is not provided, then it will be
15+
inferred from the provided module name - it will be converted to lowercase and `.` separators will be interpreted
16+
as directory separators. For example, a #{component_name} with module name `Foo.Bar` will be created at `lib/foo/bar.ex`.
17+
"""
18+
use Mix.Task
19+
20+
@switches [location: :string]
21+
@aliases [l: :location]
22+
23+
@impl true
24+
def run(argv) do
25+
do_run("lib", argv)
26+
end
27+
28+
@doc false
29+
def do_run(base_dir, argv) do
30+
{path_option, argv} = OptionParser.parse!(argv, aliases: @aliases, strict: @switches)
31+
32+
module =
33+
case argv do
34+
[] ->
35+
Mix.raise("""
36+
Module name not provided.
37+
38+
This task expects a module name, which the created #{unquote(component_type)} will have:
39+
40+
$ mix membrane.gen.#{String.downcase(unquote(component_name))} My#{unquote(component_name)}
41+
42+
""")
43+
44+
Mix.Tasks.Help
45+
46+
[module_name | _rest] ->
47+
Module.concat([module_name])
48+
end
49+
50+
component_path =
51+
case path_option do
52+
[] -> infer_path_from_module(module)
53+
[{:location, path} | _rest] -> path
54+
end
55+
|> then(&Path.join(base_dir, &1))
56+
57+
File.mkdir_p!(Path.dirname(component_path))
58+
59+
File.write!(component_path, get_component(module))
60+
end
61+
62+
defp infer_path_from_module(module) do
63+
module
64+
|> inspect()
65+
|> String.downcase()
66+
|> String.split(".")
67+
|> List.update_at(-1, &"#{&1}.ex")
68+
|> Path.join()
69+
end
70+
71+
defp get_component(module) do
72+
template =
73+
"../../../templates"
74+
|> Path.expand(__DIR__)
75+
|> Path.join(String.downcase(inspect(unquote(component_type))) <> ".ex")
76+
|> File.read!()
77+
78+
template
79+
|> String.split("\n")
80+
|> List.replace_at(0, "defmodule #{inspect(module)} do")
81+
|> Enum.join("\n")
82+
end
83+
end
84+
end)

lib/mix/tasks/membrane.gen.ex

Lines changed: 9 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,10 @@
1-
[Filter, Endpoint, Sink, Source, Bin, Pipeline]
2-
|> Enum.map(fn component_type ->
3-
defmodule Module.concat(Mix.Tasks.Membrane.Gen, component_type) do
4-
@moduledoc """
5-
Generates a template for a #{inspect(component_type)} with the provided module name.
6-
7-
$ mix membrane.gen.#{component_type |> Atom.to_string() |> String.downcase()} module_name [-l target_location]
8-
9-
## Options
10-
### `-l, --location`
11-
If a target location is provided, the #{inspect(component_type)} will be created there, relative to the `lib` directory.
12-
The filename must also be present and most likely have an `.ex` extension. If location is not provided, then it will be
13-
inferred from the provided module name - it will be converted to lowercase and `.` separators will be interpreted
14-
as directory separators. For example, a #{inspect(component_type)} with module name `Foo.Bar` will be created at `lib/foo/bar.ex`.
15-
"""
16-
use Mix.Task
17-
18-
@switches [location: :string]
19-
@aliases [l: :location]
20-
21-
@impl true
22-
def run(argv) do
23-
{path_option, argv} = OptionParser.parse!(argv, aliases: @aliases, strict: @switches)
24-
25-
module =
26-
case argv do
27-
[] -> raise "Module name not provided"
28-
[module_name | _rest] -> Module.concat([module_name])
29-
end
30-
31-
component_path =
32-
case path_option do
33-
[] -> infer_path_from_module(module)
34-
[{:location, path} | _rest] -> path
35-
end
36-
|> then(&Path.join("lib", &1))
37-
38-
File.mkdir_p!(Path.dirname(component_path))
39-
40-
File.write!(component_path, get_component(unquote(component_type), module))
41-
end
42-
43-
defp infer_path_from_module(module) do
44-
module
45-
|> inspect()
46-
|> String.downcase()
47-
|> String.split(".")
48-
|> List.update_at(-1, &"#{&1}.ex")
49-
|> Path.join()
50-
end
51-
52-
defp get_component(type, module) do
53-
template =
54-
"../../../templates"
55-
|> Path.expand(__DIR__)
56-
|> Path.join(String.downcase(inspect(type)) <> ".ex")
57-
|> File.read!()
58-
59-
template
60-
|> String.split("\n")
61-
|> List.replace_at(0, "defmodule #{inspect(module)} do")
62-
|> Enum.join("\n")
63-
end
1+
defmodule Mix.Tasks.Membrane.Gen do
2+
@shortdoc "Lists all available Membrane component generators"
3+
@moduledoc @shortdoc
4+
use Mix.Task
5+
6+
@impl true
7+
def run(_argv) do
8+
Mix.Tasks.Help.run(["--search", "membrane.gen."])
649
end
65-
end)
10+
end

0 commit comments

Comments
 (0)