exdn v2.1.1 Exdn

Exdn is a two-way translator between Elixir data structures and data following the edn specification; it wraps the erldn edn parser for Erlang, with some changes in the data formats.

Examples

iex> Exdn.to_elixir! "[1 :foo]"
[1, :foo]

iex> Exdn.to_elixir "{1 :foo, 2 :bar}"
{:ok, %{1 => :foo, 2 => :bar}}

iex> Exdn.from_elixir! %{1 => :foo, 2 => :bar}
"{1 :foo 2 :bar}"

iex> Exdn.from_elixir %{:foo => {:char, ?a}, {:char, ?b} => {:tag, :inst, "1985-04-12T23:20:50.52Z"} }
{:ok, "{:foo \a \b #inst "1985-04-12T23:20:50.52Z"}" }

Type mappings:

ednElixir generated by to_elixir functions (when no custom converter is provided)
integerinteger
floatfloat
booleanboolean
nilnil (atom)
charstring
stringstring
listtagged list {:list, [...]}
vectorlist
mapmap
setmapset
symboltagged atom {:symbol, atom}
tagged elementscall registered handler for that tag, fail if not found
Elixir accepted by from_elixir functionsedn
integerinteger
floatfloat
booleanboolean
nil (atom)nil
tagged integer {:char, <integer>}char
stringstring
tagged list {:list, [...]}list
listvector
mapmap
structmap
mapsetset
tagged atom {:symbol, atom}symbol
tagged tuple with tag and value {:tag, Symbol, Value}tagged elements

Summary

Functions

interprets a tagged expression using the tagged reversible representation and handlers passed in as a keyword list. Assumes the expression inside the tag has already been translated from edn

safe version of from_elixir!/1 — the edn string is returned as the second element of a pair whose first element is :ok — if there is an error the first element will be :error and the second the error that was raised

converts an Elixir data structure in the “reversible” format (see below) into an edn string. Will raise exceptions if the data structure cannot be converted

handlers for standard edn tagged expressions #inst and #uuid. If you need to supply your own custom handlers for other tags, you may wish to append them to this list of handlers

extracts a char (as a string) from the tagged reversible representation

extracts a list from the tagged reversible representation; does not operate at all on the contents of the extracted list

parses an edn string into an Elixir data structure, but does not throw exceptions. The parse result is returned as the second element of a pair whose first element is :ok — if there is an error the first element will be :error and the second the error that was raised

parses an edn string into an Elixir data structure; this is not a reversible conversion as chars are converted to strings, and tagged expressions are interpreted. This function can throw exceptions; for example, if a tagged expression cannot be interpreted

parses an edn string into an Elixir data structure, but in a reversible way — chars and tagged expressions are represented using tuples whose first element is :char or :tag, respectively

Functions

evaluate_tagged_expr(arg, converter, handlers)

interprets a tagged expression using the tagged reversible representation and handlers passed in as a keyword list. Assumes the expression inside the tag has already been translated from edn.

Example:

