I would like to use the before_compile module hook to programmatically generate lenses for some modules.
I have something roughly like that:
defmodule Blabla do
@before_compile {Blabla.Lens, :__before_compile__}
def module A do
defstruct [...]
end
def module B do
defstruct [...]
end
end
defmodule Blabla.Lens do
def __before_compile__(env) do
# (1) retrieve the keys of the module
# (2) generate lenses definitions for the keys
end
end
How can I generate a function definition for the module Lens within the __before_compile__ module?
Do I have to use a __using__ macro instead or is it possible?
Let’s assume for the moment that I can retrieve the keys of the structs defined in A or B from the __before_compile__ function [1].
I would like to define the lenses like this, for example if A has key k1:
@k1 Lens.make_lens(:k1)
Or do you see a better solution? I was thinking about using a function to retrieve the lens but I am realising this would not work (except maybe with a macro).
I could I define an attribute in Lens from the __before_compiling function?
[1] I can because I am defining them with a google protobuf library and I can access the keys with .keys
Thanks for your patience and sorry that I cannot express my ideas as clearly as I want.
Given this function:
defmodule Blabla.Lens do
def __before_compile__(env) do
# how to define an attribute and function in the `Blabla.Lens` module from this function?
end
end
When __before_compile__ is executed, how can I define an attribute (and a function) dynamically inside the Blabla.Lens module? I would like this definition to happen within the call to the function. The need to do it dynamically comes from the fact that the struct defines in my post are generated also dynamically from another library given a schema declaration (with protobuf, but it does not really matter here).
As far as I remember, the env variable contains the name of the module that is calling into the hook.
But as the module does not exist yet, you can’t do much with it. You can not call __struct__, nor can you ask for its attributes nor anything else.
But in general, the function has to return an AST, so whatever AST you return will be injected into the module in question.
Also, just to make clear, Blabla.Lens.__before_compile__/1 can not change the module Blabla.Lens anymore, as it has already been compiled. If it were not compiled already you weren’t able to call that function.
If you want to generate parts of Blabla.Lens depending on structs defined in other modules, you need to generate the AST by collection from those struct defining modules during compile time of Blabla.Lens.
You can use __struct__/0 to get an empty struct, remove the __struct__ key, iterate over the remaining keys, generate your code. The usual meta-programming stuff.
Thanks for your answer. I just discovered it needs to return an AST only when it is defined as a macro. But is it possible to generate definitions when __before_compile__ is defined as a function?