Prior to v1.18.0
I used the following vode to reach the struct definition in a module from __before_compile__/2
callback.
defp fields(module) do
module
|> Module.get_attribute(:__struct__, %{})
|> Map.delete(:__struct__)
|> Map.keys()
end
I know that’s the undocumented, internal feature, but I did not manage to find a better way of doing this. In v1.18.0
this :__struct__
module attribute has gone. By digging down the rabbit hole, I managed to do the following:
defp fields(module) do
with {set, _bag} <- module |> :elixir_module.data_tables(),
true <- :ets.member(set, {:elixir, :struct}),
[{{:elixir, :struct}, [_ | _] = fields}] <- :ets.lookup(set, {:elixir, :struct}) do
for %{field: field} <- fields, do: field
end
end
While it works, it looks extremely hacky and might break again tomorrow. Is there the correct way of doing that that I am missing?
I’d unimport Kerner.defstruct
, import your own wrapper (I expect you have a use MyModule
) and have it persist the information you need in a way your before compile callback can access the information.
I hate to imply limitations like “you must use This
” before calling a standard library macro defstruct/1
onto the user. I expect the code below to work smoothly
defstruct [:foo, :bar]
use MyModule
In any case, I expect to be able to get a struct definition from the __before_compile__/2
callback, and I find the necessity to hack it quite disturbing.
Apologies for a likely uninformed question but don’t compilation tracers give you what you need? One of them is this:
{:struct_expansion, meta, module, keys}
- traced whenever module
’s struct is expanded. meta
is the struct AST metadata and keys
are the keys being used by expansion
https://hexdocs.pm/elixir/1.18.0-rc.0/Macro.html#struct_info!/2
This function is also capable of expanding structs defined under the module being compiled.
That might be the new way to go then based on the changelog.
2 Likes
Thanks a ton! I must have been reading the changelog without a brain involved.
Sure they would, but attaching a tracer to get a list of struct keys looks like an overkill to me.
And if you need to support previous versions, there is Macro.struct!
.
2 Likes