Codementor Events

Elixir is pretty sweet — Part 1

Published Dec 11, 2017
Elixir is pretty sweet — Part 1

I’ve been working with Elixir for close to two years now and continue to find little sweet treats within the language.

Here’s part one of a multi-part series where I’ll be writing about five sweet things I like. Enjoy!

#5 - Find the difference between two strings in the form of an edit script

For those of you who are familiar with Eugene W. Myers and his difference algorithm, you’ll be happy to know that this is already built into Elixir’s String module.

Example:

iex> string1 = "Elixir is pretty awesome, don't you think?"
iex> string2 = "Elixir is neat, don't you think?"
iex> String.myers_difference(string1, string2)
[eq: "Elixir is ", del: "pr", ins: "n", eq: "e", del: "tty ", eq: "a",
 del: "wesome", ins: "t", eq: ", don't you think?"]

#4 - Print out messages in a process’s mailbox

Occasionally, I find that I need to investigate messages that are being sent to a process. The easiest way to do this is to use the built-in observer tool that comes with Erlang. This can be done by running :observer.start() in the Interactive Elixir console.

However, if you’d like to do this through a remote console, just use :erlang.process_info/2.

Example:

iex(1)> shell_process = self

iex(2)> spawn(fn ->
...(2)>   send(shell_process, :hello_world)
...(2)>   :erlang.process_info(shell_process, :messages) |> IO.inspect
...(2)> end)

{:messages, [:hello_world]}

#3 - Get nested values inside a map

Example:

iex> users = %{"john" => %{age: 27}, "meg" => %{age: 23}}
iex> get_in(users, ["john", :age])
27

What I like most about this is that we can easily use it in conjunction with a list of maps by invoking a function inside our list of keys.

Example:

iex> users = [%{name: "john", age: 27}, %{name: "meg", age: 23}]
iex> all = fn :get, data, next -> Enum.map(data, next) end
iex> get_in(users, [all, :age])
[27, 23]

#2 - Enforcing all keys in a struct

You may have already heard of the @enforce_keys module attribute when defining a struct. Enforcing keys allows you to ensure that specific keys are always present within your struct. Who doesn't like easy validation?

Example:

iex> defmodule Car do
...>   @enforce_keys [:make]
...>   defstruct [:model, :make]
...> end
iex> %Car{}
** (ArgumentError) the following keys must also be given when building struct Car: [:make]
    expanding struct: Car.__struct__/1

A quick way to ensure that all keys are enforced is to define all of the struct's keys in @enforce_keys. Then, define your struct using the @enforce_keys attribute, like so:

iex> defmodule Car do
...>   @enforce_keys [:model, :make]
...>   defstruct @enforce_keys
...> end
iex> %Car{}
** (ArgumentError) the following keys must also be given when building struct Car: [:model, :make]
    expanding struct: Car.__struct__/1

#1 - Running only specific tests

Coming from a JavaScript background, I was a heavy user of MochaJS. One of the features of Mocha I used the most was the ability to run a subset of tests.

Luckily, Elixir has similar functionality built in by allowing you to tag tests.

Example:

defmodule ApplicationTests do

    @tag :some_tag
    test "test number 1" do
        ...
    end
    
    @tag :another_tag
    test "test number 2" do
        ...
    end
end

To only run “test number one:”

mix test --only some_tag

Alternatively, to run all tests except for tests marked with a particular tag, run:

mix test --exclude another_tag

Conclusion

I could continue writing about Elixir's sweetness all day, so I'll be sure to write about more cool things that I find. Stay tuned!

Discover and read more posts from Sina Karimi
get started