Injecting code in macro with references to outer scope

Hello!

I’m working with macros and I am trying to inject some code into a use macro to be used “as-is” but I’m having some trouble making it work.

I would like to be able to define a __using__ macro which takes some options and creates a function that can use those options “as-is” i.e. if I pass Application.get_env(...) it will get the env at the time of the call, something like

defmodule HypotheticMod do
  # Let's assume this will create a foo function
  # which returns the value of Application.get_env(:app, :foo, 0)
  use InjectMacro, option: Application.get_env(:app, :foo, 0)

  def get_foo_from_env(), do: foo()
end

The first version I tried was this

Application.delete_env(:app, :test)

defmodule Foo do
  defmacro __using__(opts) when is_list(opts) do
    foo = Keyword.get(opts, :foo)

    quote do
      def func() do
        unquote(foo)
      end
    end

  end
end

defmodule Bar do  
  a = 1
  use Foo, foo: Application.get_env(:app, :test, a)
end

a = 2
Application.put_env(:app, :test, a)

Bar.func()

and I expected Bar.func() to output 2, but I get the following error:

function a/0 (expected Bar to define such a function or for it to be imported, but none are available)

Next I tried this

Application.delete_env(:app, :test)

defmodule Foo do
  defmacro __using__(opts) when is_list(opts) do
    foo = Keyword.get(opts, :foo)

    quote bind_quoted: [foo: foo] do
      def func() do
        unquote(foo)
      end
    end

  end
end

defmodule Bar do  
  a = 1
  use Foo, foo: Application.get_env(:app, :test, a)
end

a = 2
Application.put_env(:app, :test, a)

Bar.func()

which returns 1 for some reason I don’t understand.

I am surely missing something, can anyone help me?

Thanks :pray: