Today I Learned

A Hashrocket project

188 posts about #elixir

Print the current stacktrace in Elixir

Stacktrace, backtrace, callstack, in Elixir its stacktrace and it’s available via Process.info/2 using the :current_stacktrace item:

Process.info(self(), :current_stacktrace)

And to print it:

IO.inspect(Process.info(self(), :current_stacktrace), label: "STACKTRACE")

I’m also learning that Process.info/2 takes a pid and an item as arguments. When you call Process.info/1 with just the pid you only get a subset of the info available, not everything.

The items available via Process.info/1 are listed in the erlang documentation here.

The additional items available via Process.info/2 are listed in the erlang documentation here.

You may note that backtrace is also an item that is available via Process.info but it contains more information than you are might need to figure out where you are in the code.

Flunk Your ExUnit Tests ❌

Today I got to use the flunk/1 function in an ExUnit test. I like everything about this function, from its name to its signature.

Here’s how we used it:

case result do
  "bad" ->
    flunk("Your result is bad, and you should feel bad.")

  "good" ->
    assert result_passes_other_tests(result)
end

It fit well into a helper function that should fail if my result ever comes back a certain way.

flunk docs

`mix phx.digest` creates the manifest

mix phx.digest creates production ready assets: hashed, zipped and compressed.

In production, when you call:

Endpoint.static_path('asset_name.css')

This will look for a file in the priv/static directory and return the path for that file. But what you want is the hashed version of that file, because modern browsers are greedy cachers and will you use the use to bust that cache.

The static_path function can return a path that represents the cached version, but it needs to read the manifest, which maps the file to it’s hashed, zipped and compressed versions.

mix phx.digest creates the manifest along with the hashed, zipped and compressed versions of all the files in the priv/static directory.

Update Map Syntax

There is a special syntax for updating a map in elixir.

thing = %{a: 1, b: 2, c: 3}
updated_thing = %{thing | b: 4}
# %{a: 1, b: 4, c: 3}

But be careful, it throws an error if you try to update a key that doesn’t exist!!

thing = %{a: 1, b: 2, c: 3}
# ** (KeyError) key :x not found in: %{a: 1, b: 2, c: 3}

Skip Pending Tests in ExUnit

In ExUnit you have the ability to tag a test with any atom:

@tag :awesome
test "my awesome test" do
end

@tag :terrible
test "my terrible test" do
end

And then you can exclude those tags at the command line so that your terrible test does not run:

mix test --exclude terrible

So you can make your own tag :pending and exclude those. If you don’t want to have to set the flag at the command line everytime, you can call ExUnit.configure. This is typically placed in the test/test_helper.exs file before ExUnit.start().

ExUnit.configure(exclude: :pending)
ExUnit.start()

Now your pending tests will not run.

That is how you can use custom tags to skip tests, but you can also just use the built in skip tag to skip tests.

@tag :skip
test "my terrible test" do
end

Timex `between?` is exclusive but can be inclusive

Timex.between? is a great function for determining if a time is in a specific time period, but it’s exclusive, so if you are testing for a time at the boundary the result will be negative.

iex> end_time = Timex.now()
iex> start_time = Timex.shift(end_time, days: -7)
iex> time = start_time
iex> Timex.between?(time, start_time, end_time)
false

Never fear, you can pass an inclusive option:

iex> Timex.between?(time, start_time, end_time, inclusive: true)
true

But you don’t have to be inclusive on both sides! Here, I pass :end so that I am only inclusive at the end of my time period.

iex> Timex.between?(time, start_time, end_time, inclusive: :end)
false

And of course I can be only inclusive at the beginning of the period if I prefer:

iex> Timex.between?(time, start_time, end_time, inclusive: :start)
true

Match across lines with Elixir Regex `dotall` (s)

Elixir Regex is PCRE compliant and Ruby Regex isn’t in at least one specific way. The m (multiline) flag behaves differently in Elixir and Ruby.

Without any modifiers, Regex does not match across new lines:

iex> Regex.scan( ~r/.*/, "a\nb")
[["a"], [""], ["b"], [""]]
iex> Regex.scan( ~r/.*/, "ab")
[["ab"], [""]]

With the m (multiline) modifier, Regex will match the beginning of each line when using the ^ char.

iex> Regex.scan( ~r/.*/m, "a\nb")
[["a"], [""], ["b"], [""]]
iex> Regex.scan( ~r/^.*/, "a\nb")
[["a"]]
iex> Regex.scan( ~r/^.*/m, "a\nb")
[["a"], ["b"]]

The s (dotall) modifier is the right way in Elixir to match across newlines.

iex> Regex.scan( ~r/.*/s, "a\nb")
[["a\nb"], [""]]
iex> Regex.scan( ~r/^.*/s, "a\nb")
[["a\nb"]]

In ruby, you can match across lines with the m (modifier) and the s is ignored.

irb> "a\nb".scan(/.*/)
=> ["a", "", "b", ""]
irb> "a\nb".scan(/.*/m)
=> ["a\nb", ""]
irb> "a\nb".scan(/.*/s)
=> ["a", "", "b", ""]

Read about the history of dotall here

Get _just one_ value from Ecto query

With the data structure you use in select’s expression argument you can specify what type of data structure the query will return for a row. I’ve used [] and %{} and %Something{} but you can also specify that each row is just one value without using a data structure at all.

Combine that with Repo.one to just return one row and you can just get the specific value you are looking for without any destructuring.

age = 
  User
  |> where(id: 42)
  |> select([u], u.age)
  |> Repo.one()

Elixir sigil for DateTime with timezone

Elixir have a new sigil_U to be relased in the upcomming 1.9.0 version.

~U[2019-05-18 21:25:06.098765Z]

This new sigil creates a UTC DateTime.

Now Elixir will have all these sigils for dates & times:

Date.new(2019, 5, 18)
=> {:ok, ~D[2019-05-18]}

Time.new(23, 55, 6, 98_765)
=> {:ok, ~T[23:55:06.098765]}

NaiveDateTime.new(2019, 5, 18, 23, 55, 6, 98_765)
=> {:ok, ~N[2019-05-18 23:55:06.098765]}

DateTime.from_iso8601("2019-05-18T23:55:06.098765+02:30")
=> {:ok, ~U[2019-05-18 21:25:06.098765Z], 9000}

Install the last Elixir version with asdf

If you are using asdf for managing Elixir version through asdf-elixir then you can install the master version. This way we can use new features yet to be release as 1.9. Let’s see how:

asdf install elixir master
asdf global elixir master

Then:

elixir --version
Erlang/OTP 21 [erts-10.3.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Elixir 1.9.0-dev (6ac1b99) (compiled with Erlang/OTP 20)

Get pids for each beam application in Elixir

In Elixir, it’s hard to determine what pids belong to what applications just by using Process.info

iex> pid(0,45,0) |> Process.info
[
  current_function: {:application_master, :main_loop, 2},
  initial_call: {:proc_lib, :init_p, 5},
  status: :waiting,
  message_queue_len: 0,
  links: [#PID<0.46.0>, #PID<0.43.0>],
  dictionary: [
    "$ancestors": [#PID<0.44.0>],
    "$initial_call": {:application_master, :init, 4}
  ],
  trap_exit: true,
  error_handler: :error_handler,
  priority: :normal,
  group_leader: #PID<0.45.0>,
  total_heap_size: 376,
  heap_size: 376,
  stack_size: 7,
  reductions: 49,
  garbage_collection: [
    max_heap_size: %{error_logger: true, kill: true, size: 0},
    min_bin_vheap_size: 46422,
    min_heap_size: 233,
    fullsweep_after: 65535,
    minor_gcs: 0
  ],
  suspending: []
]

With the above output, I can’t tell what application this is!

I can use the :running key of Erlang’s :application.info to get a map of applications to pids.

iex> :application.info[:running]
[
  logger: #PID<0.93.0>,
  iex: #PID<0.85.0>,
  elixir: #PID<0.79.0>,
  compiler: :undefined,
  stdlib: :undefined,
  kernel: #PID<0.45.0>
]

Oh ok, pid(0,45,0) is the Kernel application.

Test that an email was sent with correct params

assert_email_delivered_with is a function that checks if an email was delivered using Bamboo.

Sending an email is a side-effect in functional programming parlance. When testing a function where the email is sent several calls deep, you generally don’t get the email as a return value of that function.

When using Bamboo’s TestAdaptor in test mode, Bamboo captures the delivered email so that you can assert about it.

Lottery.notify_winner()
assert_email_delivered_with(subject: "You Won!!")

You can also assert on: to, cc, text_body, html_body, from, and bcc.

Happy Testing!

Hide an Elixir Module from Documentation

Recently I’ve noticed @moduledoc false sprinkled through some Elixir projects. What’s going on? To quote the docs:

Conveniently, Elixir allows developers to hide modules and functions from the documentation, by setting @doc false to hide a particular function, or @moduledoc false to hide the whole module. If a module is hidden, you may even document the functions in the module, but the module itself won’t be listed in the documentation…

Why would you see this in a project that doesn’t autogenerate docs? Possibly to satisfy a linter like Credo. In a codebase with public APIs, I think this kind of explicit statement is a good practice.

Writing Elixir Docs

Formatting the email address fields with Bamboo

When you create an email with Bamboo and deliver it:

 email = new_email(
      to: "chris@example.com",
      from: "vitamin.bot@example.com",
      subject: "Reminder",
      text_body: "Take your vitamins"
    )
 |> Mailer.deliver_now()

The to field will not be what you expect it to be:

email.to
# {nil, "chris@example.com"}

This is the normalized format for a to field. The first element in the tuple is the name of the recipient.

Bamboo allows you to format this field yourself with protocols.

defimpl Bamboo.Formatter, for: Person do
  def format_email_address(person, _opts) do
    {person.nickname, person.email}
  end
end

And now if I send an email with Person in the to field:

person = %Person{
    nickname: "shorty", 
  email: "chris@example.com"
}

email = new_email(
      to: person,
      from: "vitamin.bot@example.com",
      subject: "Reminder",
      text_body: "Take your vitamins"
    )
|> Mailer.deliver_now()

Then the to field gets formatted with our protocol.

email.to
# {"shorty", "chris@example.com"}

Read more about the Bamboo Formatter here.

Fuzzy translation key merging with Gettext

Gettext is a great tool for i18n in elixir. It provides a mix task for extracting translation keys from your code. The translation keys (or message ids) are natural language and look like this:

gettext("Hi, Welcome to Tilex!")

After running mix gettext.extract && mix gettext.merge, an already translated Italian locale file would look like:

msgid "Hi, Welcome to Tilex!"
msgstr "Italian version of Welcome!"

There’s a chance that the natural language key (which also serves as the default string) will change.

If it changes just a little bit then the Italian locale file will look like:

#, fuzzy
msgid "Hi, Welcome to Tilex!!"
msgstr "Italian version of Welcome!"

It gets marked as #, fuzzy, and the new msgid replaced the old msgid.

Gettext determines how big of a change will constitute a fuzzy match with String.jaro_distance.

iex> String.jaro_distance("something", "nothing")
0.8412698412698413
iex> String.jaro_distance("peanuts", "bandersnatch")
0.576984126984127

The higher the number the closer the match. fuzzy_threshold is the configuration that determines whether a msgid is fuzzy or not and the default for fuzzy_threshold is 0.8, set here.

Weighted Shuffle in Elixir

Shuffling a list is easy, but what if you want to perform a weighted shuffle? That is, what if some elements in a list had a greater chance of being selected, or higher in the list, than others?

Given these colors and these weights:

weighted_colors = [{1, "orange"}, {3, "green"}, {5, "red"}]

I can create a list that is mostly represents each item the number of times of it’s weight by utilizing List.duplicate:

weighted_colors
|> Enum.map(fn ({weight, color}) -> 
  List.duplicate(color, weight)
end)
|> Enum.flatten
# ["orange", "green", "green", "green", "red", "red", "red", "red", "red"]

Then shuffle it:

|> Enum.shuffle
# ["red", "red", "orange", "red", "green", "green", "red", "green", "red"]

And then use Enum.uniq attribute of preserving the order in which it encounters each unique element from left to right.

|> Enum.uniq
# ["red", "orange", "green"]

Run this 100 times over the same weighted list and the most outcome that you would experience most often is:

# ["red", "green", "orange"]

Legible milliseconds in Elixir using Erlang timer

In Elixir, we often need to set milliseconds. This is especially common when working with GenServer, Task.Supervisor, Agent and others.

While we could write our milliseconds directly:

10800000

or perhaps

10_800_000

Did you know that was 3 hours just by glancing at it? Sure the math is fairly easy, but why make us think? Erlang’s timer to the rescue!

iex()> :timer.hours(3)
10800000

Well that makes our 3 hours pretty legible if you ask me.

We also have minutes and seconds:

iex()> :timer.minutes(11)
660000
iex()> :timer.seconds(455)
455000

Thanks Erlang!

Find duplicate routes in Elixir Phoenix

If you have duplicated routes in your route file like this:

scope "/api", MyAppWeb.Api, as: :api do
  pipe_through [:this]
  
  resources "/users", UserController, except: [:new, :edit]
  scope 
end

scope "/api", MyAppWeb.Api, as: :api do
  pipe_through [:that]

  resources "/users", UserController, except: [:new, :edit]
end

Then you’ll get a warning like this:

warning: this clause cannot match because a previous clause at line 2 always matches
  lib/idea_web/router.ex:2

The warning doesn’t really let you know which routes are duplicated, but it’s really ease to find the duplicated routes by utilizing the uniq command.

mix phx.routes | sort | uniq -d

The -d flag for uniq is duplicates only. -d only considers similar lines in consecutive order as duplicates, so you need to run it through sort first.

The output looks like this:

api_user_path  DELETE  /api/users/:id                   MyAppWeb.Api.UserController :delete
api_user_path  GET     /api/users                       MyAppWeb.Api.UserController :index
api_user_path  GET     /api/users/:id                   MyAppWeb.Api.UserController :show
api_user_path  PATCH   /api/users/:id                   MyAppWeb.Api.UserController :update
api_user_path  POST    /api/users                       MyAppWeb.Api.UserController :create

And those are your duplicate routes!

Named bindings in Ecto (vs positional bindings)

Positional bindings in Ecto are meant to confuse when buildings large queries across several different functions.

query = Thing
|> join(:inner, [t], x in X, on: t.x_id = x.id)
|> join(:inner, [_, x], y in Y, on: x.y_id = y.id)

Using that query in another function might look like this:

query
|> where([_, x, _], x.type == "Articulated")

But what if the positions change? How am I supposed to know which positions are which when I’m adding to this query out of context?

Named bindings help tremendously here (note the :as option):

query = Thing
|> join(:inner, [t], x in X, as: :x, on: t.x_id = x.id)
|> join(:inner, [_, x], y in Y, as: :y, on: x.y_id = y.id)

Now I can refer to these things without knowing the position. If the position changes it’s all good the additive where statement does not have to change:

query
|> where([y: y, x: x], x.type == "Articulated", y.feel == "Good")

How to actually _load_ the resource with Guardian

Guardian, like all auth libraries in all languages, is tough to wrap my head around.

I know there is a plug in the pipeline called plug Guardian.Plug.LoadResource. I know there is a function called Guardian.Plug.current_resource(conn) that takes the conn and returns that returns the resource placed in the conn by the Guardian.Plug.LoadResource plug.

What I don’t know is how the LoadResource plug knows what resource to get.

In Guardian, you configure the pipeline with:

use Guardian.Plug.Pipeline, otp_app: :my_app,
                              module: GuardianImpl,
                              error_handler: ErrorHandler

The GuardianImpl is a module that uses the Guardian behaviour.

The Guardian behaviour has a callback resource_from_claims that might be implemented like this:

def resource_from_claims(claims) do
  {:ok, Repo.get(User, claims["sub"])}
end

So when you need to modify how you load the resource, you should look to see how the resource_from_claims callback is implemented.

Read more here.

Updating the ExUnit test context with setup

When using ExUnit the second argument to the test macro is context.

test "1 + 1 = value", context do
  assert 1 + 1 == 2
end

This context can provide setup values so that you can share setup across tests.

Use the setup macro to update the context. The keyword list you return from the setup function will be merged into the map of the context.

setup do
  [result: 2]  # this gets merged into the context
end

setup do
  # create some database records
  :ok # this does not get merged into the context
end

Also in the setup macro you can have access to the context, allowing you to potentially change the context based on the needs of the test.

setup context do
  %{result: r} = context
    [result: r + 1]
end

test "1 + 1 = value", %{result: value} do
  assert 1 + 1 == value
end

Read more about ExUnit setup here.

Elixir ExDoc has version dropdown

ExDoc released a new version that allow developers to show a version dropdown on their documentation.

Here’s how I added to my library:

Open the mix.exs file and add javascript_config_path to the docs option on your project function.

def project do
  [
    ...
    docs: [
      main: "readme",
      extras: ~w(README.md),
      javascript_config_path: "../.doc-versions.js"
    ],
    ...
end

And on my Makefile I have this:

docs: ## Generate documentation.
docs: setup
    echo "var versionNodes = [" > .doc-versions.js
    app=`mix run -e 'IO.puts(Mix.Project.config()[:app])'`; \
    for v in $$(git tag | tail -r); do echo "{version: \"$$v\", url: \"https://hexdocs.pm/$$app/$$v/\"}," >> .doc-versions.js; done
    echo "]" >> .doc-versions.js
    mix docs

So if I run make docs this will generate or update a file .doc-versions.js from what I have on my git tag

And here is how it looks like:

image

Here’s the ExDoc changelog.

Elixir Pattern Matching with Variables

Let’s say you have a variable that you want to pattern match.

By default Elixir won’t use the variable’s value to do the pattern matching and it will do a regular assignment, overriding the original variable’s value:

iex(1)> year = 2020
2020

iex(2)> car = %{year: 2019}
%{year: 2019}

iex(3)> %{year: year} = car
%{year: 2019}

iex(4)> year
2019

Elixir has the pin opertator ^ that does exactly what we need. So in our example we can use the pin operator and if it doesn’t match you get an error:

iex(1)> year = 2020
2020

iex(2)> car = %{year: 2019}
%{year: 2019}

iex(3)> %{year: ^year} = car
** (MatchError) no match of right hand side value: %{year: 2019}

Pattern matching structs (why order is important)

When pattern matching structs with maps, many people don’t consider the consequences of order.

Say we have a user:

defmodule User do; defstruct [:name, :age] end

This will match just fine:

iex()> %{name: nil, age: nil} = %User{}
%User{age: nil, name: nil}

While the reverse will not:

iex()> %User{} = %{name: nil, age: nil}
Bug Bug ..!!** (MatchError) no match of right hand side value: %{age: nil, name: nil}

If you care to know why:

When pattern matching maps, the right side value must contain all the keys. In our example above, it appears they do:

iex()> inspect(%User{})
"%User{age: nil, name: nil}"

But looks can be deceiving:

iex()> inspect(%User{}, structs: false)
"%{__struct__: User, age: nil, name: nil}"

With our newfound knowledge, lets try again:

iex()> %User{} = %{name: nil, age: nil, __struct__: User}
%User{age: nil, name: nil}

🎉

How to assert Elixir doctest raises an error

Today I learned how to assert an Elixir doctest raises an error. Check this out:

defmodule MyModule do
  @doc """
  This function raises ArgumentError.

  ## Examples

      iex> MyModule.my_func()
      ** (ArgumentError) something is wrong
  """
  def my_func() do
    raise(ArgumentError, "something is really wrong")
  end
end

The previous doctest will fail with this message:

  1) doctest MyModule.my_func/0 (1) (MyModuleTest)
     test/my_module_test.exs:3
     Doctest failed: wrong message for ArgumentError
     expected:
       "something is wrong"
     actual:
       "something is really wrong"
     code: MyModule.my_func()
     stacktrace:
       lib/my_module.ex:10: MyModule (module)

Compute Intermediate Values In A With Construct

The expressions you use in a with construct do not have to contain the <- syntax. You can pattern match and bind values along the way as well.

with %{id: id} <- get_user(),
     url = "/api/#{id}/blogs",
     %{status_code: 200, body: body} <- HTTPoison.get(url),
     {:ok, decoded_body} <- Poison.decode(body) do
  {:ok, decoded_body}
end

In the above (sorta contrived) example we were able to construct a URL in the middle of the series of expressions.

The values we compute inline will be closed into the with construct, so they won’t leak.

See the with docs for more details.

Check List Membership In Elixir

You can use the in operator to check if something appears in a list. This is a handy way of checking if a variable is one of a few acceptable or expected values.

For instance, a common DateTime comparison pattern relies on this to check if a DateTime is >= or <= to another DateTime.

{:ok, datetime} = DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Etc/UTC")

DateTime.compare(datetime, DateTime.utc_now()) in [:lt, :eq]

Alternatively, you can check that something does not have membership in a list by also including the not operator.

DateTime.compare(datetime, DateTime.utc_now()) not in [:lt, :eq]

Using When Clauses In A With Construct In Elixir

Because Elixir’s with construct supports the full power of the language’s pattern matching, we can use when clauses to further narrow down our matches.

For instance, if we want to match against the response to an API request, but only for response status codes in the 2xx range, we can do something like the following:

with %{status_code: code, body: body}
       when code >= 200 && code < 300 <- HTTPoison.get!(url),
     {:ok, decoded_body} <- Poison.decode(body) do
  {:ok, decoded_body}
end

See the docs for with for more details.

Match On A Map In A With Construct In Elixir

Many usage example of the with construct show a series of matches on a tuple.

with {:ok, width} <- Map.fetch(opts, :width),
     {:ok, height} <- Map.fetch(opts, :height) do
  {:ok, width * height}
end

You can match on more than just tuples though. Here is how you might match on a map.

with %{status_code: 200, body: body} <- HTTPoison.get!(url),
     {:ok, decoded_body} <- Poison.decode(body) do
  {:ok, decoded_body}
end

In fact, you have the full power of Elixir’s pattern matching available to you in your series of matches for a with construct.

Comparing DateTime Structs In Elixir

Remember, comparisons in Elixir using ==/2, >/2, </2 and friends are structural and based on the DateTime struct fields. For proper comparison between datetimes, use the compare/2 function.

As the DateTime docs say, you’ll want to use compare/2 in order to accurately compare two DateTime structs.

{:ok, older} = DateTime.from_naive(~N[2016-05-24 13:26:08.003], "Etc/UTC")
{:ok, newer} = DateTime.from_naive(~N[2017-11-24 13:26:08.003], "Etc/UTC")

DateTime.compare(older, newer)
#=> :lt

DateTime.compare(newer, older)
#=> :gt

DateTime.compare(newer, newer)
#=> :eq

When using compare/2, you’ll get one of :lt, :gt, or :eq as a result, meaning less than, greater than, or equal respectively.

Build a CLI with Elixir

Elixir Mix ships with built-in CLI support, called escript. From the docs:

An escript is an executable that can be invoked from the command line. An escript can run on any machine that has Erlang/OTP installed and by default does not require Elixir to be installed, as Elixir is embedded as part of the escript.

Yesterday I built a CLI that reads an input file, does some calculations, and prints a result. For me, CLI’s are often the mark of a fully-realized project, and I appreciate how the Elixir community treats CLI’s as a first-class idea.

In lieu of a longer explanation, here are the docs:

mix escript.build

Viewing your test coverage in Elixir

Curious about test coverage in your Elixir application? Mix.Tasks.Test comes with a handy --cover option.

$ mix test --cover
...
Generating cover results ...

Percentage | Module
-----------|--------------------------
   ...
   100.00% | TilexWeb.PixelController
    75.00% | Mix.Tasks.Deploy
    30.00% | TilexWeb
   ...
-----------|--------------------------
    68.33% | Total

By default it uses a wrapper around OTPs built in cover, however that’s configurable. If you wanted to use something like excoveralls you could:

def project() do
  [
    ...
    test_coverage: [tool: ExCoveralls]
    ...
  ]
end

Other niceties, like color based thresholds, can be found in the docs

Pattern match against Dates in Elixir using struct

A recent TIL by my coworker Ryan reminded me of an alternative to pattern matching on dates (and other structs) by matching on their Name. Using __struct__ to grab the name allows us to use a guard and only match on struct types we want:

def foo(%{__struct__: struct_name} = datetime)
  when struct_name in [Date, DateTime] do
    Timex.to_naive_datetime(datetime) |> foo
end

def foo(%NaiveDateTime{} = datetime) do
  IO.inspect({"My Naive Datetime", datetime})
end

Pattern matching with `Kernel.match`

Pattern matching is powerful, but when iterating over a list with an Enum function you must allow all variants of the list to be processed. So this fails:

sample = [{1, "A"}, {2, "B"}]
 > Enum.filter(sample, fn ({_, "B"}) -> true end)
** (FunctionClauseError) no function clause matching in :erl_eval."-inside-an-interpreted-fun-"/1

    The following arguments were given to :erl_eval."-inside-an-interpreted-fun-"/1:

        # 1
        {1, "A"}

    (stdlib) :erl_eval."-inside-an-interpreted-fun-"/1
    (stdlib) erl_eval.erl:826: :erl_eval.eval_fun/6
    (elixir) lib/enum.ex:2898: Enum.filter_list/2

Instead of using pattern matching here we can just use an anonymous function that takes all args and makes a comparison.

sample = [{1, "A"}, {2, "B"}]
Enum.filter(sample, fn ({_, letter}) -> letter == "B" end)
# [{2, "B"}]

But the cool way to do it is with Kernel.match?. Which according to the docs is:

A convenience macro that checks if the right side (an expression) matches the left side (a pattern).

What that looks like:

sample = [{1, "A"}, {2, "B"}]
Enum.filter(sample, &match?({_, "B"}, &1))
# [{2, "B"}]

H/T Taylor Mock

Pattern matching against Dates in Elixir

Dates in Elixir aren’t native values, so there aren’t any guard clause functions available for use with date/datetime. You can, however, use pattern matching:

def foo(%Date{} = date) do
  Timex.to_naive_datetime(date) |> foo
end

def foo(%DateTime{} = datetime) do
  Timex.to_naive_datetime(datetime) |> foo
end

def foo(%NaiveDateTime{} = datetime) do
  IO.inspect({"My Naive Datetime", datetime})
end

Serialize an Elixir pid

I was wondering how to serialize/deserialize a pid for some tricks with Ecto Sandbox and I found out some nice code on phoenix_ecto code. Here it goes my version:

defmodule MyApp.Serializer do
  @spec serialize(term) :: binary
  def serialize(term) do
    term
    |> :erlang.term_to_binary()
    |> Base.url_encode64()
  end

  @spec deserialize(binary) :: term
  def deserialize(str) when is_binary(str) do
    str
    |> Base.url_decode64!()
    |> :erlang.binary_to_term()
  end
end

And the test:

defmodule MyApp.SerializerTest do
  use ExUnit.Case, async: true

  alias MyApp.Serializer

  describe "serialize/1" do
    test "serializes a pid" do
      pid = self()
      assert pid |> Serializer.serialize() |> is_binary()
    end

    test "serializes a map" do
      map = %{foo: :bar}
      assert map |> Serializer.serialize() |> is_binary()
    end
  end

  describe "serialize/1, deserialize/1" do
    test "serializes and deserializes a pid" do
      pid = self()
      assert pid |> Serializer.serialize() |> Serializer.deserialize() == pid
    end

    test "serializes and deserializes a map" do
      map = %{foo: :bar}
      assert map |> Serializer.serialize() |> Serializer.deserialize() == map
    end
  end
end

Send an event to a Channel from outside Phoenix

So this one was non-obvious to me.

In the following example, any module on any process can call TopicChannel.send_to_channel/1and that will be handled by the handle_info call below and sent to the socket.

defmodule MyAppWeb.TopicChannel do
  use Phoenix.Channel

  def send_to_channel(data) do
    Phoenix.PubSub.broadcast(
      MyApp.PubSub, 
      "topic:subtopic",
      %{type: "action", payload: %{data: data}
    )
  end

  def join("topic:subtopic", message, socket) do
    {:ok, socket}
  end
  
  def handle_info(%{type: "action"}=info, socket) do
    push socket, "action", info

    {:noreply, socket}
  end
end

Parameter filtering in Elixir Phoenix logs

Sometimes you want to filter out parameters that are being logged (think GDPR compliance). Enter Phoenix’s handy config filter_parameters :

config :phoenix, :filter_parameters, ["password", "birthday"]

Or if you want to be extra safe, you can filter all parameters and only whitelist ones you want to see. For example: id and order:

config :phoenix, :filter_parameters, {:keep, ["id", "order"]}

Enable gzip for all phoenix responses

Enabling gzip for static assets in phoenix couldn’t be simpler. In lib/myapp_web/endpoint.ex change gzip from false to true:

 plug(Plug.Static, at: "/", from: :tilex, gzip: true, only: ~w(assets ...))

But why stop there? We can compress our dynamic document bodies just as easily. In config/prod.exs, add compress: true to the http config of the endpoint.

config :my_app, MyAppWeb.Endpoint,
  http: [port: {:system, "PORT"}, compress: true]

Client Connection Vars with Ecto

Postgres has dozens of connection variables it will take, a couple of my favorite ones are statement_timeout and application_name.

Ecto takes a parameters connection option, which is a keyword list of connection parameters.

# dev.exs

...

# Configure your database
config :myapp, Myapp.Repo,
  adapter: Ecto.Adapters.Postgres,
  database: "myapp_dev",
  socket_dir: "/var/run/postgresql",
  parameters: [application_name: "My App Development", statement_timeout: "5000"],
  pool_size: 10



Example of statement_timeout being respected in Ecto:

Ecto.Adapters.SQL.query!(Myapp.Repo, "select pg_sleep(86400)")

** (Postgrex.Error) ERROR 57014 (query_canceled): canceling statement due to statement timeout
    (ecto) lib/ecto/adapters/sql.ex:200: Ecto.Adapters.SQL.query!/5


Client Connection Variables references: https://www.postgresql.org/docs/current/static/runtime-config-client.html

Use a unix socket with Ecto

Ecto allows the use of a unix socket to connect to postgres, instead of TCP. In order to use a unix socket in a exs file, you should remove the hostname list item, and provide the socket_dir list item.

# dev.exs

...

# Configure your database
config :myapp, Myapp.Repo,
  adapter: Ecto.Adapters.Postgres,
  database: "myapp_dev",
  socket_dir: "/var/run/postgresql",
  pool_size: 10

Elixir String Manipulation

To get the list of string that compose a longer string, use String.codepoints/1

iex> cdp =  String.codepoints("abcdefg")
["a", "b", "c", "d", "e", "f", "g"]
iex> Enum.at(cdp, 0)
"a"

To get the list of codepoints that represent each letter in the string, use String.to_charlist/1

iex> chr = String.to_charlist("abcdefg")
'abcdefg'
iex> Enum.at(chr, 0)
97