Eden
=====
[](https://travis-ci.org/jfacorro/Eden)
[](https://hex.pm/packages/eden)
[](https://hex.pm/packages/eden)
[edn](https://github.com/edn-format/edn) (extensible data notation) encoder/decoder implemented in Elixir.
## Usage
Include Eden as a dependency in your Elixir project by adding it in your `deps` list:
```elixir
def deps do
[{:eden, "~> 0.1.2"}]
end
```
Eden is a library application and as such doesn't specify an application callback module. Even so, if you would like to build a release that includes Eden, you need to add it as an application dependency in your `mix.exs`:
```elixir
def application do
[applications: [:eden]]
end
```
## Examples
```elixir
iex> Eden.encode([1, 2])
{:ok, "(1, 2)"}
iex> Eden.encode(%{a: 1, b: 2, c: 3})
{:ok, "{:a 1, :b 2, :c 3}"}
iex> Eden.encode({:a, 1})
{:error, Protocol.UndefinedError}
iex> Eden.decode("{:a 1 :b 2}")
{:ok, %{a: 1, b: 2}}
iex> Eden.decode("(hello :world \\!)")
{:ok, [%Eden.Symbol{name: "hello"}, :world, %Eden.Character{char: "!"}]
iex> Eden.decode("[1 2 3 4]")
{:ok, #Array<[1, 2, 3, 4], fixed=false, default=nil>}
iex> Eden.decode("nil true false")
{:ok, [nil, true, false]}
iex> Eden.decode("nil true false .")
{:error, Eden.Exception.UnexpectedInputError}
```
## Data Structures Mapping: **edn** <-> **Elixir**
| Edn | Elixir |
|---|---|
| `nil` | `:nil = nil` |
| `true` | `:true = true` |
| `false` | `:false = false` |
| `string` | `String` |
| `character` | `Eden.Character` |
| `symbol` | `Eden.Symbol` |
| `keyword` | `Atom` |
| `integer` | `Integer` |
| `float` | `Float` |
| `list` | `List` |
| `vector` | `Array` |
| `map` | `Map` |
| `set` | `HashSet` |
| `#inst` | `Timex.DateTime` |
| `#uuid` | `Eden.UUID` |
## Further Considerations
### `Character`
There is no way of distinguishing a common integer from the representation of a character in a `String` or in `Char lists`. This forces the creation of a new representation for this type so it can be correctly translated from and to **edn**.
### Arbitrary Precision `Integer` and `Float`
The Erlang VM (EVM) only provides arbitrary precision integers so all integers will be of this type this and the `N` modifier will be ignored when parsing an **edn** integer.
On the other hand native arbitrary precision floating point numbers are not provided by the EVM so all values of type `float` will be represented according to what the EVM supports.
### `Keyword` and `Symbol` Representation
On one hand the decision to translate **edn** `keyword`s as Elixir `atom`s comes from the fact these two data types are given a similar usage on both languages. On the other, it might get awkward really fast using a new `Eden.Symbol` struct as the representation for **edn**'s `symbol`s so this might change.
### `vector`
There is no constant lookup or nearly constant indexed data structure like **edn**'s `vector` other than the `:array` data structure implemented in one of Erlang's standard library modules. Until there is a better implementation for this `Eden` will use [`Array`](https://github.com/takscape/elixir-array), an Elixir wrapper library for Erlang's array.
## **edn** grammar
```
expr -> literal | map | list | vector | tagged_value
literal -> nil | true | false | keyword | symbol | integer | float | string
map -> { pair* }
pair -> expr expr
list -> ( expr* )
vector -> [ expr* ]
tagged_value -> tag expr
```