Skip to content

Commit

Permalink
feat: extension section module imports, generated .formatter.exs
Browse files Browse the repository at this point in the history
  • Loading branch information
zachdaniel committed Jun 14, 2020
1 parent c776da9 commit d1e416b
Show file tree
Hide file tree
Showing 11 changed files with 159 additions and 34 deletions.
3 changes: 2 additions & 1 deletion .check.exs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"mix coveralls.github"
else
"mix test"
end}
end},
{:check_formatter, command: "mix ash.formatter --check"}

## custom new tools may be added (mix tasks or arbitrary commands)
# {:my_mix_task, command: "mix release", env: %{"MIX_ENV" => "prod"}},
Expand Down
46 changes: 27 additions & 19 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -1,27 +1,35 @@
# Used by "mix format"
# THIS FILE IS AUTOGENERATED USING `mix ash.formatter`
# DONT MODIFY IT BY HAND
locals_without_parens = [
read: 1,
read: 2,
create: 1,
create: 2,
update: 1,
update: 2,
destroy: 1,
destroy: 2,
actions: 1,
primary_key?: 1,
allow_nil?: 1,
generated?: 1,
writable?: 1,
update_default: 1,
default: 1,
type: 1,
attribute: 2,
attribute: 3,
belongs_to: 2,
belongs_to: 3,
create_timestamp: 1,
update_timestamp: 1,
destination_field: 1,
source_field: 1,
reverse_relationship: 1,
source_field_on_join_table: 1,
destination_field_on_join_table: 1,
through: 1,
define_field?: 1,
field_type: 1,
has_one: 2,
has_one: 3,
has_many: 2,
has_many: 3,
many_to_many: 2,
many_to_many: 3,
resources: 1,
destination_field: 1,
allow_nil?: 1
belongs_to: 2,
primary?: 1,
create: 1,
read: 1,
update: 1,
destroy: 1,
description: 1,
resource: 1
]

[
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Elixir CI
name: Ash CI

on:
push:
Expand Down
15 changes: 11 additions & 4 deletions lib/ash.ex
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,19 @@ defmodule Ash do
|> Enum.find(&(&1.name == relationship_name))
end

@spec resource_module?(module) :: boolean
def resource_module?(module) do
def implements_behaviour?(module, behaviour) do
:attributes
|> module.module_info()
|> Keyword.get(:behaviour, [])
|> Enum.any?(&(&1 == Ash.Resource))
|> Enum.flat_map(fn
{:behaviour, value} -> List.wrap(value)
_ -> []
end)
|> Enum.any?(&(&1 == behaviour))
end

@spec resource_module?(module) :: boolean
def resource_module?(module) do
implements_behaviour?(module, Ash.Resource)
end

@doc false
Expand Down
17 changes: 16 additions & 1 deletion lib/ash/dsl/extension.ex
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,13 @@ defmodule Ash.Dsl.Extension do
section_path = unquote(path ++ [section.name])
section = unquote(Macro.escape(section))

configured_imports =
for module <- unquote(section.imports) do
quote do
import unquote(module)
end
end

entity_imports =
for module <- unquote(entity_modules) do
quote do
Expand All @@ -376,6 +383,13 @@ defmodule Ash.Dsl.Extension do
]
end

configured_unimports =
for module <- unquote(section.imports) do
quote do
import unquote(module), only: []
end
end

