View Source Pathex (Pathex v2.2.0)

This module contains functions and macros to be used with Pathex and i

To use Pathex just insert to your context. You can import Pathex in module body or even in function body.

require Pathex
import Pathex, only: [path: 1, path: 2, "~>": 2, ...]

Or you can use use

defmodule MyModule do

  # `default_mod` option is optional
  # when no mod is specified, `:naive` is selected
  use Pathex, default_mod: :json

  ...
end

This will import all operatiors and path macro

Any macro here belongs to one of three categories:

  1. Macro which creates path closure (only path/2)
  2. Macro which uses path closure as path (over/3, set/3, view/2, ...)
  3. Macro which creates path composition (~>/2, |||/2, ...)

Link to this section Summary

Types

Function which is passed to path-closure as second element in args tuple

More about modifiers

This depends on the modifier

Value returned by non-bang path call

t()

Also known as path-closure

Functions

Creates composition of two paths which has some inspiration from logical and.
This means that a &&& b path-closure tries to apply a and only if it returns {:ok, something}, tries apply b and if b returns exactly the same as a does, the a &&& b returns {:ok, something}

Easy and convenient way to add pathex to your module.

This macro creates compositions of paths which work along with each other

Applies func under path in struct and returns result of this func. Raises if path is not found.

Applies func under path in struct and returns result of this func.

The same as Pathex.~>/2 for those who do not like operators

Deletes value under path in struct or raises if value is not found.

Deletes value under path in struct.

Gets the value under path in struct or returns default value if not found.

Applies func under path of struct.

Applies func under path of struct.

Sets the value under path in struct.

Sets the value under path in struct.

Gets the value under path in struct or returns default when path is not present.

Inspect the given path-closure and returns string which corresponds to given path-closure

Applies the func to the item under path in struct and returns modified structure. Works like Map.update!/3.

Applies func to the item under the path in struct and returns modified structure. Works like Map.update!/3 but doesn't raise.

Creates path from quoted ast. Paths look like unix fs path and consist of elements separated from each other with /. See

Gets value under path in struct and then deletes it. Note that current implementation of this function performs double lookup.

Macro which gets value in the structure and deletes it. Note that current implementation of this function performs double lookup.

Sets the value under path in struct. Think of it like Map.put/3.

Sets value under path in structure. Think of it like Map.put/3.

Gets the value under path in struct. Raises if path not found.

Gets the value under path in struct.

Creates composition of two paths which has some inspiration from logical or.
This means that a ||| b path-closure tries to apply a and only if it returns :error, tries apply b

Creates composition of two paths similar to concatenating them together.
This means that a ~> b path-closure applies a and only if it returns {:ok, something} it applies b to something

Link to this section Types

Link to this type

force_update_args(input, output)

View Source
@type force_update_args(input, output) :: {input, inner_func(output), any()}
@type inner_func(output) :: (any() -> result(output))

Function which is passed to path-closure as second element in args tuple

@type inspect_args() :: any()
@type mod() :: :map | :json | :naive

More about modifiers

Link to this type

pathex_compatible_structure()

View Source
@type pathex_compatible_structure() :: map() | list() | Keyword.t() | tuple()

This depends on the modifier

@type result(inner) :: {:ok, inner} | :error | :delete_me

Value returned by non-bang path call

@type t() :: t(pathex_compatible_structure(), any())

Also known as path-closure

@type t(input, output) ::
  (op_name(),
   force_update_args(input, output)
   | update_args(input, output)
   | inspect_args() ->
     result(output | input))

Also known as path-closure

Link to this type

update_args(input, output)

View Source
@type update_args(input, output) :: {input, inner_func(output)}

Link to this section Functions

Creates composition of two paths which has some inspiration from logical and.
This means that a &&& b path-closure tries to apply a and only if it returns {:ok, something}, tries apply b and if b returns exactly the same as a does, the a &&& b returns {:ok, something}

Example:

iex> p1 = path :x / :y
iex> p2 = path :a / :b
iex> ap = p1 &&& p2
iex> {:ok, 1} = view %{x: %{y: 1}, a: [b: 1]}, ap
iex> :error = view %{x: %{y: 1}, a: [b: 2]}, ap
iex> {:ok, %{x: %{y: 2}, a: [b: 2]}} = set %{x: %{y: 1}, a: [b: 1]}, ap, 2
iex> {:ok, %{x: %{y: 2}, a: %{b: 2}}} = force_set %{}, ap, 2
Link to this macro

__using__(opts)

View Source (macro)

Easy and convenient way to add pathex to your module.

You can specify modifier

use Pathex, default_mod: :json

Or just use it with default :naive modifier

use Pathex
Link to this macro

alongside(list)

View Source (macro)

This macro creates compositions of paths which work along with each other

Think of alongside([path1, path2, path3]) as path1 &&& path2 &&& path3 The only difference is that for viewing alongside returns list of variables

Example:

iex> pa = alongside [path(:x), path(:y)]
iex> {:ok, [1, 2]} = view(%{x: 1, y: 2}, pa)
iex> {:ok, %{x: 3, y: 3}} = set(%{x: 1, y: 2}, pa, 3)
iex> :error = set(%{x: 1}, pa, 3)
iex> {:ok, %{x: 1, y: 1}} = force_set(%{}, pa, 1)
Link to this macro

at!(struct, path, func)

View Source (macro)

Applies func under path in struct and returns result of this func. Raises if path is not found.

Example:

iex> x = 1
iex> 9 = at! [0, %{x: 8}], path(x / :x), fn x -> x + 1 end
iex> p = path "hey" / 0
iex> {:here, 9} = at!(%{"hey" => {9, -9}}, p, & {:here, &1})
Link to this macro

at(struct, path, func)

View Source (macro)

Applies func under path in struct and returns result of this func.

Example:

iex> x = 1
iex> {:ok, 9} = at [0, %{x: 8}], path(x / :x), fn x -> x + 1 end
iex> p = path "hey" / 0
iex> {:ok, {:here, 9}} = at(%{"hey" => {9, -9}}, p, & {:here, &1})

The same as Pathex.~>/2 for those who do not like operators

Example:

iex> p1 = path :x / :y
iex> p2 = path :a / :b
iex> composed_path = concat(p1, p2)
iex> {:ok, 1} = view %{x: [y: [a: [a: 0, b: 1]]]}, composed_path
Link to this macro

delete!(struct, path)

View Source (macro)

Deletes value under path in struct or raises if value is not found.

Example:

iex> x = 1
iex> [0, %{}] = delete!([0, %{x: 8}], path(x / :x))
Link to this macro

delete(struct, path)

View Source (macro)

Deletes value under path in struct.

Example:

iex> x = 1
iex> {:ok, [0, %{}]} = delete([0, %{x: 8}], path(x / :x))
iex> :error = delete([0, %{x: 8}], path(1 / :y))
Link to this macro

exists?(struct, path)

View Source (macro)

Gets the value under path in struct or returns default value if not found.

Example:

iex> x = 1
iex> true = exists?([0, %{x: 8}], path(x / :x))
iex> p = path "hey" / "you"
iex> false = exists?(%{"hey" => [x: 1]}, p)
Link to this macro

force_over!(struct, path, func, value \\ nil)

View Source (macro)

Applies func under path of struct.

If the path does not exist it creates the path favouring maps when structure is unknown and inserts default value.

Example:

iex> x = 1
iex> [0, %{x: {:xxx, 8}}] = force_over!([0, %{x: 8}], path(x / :x), & {:xxx, &1}, 123)
iex> p = path "hey" / 0
iex> %{"hey" => %{0 => 1}} = force_over!(%{}, p, fn x -> x + 1 end, 1)

If the item in path doesn't have the right type, it raises.

Example:

iex> p = path "hey" / "you"
iex> force_over! %{"hey" => {1, 2}}, p, fn x -> x end, "value"
** (Pathex.Error) Type mismatch in structure
Link to this macro

force_over(struct, path, func, value \\ nil)

View Source (macro)

Applies func under path of struct.

If the path does not exist it creates the path favouring maps when structure is unknown and inserts default value.

Example:

iex> x = 1
iex> {:ok, [0, %{x: {:xxx, 8}}]} = force_over([0, %{x: 8}], path(x / :x), & {:xxx, &1}, 123)
iex> p = path "hey" / 0
iex> {:ok, %{"hey" => %{0 => 1}}} = force_over(%{}, p, fn x -> x + 1 end, 1)

If the item in path doesn't have the right type, it returns :error.

Example:

iex> p = path "hey" / "you"
iex> :error = force_over %{"hey" => {1, 2}}, p, fn x -> x end, "value"
Link to this macro

force_set!(struct, path, value)

View Source (macro)

Sets the value under path in struct.

If the path does not exist it creates the path favouring maps when structure is unknown.

Example:

iex> x = 1
iex> [0, %{x: 123}] = force_set! [0, %{x: 8}], path(x / :x), 123
iex> p = path "hey" / 0
iex> %{"hey" => %{0 => 1}} = force_set! %{}, p, 1

If the item in path doesn't have the right type, it raises.

Example:

iex> p = path "hey" / "you"
iex> force_set! %{"hey" => {1, 2}}, p, "value"
** (Pathex.Error) Type mismatch in structure
Link to this macro

force_set(struct, path, value)

View Source (macro)

Sets the value under path in struct.

If the path does not exist it creates the path favouring maps when structure is unknown.

Example:

iex> x = 1
iex> {:ok, [0, %{x: 123}]} = force_set [0, %{x: 8}], path(x / :x), 123
iex> p = path "hey" / 0
iex> {:ok, %{"hey" => %{0 => 1}}} = force_set %{}, p, 1

If the item in path doesn't have the right type, it returns :error.

Example:

iex> p = path "hey" / "you"
iex> :error = force_set %{"hey" => {1, 2}}, p, "value"
Link to this macro

get(struct, path, default \\ nil)

View Source (macro)

Gets the value under path in struct or returns default when path is not present.

Example:

iex> x = 1
iex> 8 = get([0, %{x: 8}], path(x / :x))
iex> p = path "hey" / "you"
iex> nil = get(%{"hey" => [x: 1]}, p)
iex> :default = get(%{"hey" => [x: 1]}, p, :default)
@spec inspect(t()) :: iodata()

Inspect the given path-closure and returns string which corresponds to given path-closure

Example:

iex> index = 1
iex> p = path(:x) ~> path(:y / index) &&& path(-1)
iex> Pathex.inspect(p)
"path(:x) ~> path(:y / 1) &&& path(-1)"
Link to this macro

over!(struct, path, func)

View Source (macro)

Applies the func to the item under path in struct and returns modified structure. Works like Map.update!/3.

Example:

iex> x = 1
iex> inc = fn x -> x + 1 end
iex> [0, %{x: 9}] = over! [0, %{x: 8}], path(x / :x), inc
iex> p = path "hey" / 0
iex> %{"hey" => [2, [2]]} = over! %{"hey" => [1, [2]]}, p, inc
Link to this macro

over(struct, path, func)

View Source (macro)

Applies func to the item under the path in struct and returns modified structure. Works like Map.update!/3 but doesn't raise.

Example:

iex> index = 1
iex> inc = fn x -> x + 1 end
iex> {:ok, [0, %{x: 9}]} = over [0, %{x: 8}], path(index / :x), inc
iex> p = path "hey" / 0
iex> {:ok, %{"hey" => [2, [2]]}} = over %{"hey" => [1, [2]]}, p, inc

Note: Exceptions from passed function left unhandled

iex> over(%{1 => "x"}, path(1), fn x -> x + 1 end)
** (ArithmeticError) bad argument in arithmetic expression
Link to this macro

path(quoted, mod \\ nil)

View Source (macro)

