View Source Modifiers tutorial

Every pathex path created with Pathex.path/2 can have modifier specified as a second argument. Modifier defines behaviour of the path in a way of structures it can match inside. For example, path created with :map modifier can only match maps inside them. Modifiers can be specified only in form of an atom, variables are not accepted.

When? How? & Why?

You should use modifiers when you need to specify type of inner structures to match or reduce amount of generated code by Pathex or improve performance of the path

Usage

Currently only three modifiers are available:

  • :json which matches lists and maps
  • :naive which matches lists, tuples, keywords and maps
  • :map which matches only maps

Default modifier for every path is :naive

Modifiers are specified as second argument in path/2 like

path :x / :y, :naive
path 0 / :x, :json

Naive modifier

This modifier matches lists, tuples, keyword and maps It generates matches for every structure like

For example:

path(:x, :naive) generates something like

case input do
  %{x: value} ->
     ...
  [{a, _} | _] = k when is_atom(a) ->
     case Keyword.fetch(k, :x) do
       ...
     end
end

Json modifier

This modifier specifies paths which macth lists (for integer keys only) and maps

Note: This modifier treats variables as map keys, this means that

iex> x = 1
iex> p = path x, :json
iex> :error = Pathex.view([1, 2, 3], p)
iex> {:ok, :x} = Pathex.view(%{1 => :x}, p)

But passed integers are exanded into list matching this makes it very efficient to view data from the structure

For example:

path 1 / :x, :json generates closure with

case input do
  [_, %{x: value} | _] ->
    {:ok, value}

  %{1 => %{x: value}} ->
    {:ok, value}

  _ ->
    :error
end

Which extracts maximum efficiency from BEAM's pattern-matching

Map modifier

This modifier matches only maps and therefore is the fastest modifier available

For example:

path 1 / :x / "y", :map will generate closure with

case input do
  %{1 => %{x: %{"y" => value}}} ->
    {:ok, value}

  _ ->
    :error
end

Annotations

Usually a key passed to path can match to one or more types. For example, key :x can be a key in Map like %{x: 1} and a key in Keyword like [x: 1]. To make key match only certain type it can be annotated to the exact type using this syntax path(:x :: :map). Available annotations are :map, :keyword, :list and :tuple.

For example:

first_in_tuple = path(1 :: :tuple)
:error   = Pathex.view([0, 1, 2, 3], first_in_tuple)
{:ok, 0} = Pathex.view({0, 1, 2, 3}, first_in_tuple)