wwaldner
How to create some form of module registry that can be used to lookup a module by name?
Has anyone come up with a good way to create some form of module registry that can be used to lookup a module by name. My use case is to have a module that can deserialize a list of heterogeneous items. I would like the different items to be added to a registry automatically. Ultimately, it would be nice to ‘auto’ generate the Filters module below.
defmodule Filters do
@moduledoc """
Module that aids in dealing with filters. It acts as a registry that
knows about all the filter types at compile time.
Supports serializing and deserializing a list of heterogeneous filter types.
"""
# Serialize a specific filter, adding name to serialized value.
# this can be better handled with `Protocols` and defimpl in __using__ macro.
# This is not the difficult part.
def serialize(%Filter1{} = filter) do
%{
type: "filter1",
value: Filter1.serialize(filter)
} |> Jason.encode!()
end
def deserialize(s) when is_binary(s) do
# s is a json encoded string that needs to be
# deserialized into one of the filter modules below
deserialize(Jason.decode!(s))
end
# THIS IS THE FUNCTION THAT I WOULD LIKE TO GET AUTO GENERATED, or have
# some kind of registry that can give me the module for some arbitrary name.
#
# Some means to create a specific struct given some name, in this case, "filter1"
def deserialize(%{type: "filter1", value: value}) do
Filter1.deserialize(value)
end
end
defmodule Filter1 do
# can something be done in the declaration of this module
# to add it to the Filters module?
def serialize(filter), do...
def deserialize(data), do...
end
defmodule Filter2 do
...
end
Most Liked
zachdaniel
Having gone down this road many times (trying to build lists of modules dynamically based on properties) I’d advise against it. It can work well enough for production, but in development mode things can get very frustrating very quickly because of incremental recompilation.
My general suggestion for this is to instead have a module that lists all of these, i.e
defmodule MyFilters do
def filters, do: [Filter1, Filter2, Filter3]
end
And then add this:
defmodule Filter do
defmacro __using__(_) do
quote do
@behaviour Filter
unless __MODULE__ in MyFilter.filters() do
raise "Hey, don't forget to put this module into the list in MyFilter"
end
end
end
end
Then in each filter, you say
use Filter
which sets up the behaviour and also validates that you are in the registry of filters. This way, when someone inevitably copies one and renames it, they get a helpful error. Its not as convenient as having a module magically detect other modules, but trust me that kind of thing has so many edge cases.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance









