plymio_ast v0.2.0 Plymio.Ast.Form

Utility Functions for Manipulating Asts (Quoted Forms)

Summary

Functions

maybe_ast_escape/1 escapes (Macro.escape/1) any value other than a module attribute or an existing ast (i.e. Macro.validate/1 returns :ok)

Takes a maybe quoted value and returns the realised value

Takes a maybe quoted value, realises it and, if a function, returns {:ok, function}. Anything else returns :error

Takes a maybe quoted value, realises it using maybe_ast_realise_function/1, and, if {:ok, function}, returns the function, else raises a BadFunctionError exception

Takes a maybe quoted value, realises it and, if a Map, returns {:ok, map}

Takes a maybe quoted value, realises it using maybe_ast_realise_map/1, and if the result is {:ok, map}, returns the map, else raises a BadMapError exception

Takes a maybe quoted value, realises it and, if a compiled module, returns {:ok, module}

Takes a maybe quoted value, realises it using maybe_ast_realise_module/1, and, if {:ok, module}, returns the module, else raises a ArgumentError exception

Takes a maybe quoted value, realises it and, if a tuple, returns {:ok, tuple}

Takes a maybe quoted value, realises it using maybe_ast_realise_tuple/1, and if the result is {:ok, tuple}, returns the tuple, else raises an ArgumentError exception

Functions

maybe_ast_escape(value)
maybe_ast_escape(any) :: Macro.t

maybe_ast_escape/1 escapes (Macro.escape/1) any value other than a module attribute or an existing ast (i.e. Macro.validate/1 returns :ok)

Examples

iex> 42 |> maybe_ast_escape
42

iex> :two |> maybe_ast_escape
:two

iex> %{a: 1} |> maybe_ast_escape
{:%{}, [], [a: 1]}

iex> %{a: 1} |> Macro.escape |> maybe_ast_escape
{:%{}, [], [a: 1]}

iex> [1, %{b: 2}, {:c, 2, :tre}] |> maybe_ast_escape
[1, {:%{}, [], [b: 2]}, {:{}, [], [:c, 2, :tre]}]

iex> [1, %{b: 2}, {:c, 2, :tre}] |> Macro.escape |> maybe_ast_escape
[1, {:%{}, [], [b: 2]}, {:{}, [], [:c, 2, :tre]}]
maybe_ast_realise(value)
maybe_ast_realise(any) :: any

Takes a maybe quoted value and returns the realised value.

Realisation in this context means extracting the underlying (“unquoted”) value.

Examples

iex> 1 |> maybe_ast_realise
1

iex> :atom |> maybe_ast_realise
:atom

iex> "string" |> maybe_ast_realise
"string"

iex> [1, :atom, "string"] |> maybe_ast_realise
[1, :atom, "string"]

iex> {:x, 42} |> maybe_ast_realise
{:x, 42}

iex> ast = {:x, 42} |> Macro.escape
...> ast |> maybe_ast_realise
{:x, 42}

iex> %{a: 1, b: 2, c: 3} |> maybe_ast_realise
%{a: 1, b: 2, c: 3}

iex> ast = %{a: 1, b: 2, c: 3} |> Macro.escape
...> ast |> maybe_ast_realise
%{a: 1, b: 2, c: 3}

iex> fun = fn x -> x + 5 end
...> fun = fun |> maybe_ast_realise
...> 42 |> fun.()
47

iex> ast = "fn x -> x + 5 end" |> Code.string_to_quoted!
...> fun = ast |> maybe_ast_realise
...> 42 |> fun.()
47

A map’s keys and values are recursively realised:

iex> ast = %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3} |> Macro.escape
iex> ast |> maybe_ast_realise
%{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}

The elements of a tuple are recursively realised:

iex> ast = [{:x, 2, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}}] |> Macro.escape
iex> ast |> maybe_ast_realise
[{:x, 2, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}}]

The elements of a list are recursively realised:

iex> ast = [{:x,:y,:z}, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}] |> Macro.escape
iex> ast |> maybe_ast_realise
[{:x,:y,:z}, [1,2,3], %{a: %{a1: 1}, b: %{b21: 21, b22: 22}, c: 3}]
maybe_ast_realise_function(value)
maybe_ast_realise_function(any) :: {:ok, (... -> any)} | :error

Takes a maybe quoted value, realises it and, if a function, returns {:ok, function}. Anything else returns :error.

iex> fun = fn x -> x end
...> result = fun |> maybe_ast_realise_function
...> match?({:ok, ^fun}, result)
true

iex> quoted_fun = quote(do: fn x -> x end)
...> {:ok, fun} = quoted_fun |> maybe_ast_realise_function
...> is_function(fun, 1)
true

iex> 42 |> maybe_ast_realise_function
:error

iex> {:x, 42} |> Macro.escape
...> |> maybe_ast_realise_function
:error
maybe_ast_realise_function!(value)
maybe_ast_realise_function!(any) :: (... -> any) | no_return

Takes a maybe quoted value, realises it using maybe_ast_realise_function/1, and, if {:ok, function}, returns the function, else raises a BadFunctionError exception.

iex> fun = fn x -> x end
...> result = fun |> maybe_ast_realise_function!
...> match?(^fun, result)
true

