tmbb
I have some relatively legitimate reasons do do something like this (even if you think this is not even remotely legitimate, the question at the end is independent from this):
defmodule MySnippet do
defmacro __using__(_) do
quote do
def common_function1() do
# ...
end
def common_function2() do
# ...
end
# etc...
end
end
end
defmodule MyModule1 do
use MySnippet
def specific_function1() do
# ...
end
def specific_function2() do
# ...
end
# etc...
end
defmodule MyModule2 do
use MySnippet
def specific_function_a() do
# ...
end
def specific_function_b() do
# ...
end
# etc...
end
I’ve thought about defining a defsnippet macro that exapnds so that I coould do this:
require Snippet
Snippet.defsnippet MySnippet do
def f(x), do: x
def g(x), do: x
end
This way, it looks like a normal module definition and is easier to type.
I’ve written the following macro, which tries to encapsulate the module definition and the __using__/1 macro definition.
defmodule Snippet do
defmacro defsnippet(module_name, [do: body]) do
quote bind_quoted: [module_name: module_name, body: body] do
defmodule module_name do
@doc false
defmacro __using__(_opts) do
quote do
body
end
end
end
end
end
end
But when I try to run it like this
# lib/schism/example.ex
require Snippet
Snippet.defsnippet MySnippet do
def f(x), do: x
def g(x), do: x
end
I get this error:
== Compilation error in file lib/schism/example.ex ==
** (ArgumentError) cannot invoke def/2 outside module
(elixir) lib/kernel.ex:5142: Kernel.assert_module_scope/3
(elixir) lib/kernel.ex:3905: Kernel.define/4
(elixir) expanding macro: Kernel.def/2
lib/schism/example.ex:4: (file)
expanding macro: Snippet.defsnippet/2
lib/schism/example.ex:3: (file)
I don’t understand where this comes from, because I’m not calling def/2 outside of a module. I’m just taking some AST that happens to contain defs and putting it inside a macro which I can invoke later.
Doing all of this just to save some typing is probably not worth it and I don’t know if I’ll end up going that way, but no I’m curious about what the problem is independently of the rest.
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #hex
- #security










Showing Posts 1 to 3- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
mudasobwa
I am not sure if it fixes the whole issue (I believe it does,) but you definitely should use
Module.create/3notKernel.defmodule/2in this context.OvermindDL1
Eh I think defmodule is fine here.
However the issue is that you cannot use
bind_quotedin this way (I learned that well long ago). Basically what bind_quoted will do is turn the code into something like this from the return of your macro:And this is why you are getting the
defis not allowed here message. I’ve always had to do ‘fun’unquotemessing when I had to do similar things. So if you Macro.escape thebodyin bind_quoted then useunquote(body)inside the function then it might work (you might need to ‘escape’ the innerquotethough or something like that, I usually just don’t use bind_quoted at all in this case and justunquotethrough the layers as needed or build the AST manually without quote…).tmbb
It doesn’t. In fact,
defmoduledoesn’t have anything to do with it. OverminDL1 has given the correct answer. Thanks for your input anyway!