Current section
Files
Jump to
Current section
Files
lib/railyard/dsl.ex
defmodule Railyard.Dsl do
@moduledoc """
Use `Railyard.Dsl` in a module to turn it into a **resource module**.
"""
defmacro __using__(_opts \\ []) do
quote do
require Railyard.Util.BlockMap
require Railyard.Dsl
import Railyard.Dsl, only: [resource: 3, resource: 4]
@dsl_resources %{}
@ship_before []
@ship_after []
@before_compile Railyard.Dsl
:ok
end
end
defmacro __before_compile__(_env) do
quote do
def ship(bindings) do
before_results =
@ship_before
|> Enum.map(fn mod -> {mod, apply(mod, :ship, bindings)} end)
results =
@dsl_resources
|> Enum.reject(fn {_rc_name, rc} ->
case Railyard.ResourceSpec.eval_property(rc, :skip_if, bindings) do
{:skip_if, value} -> true
_ -> false
end
end)
|> Enum.map(fn {_k, v} -> v end)
|> Railyard.ship(bindings)
after_results =
@ship_after
|> Enum.map(fn mod -> {mod, apply(mod, :ship, bindings)} end)
end
end
end
@doc """
Defines a **resource spec** within the module.
Name
"""
defmacro resource(name, type, attributes_or_block, block_if_no_attributes \\ nil) do
unnamed_resource =
build_resource_spec(
name,
type,
attributes_or_block,
block_if_no_attributes
)
quote do
@dsl_resources Map.put(
@dsl_resources,
unquote(name),
%Railyard.ResourceSpec{
unquote(unnamed_resource)
| module: __MODULE__
}
)
def unquote(name)() do
Map.get(@dsl_resources, unquote(name))
end
end
end
defmacro ship_before(module) do
quote do
@ship_before [module | @ship_before]
end
end
defmacro ship_after(module) do
quote do
@ship_after [module | @ship_after]
end
end
defp build_resource_spec(name, type, attributes, do: block) do
quote do
%Railyard.ResourceSpec{
name: unquote(name),
type: unquote(type),
attributes: unquote(attributes),
block: Railyard.Util.BlockMap.create_block(do: unquote(block))
}
end
end
defp build_resource_spec(name, type, [do: block], nil) do
quote do
%Railyard.ResourceSpec{
name: unquote(name),
type: unquote(type),
attributes: [],
block: Railyard.Util.BlockMap.create_block(do: unquote(block))
}
end
end
end