samgaw
Implementing Inspect
I’m working on a small library to scratch a current itch involving IP addresses & network subnetting that gives me a more structured datatype (a struct) after parsing a string or tuple.
While trying to improve it and make it nicer to work with, I started experimenting with deimpl Enumerable and managed to get things functional. However to do that, I ended up introducing a hidden key much like __struct__. Which then led me into deimpl Inspect in order to hide the new key and now I’m at a bit of a cross roads trying to balance two separate needs.
The struct I’m working with looks like:
%CIDR{
first: {172, 16, 0, 0},
last: {172, 31, 255, 255},
prefix: 12,
hosts: 1048576,
version: :v4
}
And I get that using:
defimpl Inspect, for: CIDR do
def inspect(%module{} = network, opts \\ []) do
filtered = Map.drop(network, [:__enum__, :__struct__])
Inspect.Map.inspect(filtered, Code.Identifier.inspect_as_atom(module), opts)
end
end
Reading that in the console standalone is perfect because I can quickly scan and grab whatever information I need from it. But if I’m looking at a list of maps, and the struct is the value of a key in each, it becomes a lot of noise.
To suppress things a bit I had a look at sigils and ended up implementing one which meant I was able to do:
defimpl Inspect, for: CIDR do
import Inspect.Algebra
def inspect(network, _opts), do: concat(["~n\"", CIDR.to_string(network) , "\""])
end
That’s perfect when it’s used as a datatype in a map or struct but I lose the convenience of seeing the struct in cases like:
iex> CIDR.parse("10.0.0.0/8")
~n"10.0.0.0/8"
It may be asking for a lot but is there anything contextual in Inspect that would allow me to use the short form when it’s a nested value but the long form when it’s the parent structure displayed?
Thanks.
Most Liked
fuelen
:custom_options key in https://hexdocs.pm/elixir/master/Inspect.Opts.html probably is what you are looking for
lud
Hi,
I don’t think that could be automatic but you could use the inspect options for that:
defmodule Test do
defmodule CIDR do
defstruct a: nil, b: nil, c: nil
end
def test do
t = %CIDR{a: 1, b: 2, c: 3}
IO.inspect(t)
IO.inspect(t, pretty: true)
end
end
defimpl Inspect, for: Test.CIDR do
def inspect(%Test.CIDR{a: a, b: b, c: c} = t, %Inspect.Opts{pretty: true}) do
"#CIDR<#{a}/#{b}/#{c}>"
end
def inspect(%Test.CIDR{a: a, b: b, c: c} = t, _) do
"#CIDR<#{a}>"
end
end
Test.test()
#CIDR<1>
#CIDR<1/2/3>
You can also use custom options, or other options from Inspect.Opts.
Of course that would still be up to you to pass or not the option that would change the result. Options will be passed down to your implementation from the implementation for lists.







