Skip to content

Instantly share code, notes, and snippets.

@the-mikedavis
Last active May 18, 2018 15:26
Show Gist options
  • Save the-mikedavis/03bb3a47185b6ad5ce0d7563dbfb1e8a to your computer and use it in GitHub Desktop.
Save the-mikedavis/03bb3a47185b6ad5ce0d7563dbfb1e8a to your computer and use it in GitHub Desktop.
Mix.exs to ex_doc config file converter

mix.exs -> ex_doc config file

The Elixir documentation generator tool ex_doc doesn't accept a mix.exs file as a configuration file (probably because you can't compile it without editing it). This script opens the local mix.exs file, reads all the necessary portions, and finds some other info, and then prints out all the necessary ex_doc options to a config file.

Why?

This allows you to autogenerate docs without doing any (repetitive) lifting. If you have a whole bunch of projects, adding ex_doc to deps is a pain. You can use the command line version of ex_doc instead, but there are a whole bunch of command line arguments that get in your way. The way around this is the sparsely documented config command line option, but, frustratingly, you can't just use a mix.exs file as that config. This tool converts that for you.

Usage

Drop this in to your project's root folder (same level as mix.exs and mix.lock) and run

$ elixir -r mix_to_ex_doc_config.exs
# Open the mix.exs file
[ defproj, _ | important_part ] = case File.read("mix.exs") do
{ :ok, contents } -> String.split(contents, "\n")
{ :error, _ } -> raise ~s(Could not open "mix.exs")
end
# Compile mix.exs file under new name
[ "defmodule Project do" | important_part ]
|> Enum.filter(&(! Regex.match?(~r/Mix.env/, &1))) # "Mix.env()" causes
|> Enum.join("\n") # compilation errors
|> Code.compile_string
module = defproj
|> String.replace(~r(defmodule ), "")
|> String.replace(~r(\.MixProject.*), "")
[ beam_path | _ ] =
case System.cmd("find", [".", "-name", "Elixir." <> module <> ".beam"]) do
{ _, 1 } -> raise "Could not find the BEAM files. Please compile first."
{ candidates, 0 } -> candidates
end
|> String.split("\n")
|> Enum.filter(&(Regex.match?(~r/dev/, &1)))
|> Enum.map(&Path.dirname/1)
abs_beam_path =
Path.absname(".")
|> Path.join(beam_path)
|> Path.expand
# New module in scope: Project
app = Project.project()
IO.puts "Name: #{app[:name]}"
IO.puts "Version: #{app[:version]}"
IO.puts "Repo: #{app[:source_url]}"
IO.puts "Module: #{module}"
IO.puts "Beam files: #{abs_beam_path}"
config =
app
|> Keyword.put(:main, module)
|> Keyword.put(:source_beam, abs_beam_path)
File.open!("ex_doc_config.exs", [:write])
|> IO.binwrite(Kernel.inspect(config, pretty: true))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment