Pack Elixir data into self-extracting archives to paste elsewhere.
Ever had a large data structure you needed to attach to a ticket to make troubleshooting easier? Worse, was it full of references, pids, and structures with custom Inspect
protocol installations that made the output of IO.inspect/2
not valid Elixir?
Smuggle
makes it easy to pipe that value to a self-extracting archive you can paste anywhere for someone else to try on their system. It's as easy as:
Smuggle.dump(value)
The output will be Elixir code to reproduce your value
on another system. It'll be:
- Portable because
:erlang.term_to_binary/2
- Short because
compressed: 9
- Easy to get through anything that carries text because
Base.encode64/1
and line breaks
(fn v -> v |> Base.decode64!(ignore: :whitespace) |> :erlang.binary_to_term() end).(~S"""
g20AAABBT2gsIGdvb2Qgb24geW91IGZvciBjaGVja2luZy4gSXQgY291bGQgaGF2ZSBiZWVuIGFu
eXRoaW5nLCByaWdodD8=
""")
See Usage below for more details.
Do you need to take a dependency on this? The first few dozen times I did it, I copied or re-invented the encode/1
and decode/1
pipelines, but I'm enjoying having it around now. If you're in a hurry and don't want to touch mix
, loot what you need from below:
def encode(term) do
term
|> :erlang.term_to_binary(compressed: 9)
|> Base.encode64()
|> Stream.unfold(&String.split_at(&1, 76))
|> Enum.take_while(&(&1 != ""))
|> Enum.join("\n")
end
def decode(encoded) do
encoded
|> Base.decode64!(ignore: :whitespace)
|> :erlang.binary_to_term()
end
If your target is an iex
prompt:
Smuggle.dump(value)
# copy
# paste into other iex
The output of Smuggle.dump(true)
is:
(fn v -> v |> Base.decode64!(ignore: :whitespace) |> :erlang.binary_to_term() end).(~S"""
g2QABHRydWU=
""")
Paste that back into the iex
prompt of a local or remote console, and you'll get the value back:
Erlang/OTP 23 [erts-11.0.3] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [hipe]
Interactive Elixir (1.10.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> (fn v -> v |> Base.decode64!(ignore: :whitespace) |> :erlang.binary_to_term() end).(~S"""
...(1)> g2QABHRydWU=
...(1)> """)
true
It's more impressive when it's an %Ecto.Changeset{}
, but you get the gist. Speaking of which, sometimes you're trying to paste vital troubleshooting information into a GitHub issue, comment, or gist. It's polite to wrap that in a <details>
, and Smuggle
does all the hard work:
Smuggle.dump(value, wrapper: :gfm)
# copy
# paste into GitHub
On GitHub, the self-extracting archive will be hidden behind a friendly summary so it's easy to skip:
That friendly open source maintainer who'll check it out, though, can click once to see the whole thing:
Add smuggle
to your list of dependencies in mix.exs
:
def deps do
[
{:smuggle, "~> 1.0.0"}
]
end
Or, install it globally:
mix archive.install hex smuggle
make check
before you commit! If you'd prefer to do it manually:
mix do deps.get, deps.unlock --unused, deps.clean --unused
if you change dependenciesmix compile --warnings-as-errors
for a stricter compilemix coveralls.html
to check for test coveragemix credo
to suggest more idiomatic style for your codemix dialyzer
to find problems typing might reveal… albeit slowlymix docs
to generate documentation