entity_unimports =
for module <- unquote(entity_modules) do
quote do
Expand Down Expand Up @@ -404,6 +418,7 @@ defmodule Ash.Dsl.Extension do
entity_imports ++
section_imports ++
opts_import ++
configured_imports ++
[
quote do
unquote(body[:do])
Expand Down Expand Up @@ -433,7 +448,7 @@ defmodule Ash.Dsl.Extension do
opts: opts
})
end
] ++ opts_unimport ++ entity_unimports ++ section_unimports
] ++ configured_unimports ++ opts_unimport ++ entity_unimports ++ section_unimports
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/ash/dsl/section.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ defmodule Ash.Dsl.Section do
For a full example, see `Ash.Dsl.Extension`.
"""
defstruct [:name, schema: [], describe: "", entities: [], sections: []]
defstruct [:name, imports: [], schema: [], describe: "", entities: [], sections: []]

@type t :: %__MODULE__{
name: atom,
Expand Down
2 changes: 1 addition & 1 deletion lib/ash/resource/relationships/many_to_many.ex
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ defmodule Ash.Resource.Relationships.ManyToMany do
type: :atom,
required: true,
doc:
"The field on the join table that should line up with `source_field` on this resource. Default: [resource_name]_id"
"The field on the join table that should line up with `source_field` on this resource."
],
destination_field_on_join_table: [
type: :atom,
Expand Down
2 changes: 1 addition & 1 deletion lib/ash/resource/relationships/shared_options.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ defmodule Ash.Resource.Relationships.SharedOptions do
destination_field: [
type: :atom,
doc:
"The field on the related resource that should match the `source_field` on this resource. Default: [resource.name]_id"
"The field on the related resource that should match the `source_field` on this resource."
],
source_field: [
type: :atom,
Expand Down
5 changes: 1 addition & 4 deletions lib/ash/type/type.ex
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,6 @@ defmodule Ash.Type do
end

defp ash_type_module?(module) do
:attributes
|> module.module_info()
|> Keyword.get(:behaviour, [])
|> Enum.any?(&(&1 == __MODULE__))
Ash.implements_behaviour?(module, __MODULE__)
end
end
95 changes: 95 additions & 0 deletions lib/mix/tasks/ash.formatter.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
defmodule Mix.Tasks.Ash.Formatter do
@moduledoc "Generates a .formatter.exs from a list of extensions, and writes it."
use Mix.Task

@formatter_exs_template """
# THIS FILE IS AUTOGENERATED USING `mix ash.formatter`
# DONT MODIFY IT BY HAND
locals_without_parens = [
<%= for {function, arity} <- locals_without_parens do %>
<%= function %>: <%= arity %>,
<% end %>
]
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
locals_without_parens: locals_without_parens,
export: [
locals_without_parens: locals_without_parens
]
]
"""

@shortdoc @moduledoc
def run(opts) do
{opts, []} = OptionParser.parse!(opts, strict: [check: :boolean, extensions: :string])

unless opts[:extensions] do
raise "Must supply a comma separated list of extensions to generate a .formatter.exs for"
end

locals_without_parens =
opts[:extensions]
|> String.split(",")
|> Enum.flat_map(fn extension ->
extension_mod = Module.concat([extension])

all_entity_builders(extension_mod.sections())
end)
|> Enum.uniq()

contents =
@formatter_exs_template
|> EEx.eval_string(locals_without_parens: locals_without_parens)
|> Code.format_string!()
|> Enum.join()
|> Kernel.<>("\n")

if opts[:check] do
if File.read!(".formatter.exs") != contents do
raise """
.formatter.exs is not up to date!
Run the following command and commit the result:
mix ash.formatter --extensions #{opts[:extensions]}
"""
end
else
File.write!(".formatter.exs", contents)
end
end

defp all_entity_builders(sections) do
Enum.flat_map(sections, fn section ->
Enum.concat([
entity_option_builders(section),
section_option_builders(section),
entity_builders(section)
])
end)
end

defp entity_builders(section) do
Enum.map(section.entities, fn entity ->
{entity.name, Enum.count(entity.args)}
end) ++ all_entity_builders(section.sections())
end

defp entity_option_builders(section) do
Enum.flat_map(section.entities, fn entity ->
entity.schema
|> Keyword.drop(entity.args)
|> Enum.map(fn {key, _schema} ->
{key, 1}
end)
end)
end

defp section_option_builders(section) do
Enum.map(section.schema, fn {key, _} ->
{key, 1}
end)
end
end
4 changes: 3 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ defmodule Ash.MixProject do
elixirc_paths: elixirc_paths(Mix.env()),
package: package(),
deps: deps(),
dialyzer: [plt_add_apps: [:mix]],
test_coverage: [tool: ExCoveralls],
preferred_cli_env: [
coveralls: :test,
Expand Down Expand Up @@ -97,7 +98,8 @@ defmodule Ash.MixProject do
defp aliases do
[
sobelow: "sobelow --skip",
credo: "credo --strict"
credo: "credo --strict",
"ash.formatter": "ash.formatter --extensions Ash.Dsl,Ash.Api.Dsl"
]
end
end

0 comments on commit d1e416b

Please sign in to comment.