Using Gleam Packages in Your Elixir Project

Posted on .

Using Gleam packages in an Elixir project is not as simple as adding {:lib, "1.2.3"} to your mix.exs, but it's pretty close. There are two issues preventing this simple usage:

  1. Elixir's Mix doesn't know how to compile a Gleam package, which does not have any build setup. It's literally a bunch of Erlang files in a folder. I'm not sure if there is an issue about this.
  2. Gleam writes dev dependencies into the built app.src file, which causes the app to crash on startup, as the dev dependencies aren't there. Gleam issue #3035 deals with this matter.

To circumvent these issues, add your Gleam dependency to mix.exs like this:

{:scriptorium, "~> 2.0.0", app: false, manager: :rebar3}

The first option prevents reading the app file of the dependency entirely. It seems to work for libraries, but I'm not sure of its effects on Gleam projects with startable apps. I believe they won't be automatically started at least. Most Gleam projects at this point are libraries or are explicitly started, so this is likely not an issue for you.

The second tells Mix to use Rebar to build the package. This seems to work even for a plain "Erlang files in a folder" type package that Gleam generates.

You can read more about these options in Mix's documentation.

Once you've gotten your dependency installed, remember that the calling syntax is different from a typical Elixir module. Gleam modules are named according to their path with @ as a separator. For example, to call parse_header from scriptorium/parser/common, use the following:

:scriptorium@parser@common.parse_header("...")

Also note that Gleam custom types map to tuples in Elixir, and more specifically records. In fact you can define a record on the Elixir side to match your Gleam types and operate on them. For example, here's a record from one of my early mixed Elixir/Gleam projects, GeoTherminator:

defmodule GeoTherminator.PumpAPI.Device do
  require Record

  Record.defrecord(:record, :device, [
    :id,
    :device_id,
    :is_online,
    :last_online,
    :created_when,
    :mac_address,
    :name,
    :model,
    :retailer_access
  ])

  # Create idiomatic Elixir type as an alias for Gleam side type
  @type t :: :pump_api@device.device()
end

Now we can use GeoTherminator.PumpAPI.Device.t() in typespecs, and calls like GeoTherminator.PumpAPI.Device.record(my_device, :id) and GeoTherminator.PumpAPI.Device.record(my_device, name: "My Device") to operate on the type in Elixir land.

Thank You

Posted on .

I first came upon Elixir in 2013 (wow, it's been 8 years?). I was looking at Erlang and a friend of mine said that there's this new language being built on the same VM, you should look at it. I gave it a whirl and the rest is history, as they say. I've written it on and off, sadly never professionally, resulting in lots of stuff, some even in production. Elixir gave me a new joy in programming.

None of this would be possible without the hard work of people I've never seen. People who have received nothing from me but have decided to give me the tools to work with anyway. To help me avoid mistakes. To ease my experience. To expand my view of programming beyond what I could have thought of myself.

For this I want to thank you, as it's the least I can do.

Simple Configuration Setup for Elixir Projects (v1.11+)

Posted on .

I've written about Elixir configuration in an earlier post, describing the differences in the configuration styles. If you don't know how Elixir configuration works, I suggest reading it also. In this post, I will demonstrate a system for configuring an Elixir project using the config/runtime.exs system introduced in Elixir 1.11. This system is how I configure my projects, so feel free take it as inspiration, but it's not a law that you have to follow.

FBU: My First Build Tool™

Posted on .

EDIT 2017-04-04: I have since renamed the project to MBU: Mix Build Utilities and published it on Hex.pm: hex.pm/packages/mbu. I have edited the links and code examples in this post to reflect that.


tl;dr I wrote my own build tool using Elixir's Mix: Nicd/mbu.

It's no secret that I somewhat dislike the state of modern web development. JavaScript is its own terrible world, but one of the sad parts of it is the ecosystem and tooling around it. There's a lot of innovation and hard work going on in very many fragmented projects, resulting in reimplementations of already solved problems and a ton of half working, alpha quality, 0.x versioned packages with unknown support status. With these packages, you start your project by building an elaborate house of cards that is the build system. And you dread the day when you need to touch it again.

Announcing Code::Stats

Posted on .

This is a project that I've been working on for a month or so on my free time (of which there really isn't too much). I started it on my company's 12 hour hackfest, where I didn't get anything worth showing done (it was all backend stuff), but now it's ready to be published. *drumroll* So, it's time for the reveal:

Mebe and the Remote Shell

Posted on .

What better way to spend a slow weekend than by writing another blog engine? Plenty, actually, but that's what I did anyway. The result of this work: Mebe! This blog is now powered by a wonderful mix of Elixir and Phoenix. It has all the features that Laine had, with the addition of an actually working Disqus comment system. It's also search engine indexable, which I thought I didn't care about, until I didn't have it anymore. Not that I'm aiming for tons of visitors, but writing about some tech problem I have fixed is kind of pointless if no one can find the post by googling for it.

Nurina – The Elixir URI parser

Posted on .

I had some free time this weekend, so I decided to pick up on an old piece of code I wrote back when I started learning Elixir. It's a URI parser I called Nurina (the word nurina is Finnish and means grumbling or complaining -- it sounded funny and it contains the word URI). It's not really a well put together piece of code but more of a learning excercise. I also decided to avoid using regular expressions entirely and instead used pattern matching to parse the whole URI -- an additional challenge.