Hey, guys. I have a question about the metaprogramming.
Here is an example of my code (the online version):
defmodule MiniParams do
defmacro defparams(name, do: block) when is_atom(name) do
module_name = Module.concat([__MODULE__, Macro.camelize("#{name}")])
quote do
defmodule unquote(module_name) do
def echo() do
unquote(block)
IO.inspect(__MODULE__)
end
end
# other code will operated on above generated module
# ...
end
end
end
defmodule ControllerA do
require MiniParams
MiniParams.defparams :search do
IO.inspect("search defined in ControllerA")
end
end
defmodule ControllerB do
require MiniParams
MiniParams.defparams :search do
IO.inspect("search defined in ControllerB")
end
end
After calling defparams
in ControllerA
and ControllerB
, I expect that two modules will be generated:
ControllerA.MiniParams.Search
ControllerB.MiniParams.Search
But, currently, they all generate:
MiniParams.Search
And, the former one will override the previous one.
In order to make it work as I expected, I have to change the code (the online version):
# from
module_name = Module.concat([__MODULE__, Macro.camelize("#{name}")])
# to (specify the full name of module)
module_name = Module.concat([__CALLER__.module, __MODULE__, Macro.camelize("#{name}")])
But, I’m wondering why the original code doesn’t work ?
I did some experiments about this. If I don’t make module dynamic, everything is fine (the online version):
defmodule MiniParams do
defmacro defparams(name, do: block) when is_atom(name) do
quote do
# hardcode the expected module name
defmodule MiniParams.Search do
def echo() do
unquote(block)
IO.inspect(__MODULE__)
end
end
# other code will operated on above generated module
# ...
end
end
end
defmodule ControllerA do
require MiniParams
MiniParams.defparams :search do
IO.inspect("search defined in ControllerA")
end
end
defmodule ControllerB do
require MiniParams
MiniParams.defparams :search do
IO.inspect("search defined in ControllerB")
end
end
Back to question again, why does the original code not work?