Packages

plymio_codi: Generating Quoted Forms for Common Code Patterns

Current section

Files

Jump to
plymio_codi lib codi utility builder.ex
Raw

lib/codi/utility/builder.ex

defmodule Plymio.Codi.Utility.Builder do
@moduledoc false
require Plymio.Fontais.Option.Macro, as: PFOM
use Plymio.Fontais.Attribute
use Plymio.Codi.Attribute
use Plymio.Codi.Attribute.Builder
import Plymio.Codi.Error,
only: [
new_error_result: 1
]
import Plymio.Fontais.Option,
only: [
opts_canonical_keys: 2,
opts_create_aliases_dict: 1,
opts_normalise: 1,
opts_validate: 1,
opts_fetch: 2,
opts_get: 3,
opts_put: 3,
opts_merge: 1,
opzioni_merge: 1
]
import Plymio.Funcio.Enum.Map.Collate,
only: [
map_collate0_enum: 2,
map_concurrent_collate0_enum: 2
]
import Plymio.Codi.CPO
@plymio_codi_builder_opts_kvs_aliases [
@plymio_codi_builder_alias_getset_namer,
@plymio_codi_builder_alias_getset_default,
@plymio_codi_builder_alias_pattern_namer,
@plymio_codi_builder_alias_pattern_builder
]
@plymio_codi_builder_opts_dict_aliases @plymio_codi_builder_opts_kvs_aliases
|> opts_create_aliases_dict
def builder_opts_normalise(opts, dict \\ @plymio_codi_builder_opts_dict_aliases) do
opts |> opts_canonical_keys(dict)
end
@plymio_codi_builder_spec_kvs_aliases [
{@plymio_codi_builder_patterns, [:verbs, :fun, :funs]},
{@plymio_codi_builder_cpo, []},
@plymio_codi_builder_alias_getset_namer,
@plymio_codi_builder_alias_pattern_namer,
@plymio_codi_builder_alias_pattern_builder
]
@plymio_codi_builder_spec_dict_aliases @plymio_codi_builder_spec_kvs_aliases
|> opts_create_aliases_dict
def builder_spec_normalise(spec, dict \\ @plymio_codi_builder_spec_dict_aliases) do
spec |> opts_canonical_keys(dict)
end
[
builder_get_getset_namer: %{
key: @plymio_codi_builder_getset_namer,
default: @plymio_fontais_the_unset_value
},
builder_get_getset_default: %{
key: @plymio_codi_builder_getset_default,
default: %{} |> Macro.escape()
},
builder_get_pattern_namer: %{
key: @plymio_codi_builder_pattern_namer,
default: @plymio_fontais_the_unset_value
},
builder_get_pattern_builder: %{
key: @plymio_codi_builder_pattern_builder,
default: @plymio_fontais_the_unset_value
},
builder_spec_get_patterns: %{
key: @plymio_codi_builder_patterns,
default: []
},
builder_spec_get_cpo: %{
key: @plymio_codi_builder_cpo,
default: []
}
]
|> PFOM.def_custom_opts_get()
[
builder_fetch_getset_namer: @plymio_codi_builder_getset_namer,
builder_fetch_pattern_namer: @plymio_codi_builder_pattern_namer,
builder_fetch_pattern_builder: @plymio_codi_builder_pattern_builder
]
|> PFOM.def_custom_opts_fetch()
[
builder_put_getset_namer: @plymio_codi_builder_getset_namer,
builder_put_getset_default: @plymio_codi_builder_getset_default,
builder_put_pattern_namer: @plymio_codi_builder_pattern_namer,
builder_put_pattern_builder: @plymio_codi_builder_pattern_builder
]
|> PFOM.def_custom_opts_put()
defp pattern_builder_default(cpo, name, pattern)
defp pattern_builder_default(cpo, _name, _pattern) do
{:ok, cpo}
end
# defp pattern_builder_default(pattern, name, _cpo) do
# new_error_result(m: "pattern for name #{inspect name} invalid", v: pattern)
# end
def create_struct_getset_patterns(specs, opts \\ [])
def create_struct_getset_patterns(specs, opts) do
with {:ok, specs} <- specs |> opts_validate,
{:ok, opts} <- opts |> builder_opts_normalise,
{:ok, getset_default} <- opts |> builder_get_getset_default,
{:ok, pattern_builder} <-
opts |> builder_get_pattern_builder(&pattern_builder_default/3),
# build the default spec
{:ok, spec_opts} <- getset_default |> opts_normalise,
{:ok, spec_opts} <- spec_opts |> builder_put_pattern_builder(pattern_builder),
true <- true do
specs
|> map_collate0_enum(fn
{name, spec} when is_atom(name) and is_nil(spec) ->
{:ok, {name, spec_opts}}
{name, spec} when is_atom(name) and is_map(spec) ->
{:ok, {name, spec_opts ++ Map.to_list(spec)}}
{name, spec} when is_atom(name) and is_list(spec) ->
with {:ok, spec} <- spec |> opts_normalise do
{:ok, {name, spec_opts ++ spec}}
else
{:error, %{__exception__: true}} = result -> result
end
{name, x} ->
new_error_result(m: "build spec for #{inspect(name)} invalid", v: x)
x ->
new_error_result(m: "build spec invalid", v: x)
end)
|> case do
{:error, %{__struct__: _}} = result ->
result
{:ok, specs} ->
specs
|> map_concurrent_collate0_enum(fn {name, spec} ->
with {:ok, spec} <- spec |> builder_spec_normalise,
{:ok, pattern_builder} <- spec |> builder_fetch_pattern_builder,
{:ok, patterns} <- spec |> builder_spec_get_patterns,
true <- true do
patterns
|> List.wrap()
|> Enum.uniq()
|> map_collate0_enum(fn pattern ->
with {:ok, cpo} <- spec |> builder_spec_get_cpo,
{:ok, cpo} <- cpo |> cpo_normalise,
{:ok, cpo} <- cpo |> pattern_builder.(name, pattern),
{:ok, cpo} <- cpo |> cpo_normalise,
true <- true do
{:ok, cpo}
else
{:error, %{__exception__: true}} = result -> result
end
|> case do
{:error, %{__struct__: _}} = result -> result
{:ok, name_patterns} -> name_patterns |> opts_merge
end
end)
else
{:error, %{__exception__: true}} = result -> result
end
end)
|> case do
{:error, %{__struct__: _}} = result ->
result
{:ok, patterns_cpos} ->
with {:ok, cpos} <- patterns_cpos |> opzioni_merge do
{:ok, cpos |> Enum.map(fn cpo -> {@plymio_codi_key_pattern, cpo} end)}
else
{:error, %{__exception__: true}} = result -> result
end
end
end
else
{:error, %{__exception__: true}} = result -> result
end
end
end