iex> tagged = {:tag, :foo, "blarg"}
iex> handler = fn(_tag, val, _converter, _handlers) -> val <> "-converted" end
iex> Exdn.evaluate_tagged_expr(tagged, [{:foo, handler}]
"blarg-converted"
from_elixir(elixir_data)

safe version of from_elixir!/1 — the edn string is returned as the second element of a pair whose first element is :ok — if there is an error the first element will be :error and the second the error that was raised.

Example:

iex> Exdn.from_elixir %{:foo => {:char, ?a}, {:char, ?b} => {:tag, :inst, "1985-04-12T23:20:50.52Z"} }
{:ok, "{:foo \a \b #inst "1985-04-12T23:20:50.52Z"}" }
from_elixir!(elixir_data)

converts an Elixir data structure in the “reversible” format (see below) into an edn string. Will raise exceptions if the data structure cannot be converted.

Examples:

# The intermediate representation can be converted back to edn:

iex> Exdn.from_elixir! 41.2
"41.2"

iex> Exdn.from_elixir! :foo
":foo"

iex> Exdn.from_elixir! true
"true"

iex> Exdn.from_elixir! nil
"nil"

iex> Exdn.from_elixir! "asd"
""asd""

iex> Exdn.from_elixir! {:char, ?a}
"\a"

iex> Exdn.from_elixir! {:symbol, :foo}
"foo"

iex> Exdn.from_elixir! [1, :foo]
"[1 :foo]"

iex> Exdn.from_elixir! {:list, [1, :foo]}
"(1 :foo)"

iex> Exdn.from_elixir! MapSet.new([1, :foo])
"#{1 :foo}"

iex> Exdn.from_elixir! %{1 => :foo, 2 => :bar}
"{1 :foo 2 :bar}"

iex> Exdn.from_elixir! %SomeStruct{foo: 1, bar: 2}
"{:foo 1 :bar 2}"

iex> Exdn.from_elixir! {:tag, :inst, "1985-04-12T23:20:50.52Z"}
"#inst "1985-04-12T23:20:50.52Z""
standard_handlers()

handlers for standard edn tagged expressions #inst and #uuid. If you need to supply your own custom handlers for other tags, you may wish to append them to this list of handlers.

tagged_char_to_string(arg)

extracts a char (as a string) from the tagged reversible representation.

Example:

iex> Exdn.tagged_char_to_string {:char, ?a}
"a"
tagged_list_to_list(arg)

extracts a list from the tagged reversible representation; does not operate at all on the contents of the extracted list.

Example:

iex> Exdn.tagged_list_to_list {:list, [:foo]}
[:foo]
to_elixir(val, converter \\ fn x -> x end, handlers \\ standard_handlers)

parses an edn string into an Elixir data structure, but does not throw exceptions. The parse result is returned as the second element of a pair whose first element is :ok — if there is an error the first element will be :error and the second the error that was raised.

Examples:

iex> Exdn.to_elixir "{1 :foo, 2 :bar}"
{:ok, %{1 => :foo, 2 => :bar}}

iex> Exdn.to_elixir "{:foo, \a, \b #foo "blarg" }"
{:error, %RuntimeError{:message => "Handler not found for tag foo with tagged expression blarg"}}
to_elixir!(edn, converter \\ fn x -> x end, handlers \\ standard_handlers)

parses an edn string into an Elixir data structure; this is not a reversible conversion as chars are converted to strings, and tagged expressions are interpreted. This function can throw exceptions; for example, if a tagged expression cannot be interpreted.

The second (optional) argument

The third (optional) argument allows you to supply your own handlers for the interpretation of tagged expressions. These should be in the form of a keyword list. The first element of each pair should be a keyword corresponding to the tag, and the second element a function of three parameters (tag, value, handlers) that handles the tagged values.

The one-argument version provides default handlers for #inst and #uuid.

Examples:

iex> Exdn.to_elixir! "41.2"
41.2

iex> Exdn.to_elixir! ":foo"
:foo

iex> Exdn.to_elixir! "true"
true

iex> Exdn.to_elixir! "nil"
nil

iex> Exdn.to_elixir! ""asd""
"asd"

# Char
iex> Exdn.to_elixir! "\a"
"a"

# Symbol
iex> Exdn.to_elixir! "foo"
{:symbol, :foo}

# edn vectors become Elixir lists:
iex> Exdn.to_elixir! "[1 :foo]"
[1, :foo]

# edn lists are always tagged. Since Datomic is a principal use of edn, and since lists are
# used in Datomic primarily for executable expressions rather than as data structures, we
# use Elixir lists to represent vectors and keep edn lists specially tagged:
iex> Exdn.to_elixir! "(1, :foo)"
{:list, [1, :foo]}

# edn sets become Elixir sets:
iex> Exdn.to_elixir! "#{1 \a 1}"
#MapSet<[1, "a"]>

# Maps become Elixir maps:
iex> Exdn.to_elixir! "{1 :foo, 2 :bar}"
%{1 => :foo, 2 => :bar}

# You can also transform maps to Elixir structs by providing your own converter in the second argument:
iex> defmodule FooStruct do
...>    defstruct foo: "default"
...> end
iex> converter = fn map ->
...>    case map do
...>       %{:foo => _} -> struct(FooStruct, map)
...>       anything_else -> anything_else
...>     end
...>   end
iex>  Exdn.to_elixir! "{:foo 1, :bar 2}", converter
%FooStruct{foo: 1}

# Tagged expressions are converted. Standard converters for #inst and #uuid are included:
iex> Exdn.to_elixir! "#inst "1985-04-12T23:20:50.52Z""
%Calendar.DateTime{abbr: "UTC", day: 12, hour: 23, min: 20, month: 4, sec: 50,
  std_off: 0, timezone: "Etc/UTC", usec: 520000, utc_off: 0, year: 1985}

iex> Exdn.to_elixir! "#uuid "f81d4fae-7dec-11d0-a765-00a0c91e6bf6""
"f81d4fae-7dec-11d0-a765-00a0c91e6bf6"

# You can provide your own handlers for tagged expressions:
iex> handler = fn(_tag, val, _handlers) -> val <> "-converted" end
iex> Exdn.to_elixir! "#foo "blarg"", [{:foo, handler}]
"blarg-converted"
to_reversible(edn)

parses an edn string into an Elixir data structure, but in a reversible way — chars and tagged expressions are represented using tuples whose first element is :char or :tag, respectively.

Examples:

iex> Exdn.to_reversible( "\a" )
{:char, ?a}

iex> Exdn.to_reversible "#inst "1985-04-12T23:20:50.52Z""
{:tag, :inst, "1985-04-12T23:20:50.52Z"}

# An unknown tag raises no error when using the reversible conversion:
iex> Exdn.to_reversible "#foo "blarg""
{:tag, :foo, "blarg"}