I'm trying to turn a YAML file into a Map. The yamerl library
(
https://github.com/yakaz/yamerl) returns an array of tuples where the
keys are char lists and the values are built-in values like char
lists, numbers, lists, or arrays of tuples. It's not difficult to
recurse through the data and turn things into maps.
The problem I'm having is with turning list of chars into lists of
strings. I end up turning ['
foo.com', '
bar.com'] into "
foo.combar.com"
and turning [1, 2, 3] into <<1, 2, 3>>.
Here's what I have so far. What am I doing wrong?
defmodule Servers.Converter do
def to_atom_map(yaml_tuples) do
_to_atom_map(yaml_tuples, %{})
end
defp _to_atom_map([], map), do: map
defp _to_atom_map([{key, val} | yaml_tuples], map) do
yaml_tuples |> _to_atom_map(Dict.put_new(map, list_to_atom(key),
to_atom_map(val)))
end
defp _to_atom_map(val, _) when is_list(val) do
case String.from_char_data(val) do
{:ok, s} -> s
_ -> val |> Enum.map &(to_atom_map(&1))
end
end
defp _to_atom_map(val, _), do: val
end
For fun, here is the unit test I have:
defmodule ConverterTest do
use ExUnit.Case
alias Servers.Converter, as: C
test "empty" do
assert C.to_atom_map([]) == %{}
end
test "get back a map with atomic keys" do
assert C.to_atom_map([{'a', 'b'}]) == %{a: "b"}
end
test "more than one key" do
assert C.to_atom_map([{'a', 'b'}, {'c', 42}]) == %{a: "b", c: 42}
end
test "convert list values" do
# This fails: I get back {a: <<1, 2, 3>>}
assert C.to_atom_map([{'a', [1, 2, 3]}]) == %{a: [1, 2, 3]}
assert C.to_atom_map([{'a', [1, [2, 3]]}]) == %{a: [1, [2, 3]]}
end
test "convert lists of strings" do
# This fails: I get back {a: "abcdef"}
assert C.to_atom_map([{'a', ['abc', 'def']}]) == %{a: ["abc", "def"]}
end
test "recursive structures mapped" do
assert C.to_atom_map([{'a', [{'b', 'c'}]}]) == %{a: %{b: "c"}}
end
end
Jim
--
Jim Menard,
http://www.jimmenard.com/