I’m trying to write something that pretty-prints nested maps returned by MapDiff. I’ve already looked into Scribe and it doesn’t do quite what I want. I’m looking for something that will print only leaf nodes of a nested map.
If there is no such module for printing only leaf nodes of a nested map, then is there a module for traversing nested maps that I could use to create the pretty-printer myself? I’m considering Macro’s prewalk/postwalk functions for this but that kind of seems like overkill since it involves converting everything to an AST first…
I don’t know any built in module but it is very easy to implement yourself and customize what you need.
For instance, a very basic implementation could be this:
defmodule Mod do
def collect(map) when is_map(map) do
collect(map, [], [])
end
defp collect(map, prefix, acc) when is_map(map) do
Enum.reduce(map, acc, fn {k, v}, acc ->
collect(v, [k | prefix], acc)
end)
end
defp collect(value, prefix, acc) do
[{:lists.reverse(prefix), value} | acc]
end
def print_map_leafs(map) do
map
|> collect()
|> Enum.each(&print_leaf/1)
end
defp print_leaf({path, v}) do
IO.puts([Enum.map_join(path, ".", &to_string/1), ": ", inspect(v)])
end
end
Mod.print_map_leafs(%{a: 1, b: %{"c" => 2, d: %{4 => 5}}})
The next step would be to change that code to add a traverse function that accepts a callback. The callback could accept three arguments: key, value, and prefix. Then re-implement print_map_leafs using traverse.
I was faced with a similar problem. A deeply nested structure of tuples, maps and lists. I waned to see if there was a match for a specific term/pattern in the nested mess. I did something like this: