Compiling External Resources with Elixir

Posted on 05 Mar 2018 by Eric Oestrich

The other week I started playing around with the @external_resource tag in Elixir. I wanted to do something similar to a translations file for the admin panel in ExVenture for help text. I didn’t want to default to a YAML file as I’ve heard the elixir community isn’t thrilled with it, so I took a look around to see what I could do.

What I ended up with was a macro that could compile a text file into Elixir functions. It also live reloads with the Phoenix code reloader in development because of @external_resource, this is really cool to see working.

Help File Format

This is the file format I wanted to end up with. Keys and values essentially separated by new lines.

room.ecology:
  Room ecology changes the color of the map "icon" in the map grid.

room.feature:
  Room features are appended to the end of a room's description.

You can see the full file here.

Help Macro

The end result of the macro will give us an API as follows:

iex> Web.Help.get("room.feature")
"Room features are appended to the end of a room's description."

This works via a macro (full file here) that loads the file and compiles it into quoted functions. The import sections are copied below:

defmacro __using__(file) do
  help_file = Path.join(:code.priv_dir(:ex_venture), file)
  {:ok, help_text} = File.read(help_file)
  quotes = generate_gets(help_text)
  quotes = Enum.reverse([default_get() | quotes])
  [external_resource(help_file) | quotes]
end

defp generate_gets(help_text) do
  help_text
  |> String.split("\n")
  |> Enum.reject(&(&1 == ""))
  |> Enum.map(&String.trim/1)
  |> convert_to_map()
  |> Enum.map(fn {key, val} ->
    quote do
      def get(unquote(key)) do
        unquote(val)
      end
    end
  end)
end

defp external_resource(help_file) do
  quote do
    @external_resource unquote(help_file)
  end
end

The __using__ macro reads the file and generates the get quotes and the external resource quote. The external_resource/1 function is how the code live reloads when editing the text file. The generate_gets/1 function parses the help file to generate a list of quoted functions, something I’ve never tried before. It was pretty cool to see you can return a list of quoted functions and get the same result.

Conclusion

It is really cool to see the live reloading work. This may or may not be the best way to do what I want, but I had a lot of fun writing this. I think if these help files grow to be hundreds of keys long I will want to change up how this is parsing, but for now it works out well.

Lastly, you can check out more ExVenture at exventure.org and see my running instance at midmud.com.

comments powered by Disqus
Creative Commons License
This site's content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License unless otherwise specified. Code on this site is licensed under the MIT License unless otherwise specified.