Creates path from quoted ast. Paths look like unix fs path and consist of elements separated from each other with /. See

For example:

iex> x = 1
iex> mypath = path 1 / :atom / "string" / {"tuple?"} / x
iex> structure = [0, [atom: %{"string" => %{{"tuple?"} => %{1 => 2}}}]]
iex> {:ok, 2} = view structure, mypath

Default modifier of this path/2 is :naive which means that

  • Every variable is treated as index or key to tuple, list, map and keyword
  • Every atom is treated as key to map or keyword
  • Every integer is treated as index to tuple, list or key to map
  • Every other data type is treated as key to map

Note:
-1 allows data to be prepended to the list

iex> x = -1
iex> p1 = path(-1)
iex> p2 = path(x)
iex> {:ok, [1, 2]} = force_set([2], p1, 1)
iex> {:ok, [1, 2]} = force_set([2], p2, 1)
Link to this macro

pop!(struct, path)

View Source (macro)

Gets value under path in struct and then deletes it. Note that current implementation of this function performs double lookup.

Example:

iex> {1, [2, 3]} = pop!([1, 2, 3], path(0))
Link to this macro

pop(struct, path)

View Source (macro)

Macro which gets value in the structure and deletes it. Note that current implementation of this function performs double lookup.

Example:

iex> {:ok, {1, [2, 3]}} = pop([1, 2, 3], path(0))
Link to this macro

set!(struct, path, value)

View Source (macro)

Sets the value under path in struct. Think of it like Map.put/3.

Example:

iex> x = 1
iex> [0, %{x: 123}] = set! [0, %{x: 8}], path(x / :x), 123
iex> p = path "hey" / 0
iex> %{"hey" => [123, [2]]} = set! %{"hey" => [1, [2]]}, p, 123
Link to this macro

set(struct, path, value)

View Source (macro)

Sets value under path in structure. Think of it like Map.put/3.

Example:

iex> x = 1
iex> {:ok, [0, %{x: 123}]} = set [0, %{x: 8}], path(x / :x), 123
iex> p = path "hey" / 0
iex> {:ok, %{"hey" => [123, [2]]}} = set %{"hey" => [1, [2]]}, p, 123
Link to this macro

view!(struct, path)

View Source (macro)

Gets the value under path in struct. Raises if path not found.

Example:

iex> x = 1
iex> 8 = view! [0, %{x: 8}], path(x / :x)
iex> p = path "hey" / 0
iex> 9 = view! %{"hey" => {9, -9}}, p
Link to this macro

view(struct, path)

View Source (macro)

Gets the value under path in struct.

Example:

iex> x = 1
iex> {:ok, 8} = view [0, %{x: 8}], path(x / :x)
iex> p = path "hey" / 0
iex> {:ok, 9} = view %{"hey" => {9, -9}}, p

Creates composition of two paths which has some inspiration from logical or.
This means that a ||| b path-closure tries to apply a and only if it returns :error, tries apply b

Example:

iex> p1 = path :x / :y
iex> p2 = path :a / :b
iex> op = p1 ||| p2
iex> {:ok, 1} = view %{x: %{y: 1}, a: [b: 2]}, op
iex> {:ok, 2} = view %{x: 1, a: [b: 2]}, op
iex> {:ok, %{x: %{y: 2}, a: [b: 1]}} = set %{x: %{y: 1}, a: [b: 1]}, op, 2
iex> {:ok, %{x: %{y: 2}}} = force_set %{}, op, 2
iex> {:ok, %{x: %{}, a: [b: 1]}} = force_set %{x: %{y: 1}, a: [b: 1]}, op, 2

Creates composition of two paths similar to concatenating them together.
This means that a ~> b path-closure applies a and only if it returns {:ok, something} it applies b to something

Example:

iex> p1 = path :x / :y
iex> p2 = path :a / :b
iex> composed_path = p1 ~> p2
iex> {:ok, 1} = view %{x: [y: [a: [a: 0, b: 1]]]}, composed_path