How to create and publish Hex.pm package (Elixir)

How to build and publish Hex.pm Elixir package

In that article I’m going to show you how to create your own Elixir package from scratch and how to upload it to Hex.pm website which is a package manager for Elixir (and Erlang) ecosystem.

Although you don’t have to upload your package to hex.pm to make it available for others, it’s good to do this as this is the biggest catalog of useful Erlang and Elixir libraries (you can have it on GitHub for example). Hex.pm also gives some useful information like number of downloads.

I have my own Hex.pm package already. You can find it here https://hex.pm/packages/exiban and it’s a library to validate and manipulate on IBAN bank account numbers.

I’m gonna show you in a few steps how I’ve built it and made it available.

Requirements

I’ll show you how to register your own Hex.pm account, so you don’t need to have it now.

Creating a project

mix new exiban

👈 Your new project has a structure like this. Let’s see what are these files responsible for.

config/config.exs

config :exiban, iban_length: 28

You can use that setting in your code like this:

Application.get_env(:exiban, :iban_length)

Also any application that will use your package can change that configuration same as you can configure any third party packages that you use in your project.

mix.exs

def project do
[app: :exiban,
version: "0.0.1",
elixir: "~> 1.2",
build_embedded: Mix.env == :prod,
start_permanent: Mix.env == :prod,
description: description,
package: package,
deps: deps]
end

description and package can look like below. It’s a good place to describe your package:

defp description do
"""
Library for manipulating and validating IBAN account numbers.
"""
end
defp package do
[
files: ["lib", "mix.exs", "README*", "LICENSE*"],
maintainers: ["Krzysztof Kempiński"],
licenses: ["MIT"],
links: %{"GitHub" => "https://github.com/kkempin/exiban"}
]
end

Important part of mix.exs file is a definition of dependencies. In my case I want to add ex_doc that we will use in a minute to generate the documentation. deps function can be like this:

defp deps do
[
{:ex_doc, "~> 0.18", only: :dev}
]
end

lib/

At the beginning we have aexiban.ex file with a module:

defmodule Exiban do
@moduledoc """
Documentation for Exiban.
"""
@doc """
Hello world.
## Examples iex> Exiban.hello
:world
"""
def hello do
:world
end
end

Except of a documentation and examples that we’ll discuss later, that file is where everything starts, so most probably it will expose public API and will import other modules. That is only a hint because that how you wire up your package it’s totally up to you. Next most common step is to create modules in the namespace of Exiban . That means that you need to create new folder lib/exiban and put there file like parser.ex that will define a module Exiban.Parser etc.

Good to have files

Changelog.md
Most probably you will develop further your package. It’s good to document what kind of changes are introduced in each version (https://github.com/kkempin/exiban/blob/master/CHANGELOG.md)

Documentation

@moduledoc should provide useful information about a whole module whereas @doc for a function. Let’s look at the example below:

defmodule ExIban do
@moduledoc """
Validate and manipulate IBAN account number.
"""
@doc """
Returns country code extracted from IBAN.
## Examples iex> ExIban.country_code("GB82 WEST 1234 5698 7654 32")
"GB"
"""
def country_code(iban) do
{country_code, _, _, _, _} = parse(iban)
country_code
end
end

There are two important things to remember:

  1. we document only public functions with @doc — it makes no sense to document private functions
  2. if possible we should provide examples of usage. It should start with ## Examples followed by empty line. After that goes a fragment of code that should start with iex> . Next line shows an output. Keeping that format is important as we can use it for testing as we will see in a minute.

After we have written whole documentation, we can call

mix docs

to generate HTML format of the documentation in doc/ folder in our app. Now you can open index.html in your browser and see how good your documentation looks like :)

Next advantage is visible in an interactive shell for Elixir (iex -S mix) where with a command h you can see a documentation on a module (h Exiban) or a function (h Exiban.country_code).

In a section about publishing we will see how to upload that documentation on hex.pm so it is visible there.

Next cool feature of hex.pm is that it enables to download that documentation.

Testing

You can use three strategies to add tests to your package:

  • write unit tests in test/ folder
  • use a doctest feature
  • mix of these

In my package I use a doctest (https://hexdocs.pm/ex_unit/ExUnit.DocTest.html) feature. In a nutshell, it allows you to generate tests that are a part of a documentation of functions. Do you remember ## Examples section of @doc ? ExUnit (testing framework for Elixir) can use this piece of code (ExIban.country_code(“GB82 WEST 1234 5698 7654 32”)) and see if the output is the same as we provided in the documentation (GB). How cool is that?

Sometimes it’s not enough to cover your package with tests but in most cases that’s exactly what we need. So we have a fancy documentation and tests in one shot. And the only think you have to do is to put one additional line to each file with tests. For example test/exiban_test.exs :

defmodule ExibanTest do
use ExUnit.Case
doctest Exiban
end

Hint! Before you want to publish your package, run mix.test

Publishing to Hex.pm

First, let’s register on hex.pm:

mix hex.user register

You will be asked for a username, an email and a password.

Once the process is successfully finished you are ready to go.

Let’s build the project:

mix build

… and publish

mix hex.publish

If everything went ok you will be able to see your package on Hex.pm https://hex.pm/packages/NAME_OF_YOUR_PACKAGE and your documentation on https://hexdocs.pm/NAME_OF_YOUR_PACKAGE

Please remember that a versioning is exactly as you specified in mix.exs file in project function, so keep it consistent and change when you want to publish next version.


I hope that wasn’t difficult and I encourage you to publish your own packages as Elixir ecosystem is still young and needs more tooling.


Want to know first about new articles from that blog?

Subscribe to my newsletter now! — http://eepurl.com/cVPm_v


If you like this article and consider it useful for you, please support it with 👏.

kkempin’s dev blog

Dev and life blog.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store