Reputation: 382
I want to put my Accounts context functions into their own files, then import them into the context so that I can alias the App.Accounts
in my controllers and use the functions that were imported into the context.
See below for the rough setup that I am after.
defmodule App.Accounts.UserAPI do
alias App.Accounts.User
def get_user!(id), do: User.get!(User, id) end
defmacro __using__(_) do
import App.Accounts.UserAPI
end
defmodule App.Accounts do
alias App.Accounts.UserAPI
use UserAPI
end
defmodule AppWeb.UserController do
alias App.Accounts
IO.inspect Accounts.module_info
# [
# module: Ev2.Accounts,
# exports: [__info__: 1, module_info: 0, module_info: 1],
# attributes: [vsn: [234644860605005629180170678994286615550]],
# compile: [options: [:debug_info], version: '7.0.4',
# source: '/Users/.../accounts.ex'],
# native: false,
# md5: <<176, 134, 244, 210, 70, 244, 89, 41, 130, 7, 134, 109, 55, 131, 27, 254>>
# ]
def index(conn, %{"id" => id}) do
Accounts.get_user(id) # Accounts.get_user/1 is not defined
end
end
I currently have it working by wrapping the entire App.UserAPI
in __using__
macro and quotes, but that feels verbose and wrapping in quote seems to prevent me from calling utility functions from within the UserAPI
.
Why do the UserAPI
functions not appear in the Accounts.module_info
exports?
And what is the "right" way to do this?
Thanks!
Upvotes: 0
Views: 716
Reputation: 222040
The problem is that imported functions are not exported by a module. They're only available in the context of the import. You want to re-export imported functions. There are two ways I can think of.
What you're currently doing according to your description: define all functions in a quote block in __using__
:
defmodule App.Accounts.UserAPI do
defmacro __using__(_) do
quote do
alias App.Accounts.User
def get_user!(id), do: User.get!(User, id) end
end
end
end
Use defdelegate
to define a function which just calls another function:
defmodule App.Accounts.UserAPI do
def get_user!(id), do: User.get!(User, id) end
defmacro __using__(_) do
quote do
defdelegate :get_user!(id), to: App.Accounts.UserAPI
end
end
end
In both cases, a use App.Accounts.UserAPI
will do what you want.
Upvotes: 3