iex> quoted_fun = quote(do: fn x -> x end)
...> fun = quoted_fun |> maybe_ast_realise_function!
...> is_function(fun, 1)
true

iex> 42 |> maybe_ast_realise_function!
** (BadFunctionError) expected a function, got: :error

iex> {:x, 42}
...> |> Macro.escape
...> |> maybe_ast_realise_function!
** (BadFunctionError) expected a function, got: :error
maybe_ast_realise_map(value)
maybe_ast_realise_map(any) :: {:ok, map} | :error

Takes a maybe quoted value, realises it and, if a Map, returns {:ok, map}.

If the realised value is a Keyword, its is converted to a map and {:ok, map} returned.

Anything else returns :error.

The keys and values are recursively realised.

iex> %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> maybe_ast_realise_map
{:ok, %{a: 1, b: %{b21: 21, b22: 22}, c: 3}}

iex> ast = %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> Macro.escape
iex> ast |> maybe_ast_realise_map
{:ok, %{a: 1, b: %{b21: 21, b22: 22}, c: 3}}

iex> 42 |> maybe_ast_realise_map
:error

iex> ast = {:x, 42} |> Macro.escape
iex> ast |> maybe_ast_realise_map
:error
maybe_ast_realise_map!(value)
maybe_ast_realise_map!(any) :: map | no_return

Takes a maybe quoted value, realises it using maybe_ast_realise_map/1, and if the result is {:ok, map}, returns the map, else raises a BadMapError exception.

iex> %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> maybe_ast_realise_map!
%{a: 1, b: %{b21: 21, b22: 22}, c: 3}

iex> ast = %{a: 1, b: %{b21: 21, b22: 22}, c: 3} |> Macro.escape
iex> ast |> maybe_ast_realise_map!
%{a: 1, b: %{b21: 21, b22: 22}, c: 3}

iex> 42 |> maybe_ast_realise_map!
** (BadMapError) expected a map, got: :error

iex> ast = {:x, 42} |> Macro.escape
iex> ast |> maybe_ast_realise_map!
** (BadMapError) expected a map, got: :error
maybe_ast_realise_module(value)
maybe_ast_realise_module(any) :: {:ok, atom} | :error

Takes a maybe quoted value, realises it and, if a compiled module, returns {:ok, module}.

Tests whether the module’s __info__ function works to confirm an actual module.

Anything else returns :error.

iex> mod = (defmodule ABC1, do: nil) |> elem(1)
...> result = mod |> maybe_ast_realise_module
...> match?({:ok, ^mod}, result)
true

iex> mod = (defmodule ABC2, do: nil) |> elem(1)
...> quoted_mod = mod |> Macro.escape
...> result = quoted_mod |> maybe_ast_realise_module
...> match?({:ok, ^mod}, result)
true

iex> 42 |> maybe_ast_realise_module
:error

iex> {:x, 42}
...> |> Macro.escape
...> |> maybe_ast_realise_module
:error
maybe_ast_realise_module!(value)
maybe_ast_realise_module!(any) :: atom | no_return

Takes a maybe quoted value, realises it using maybe_ast_realise_module/1, and, if {:ok, module}, returns the module, else raises a ArgumentError exception.

iex> mod = (defmodule ABC3, do: nil) |> elem(1)
...> result = mod |> maybe_ast_realise_module!
...> match?(^mod, result)
true

iex> mod = (defmodule ABC, do: nil) |> elem(1)
...> quoted_mod = mod |> Macro.escape
...> result = quoted_mod |> maybe_ast_realise_module!
...> match?(^mod, result)
true

iex> :an_atom_but_not_a_module |> maybe_ast_realise_module!
** (ArgumentError) expected a module, got: :error

iex> 42 |> maybe_ast_realise_module!
** (ArgumentError) expected a module, got: :error

iex> {:x, 42}
...> |> Macro.escape
...> |> maybe_ast_realise_module!
** (ArgumentError) expected a module, got: :error
maybe_ast_realise_tuple(value)
maybe_ast_realise_tuple(any) :: {:ok, tuple} | :error

Takes a maybe quoted value, realises it and, if a tuple, returns {:ok, tuple}.

Anything else returns :error.

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3} |> maybe_ast_realise_tuple
{:ok, {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}}

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}
...> |> Macro.escape
...> |> maybe_ast_realise_tuple
{:ok, {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}}

iex> 42 |> maybe_ast_realise_tuple
:error

iex> %{x: 42}
...> |> Macro.escape
...> |> maybe_ast_realise_tuple
:error
maybe_ast_realise_tuple!(value)
maybe_ast_realise_tuple!(any) :: tuple | no_return

Takes a maybe quoted value, realises it using maybe_ast_realise_tuple/1, and if the result is {:ok, tuple}, returns the tuple, else raises an ArgumentError exception.

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3} |> maybe_ast_realise_tuple!
{:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}

iex> {:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}
...> |> Macro.escape
...> |> maybe_ast_realise_tuple!
{:one, 1, %{"two1" => 21, :two2 => 22}, "tre", 3}

iex> 42 |> maybe_ast_realise_tuple!
** (ArgumentError) expected a tuple, got: :error

iex> %{x: 42}
...> |> Macro.escape
...> |> maybe_ast_realise_tuple!
** (ArgumentError) expected a tuple, got: :error