1

I have a general-purpose loader for fetching records from a database:

defmodule Loader do
  defmacro __using__(opts) do
    quote location: :keep, bind_quoted: [schema: opts[:schema]] do

      def one(id), do: unquote(schema) |> Repo.get(id)
      def all,     do: unquote(schema) |> Repo.all
    end
  end
end

and particular loaders fro specific schemas:

defmodule Location.Loader do
  use Loader, schema: Location
end

Is there any way to communicate with "used" module in some other way e.g. __MODULE__.parent?

5
  • 1
    What is it that you would like to do? You can refer to the module by name like any other module. Commented Apr 26, 2016 at 8:13
  • 1
    The thing you are trying to do looks a little bit overcomplicated. I would also like to know what are you trying to achieve. Commented Apr 26, 2016 at 8:46
  • As you can see, I want to have access in Loader to Location which is a "top" module of a module where Loader is used. Commented Apr 26, 2016 at 8:46
  • What is the reason you want to access Loader. What do you mean by "access" - call functions? If so you can call public functions with Loader.some_function(). There is no way to call private functions from another module. Commented Apr 26, 2016 at 8:56
  • I want to use Location.Loader.all or Location.Loader.one(123). The thing is that I want to know somehow in general Loader, the name of module it is invoked from e.g. Location.Loader. I achieved that by passing this in opts but i wonder if there's any other way to do so. Commented Apr 26, 2016 at 10:26

1 Answer 1

2

You can use __MODULE__ from inside the quote of Loader.__using__, and use Module.split/1, Enum.drop/2, and Module.concat/1 to get the parent module.

defmodule Loader do
  defmacro __using__(opts) do
    quote location: :keep, bind_quoted: [schema: opts[:schema]] do
      @parent_module __MODULE__ |> Module.split |> Enum.drop(-1) |> Module.concat
      def one(id), do: IO.puts("#{@parent_module}:one:#{id}")
      def all,     do: IO.puts("#{@parent_module}:all")
    end
  end
end

defmodule Location.Loader do
  use Loader
end

Location.Loader.one 123
Location.Loader.all

prints

Elixir.Location:one:123
Elixir.Location:all

But, I would recommend not using this and using your original code as it's more explicit, and from my experience, considered more idiomatic.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.