Given the output of IO.inspect on a map, is there any way to parse that string back into a map?

Given the output of IO.inspect on a map, is there any way to parse that string back into a map?

For a one-shot hack, one could put them into source files and compile. For ongoing parsing out of a log, one could JSON encode them instead. But assume there’s a pile of maps written out by IO.inspect: is there a way to rehydrate them directly?

A tiny bit of context: I actually thought I had JSON in the files, but lolz, I do not.

1 Like

For a single map you can do this:

 %{a: 1} |> inspect |> Code.eval_string() |> elem(0)

Now if you have more, you will have to find a way to split the string into valid chunks of code.

Now if this for a test or a quick made tool it’s fine but otherwise consider that eval is evil and be sure that there is no proper way of doing what you want before eval’ing code.

2 Likes

Thank you, eval_string is what I was missing.

I do have more, and I am already splitting them–I got to the part where I tried to parse them after splitting, Jason.decode kept failing, I looked closer and realized D’OH! NOT JSON!! :wink:

2 Likes

You can also Code.eval_file if it was written to a file.

File.write!("maps.txt", inspect([%{foo: :bar}, %{biz: :baz}]))
# => :ok
"maps.txt"
|> Code.eval_file()
|> elem(0)
# => [%{foo: :bar}, %{biz: :baz}]

Again, eval is very dangerous! Only use it if you trust the content 100%. Sounds like maybe you wrote the files though but just be careful.

1 Like

One gotcha: inspect will truncate output by default if the maps are large. For instance:

0..100 |> Enum.with_index() |> Map.new() |> inspect() |> Code.eval_string()

fails (on my machine anyways) with:

warning: variable "..." does not exist and is being expanded to "...()", please use parentheses to remove the ambiguity or change the variable name
  nofile:1

** (CompileError) nofile:1: undefined function .../0 (there is no such import)
    (elixir 1.13.4) lib/code.ex:404: Code.validated_eval_string/3
4 Likes

True! and inspect(limit: :infinity, printable_limit: :infinity) solves that.

1 Like

Another gotcha is that there’s no requirement for the inspect output to be valid Elixir. Many structs are inspected as something like #Foo<something> instead of %Foo{something}. It may not be feasible to parse your inspect output at all.

Obligatory note, evaling strings is very dangerous and a wide open invitation for remote code execution, if an attacker can control the inputs.

2 Likes