I’m writing a CLI tool that loads a user-defined module which I inject a module attribute into. My first solution was grabbing some GenServer state in in the __using__/1
callback of the module the user has to use
, but I thought I’d avoid state and try and do it by injecting it into the AST. After several minding hours of going down the wrong paths I got it working! The satisfaction is real but it’s a bit ugly. I was wondering if anyone could help me clean it up. I’m sure when I put some more time into it later I can figure it out but my brain is burnt out and some human interaction over it would be nice
Here’s what I have:
def do_the_thing(module_attribute_value) do
{:ok, ast} =
Path.join(~w[path to user defined module])
|> File.read!()
|> Code.string_to_quoted()
{:defmodule, line, [aliases | [[do: {:__block__, meta, body}]]]} = ast
args = Macro.escape(module_attribute_value)
module_attribute = quote(do: (@args unquote(args)))
body = [module_attribute | body]
ast = {:defmodule, line, [aliases | [[do: {:__block__, meta, body}]]]}
[{module | _}] = Code.compile_quoted(ast)
# do some other stuff
end
Also, are there any repercussions of the [line: n]
nodes getting out of whack with my solution? Anything else, aside from being a bit ugly, that could go wrong with it?
Thanks!
PS: I’m looking for help on the AST injection specifically, I plan on adding error-handling and all that.
EDIT: It’s already causing problems, lol. So ya, how to you reliably inject a line at the top of a module?