Allow optional: :all when deriving Inspect (#14400)

* Allow optional: :all when deriving Inspect

* Improve error message when passing a non-list
This commit is contained in:
Jean Klingler
2025-04-05 16:58:13 +09:00
committed by GitHub
parent a93ce0886a
commit be17d71e45
2 changed files with 44 additions and 3 deletions
+19 -3
View File
@@ -67,7 +67,8 @@ defprotocol Inspect do
* `:optional` - (since v1.14.0) a list of fields that should not be
included when they match their default value. This can be used to
simplify the struct representation at the cost of hiding
information.
information. Since v1.19.0, the `:all` atom can be passed to
mark all fields as optional.
Whenever `:only` or `:except` are used to restrict fields,
the struct will be printed using the `#User<...>` notation,
@@ -159,11 +160,19 @@ defprotocol Inspect do
only = Keyword.get(options, :only, fields)
except = Keyword.get(options, :except, [])
optional = Keyword.get(options, :optional, [])
:ok = validate_option(:only, only, fields, module)
:ok = validate_option(:except, except, fields, module)
:ok = validate_option(:optional, optional, fields, module)
optional =
case Keyword.get(options, :optional, []) do
:all ->
fields
optional ->
:ok = validate_option(:optional, optional, fields, module)
optional
end
inspect_module =
if fields == Enum.sort(only) and except == [] do
@@ -226,6 +235,13 @@ defprotocol Inspect do
end
defp validate_option(option, option_list, fields, module) do
if not is_list(option_list) do
raise ArgumentError,
"invalid value #{Kernel.inspect(option_list)} in #{Kernel.inspect(option)} " <>
"when deriving the Inspect protocol for #{Kernel.inspect(module)} " <>
"(expected a list)"
end
case option_list -- fields do
[] ->
:ok
+25
View File
@@ -715,6 +715,17 @@ defmodule Inspect.MapTest do
end
end
test "passing a non-list to the :only option" do
assert_raise ArgumentError,
"invalid value :not_a_list in :only when deriving the Inspect protocol for Inspect.MapTest.StructInvalidListInOnlyOption (expected a list)",
fn ->
defmodule StructInvalidListInOnlyOption do
@derive {Inspect, only: :not_a_list}
defstruct [:a, :b]
end
end
end
defmodule StructWithExceptOption do
@derive {Inspect, except: [:b, :c]}
defstruct [:a, :b, :c, :d]
@@ -772,6 +783,20 @@ defmodule Inspect.MapTest do
assert inspect(struct) ==
"#Inspect.MapTest.StructWithExceptOptionalAndOrder<d: nil, a: nil, ...>"
end
defmodule StructWithOptionalAll do
@derive {Inspect, optional: :all}
defstruct [:a, :b, :c, :d]
end
test "struct with :optional set to :all" do
struct = %StructWithOptionalAll{a: 1, b: 2}
assert inspect(struct) == "%Inspect.MapTest.StructWithOptionalAll{a: 1, b: 2}"
struct = %StructWithOptionalAll{}
assert inspect(struct) == "%Inspect.MapTest.StructWithOptionalAll{}"
end
end
defmodule Inspect.OthersTest do