Skip to content

Commit be17d71

Browse files
authored
Allow optional: :all when deriving Inspect (#14400)
* Allow optional: :all when deriving Inspect * Improve error message when passing a non-list
1 parent a93ce08 commit be17d71

File tree

2 files changed

+44
-3
lines changed

2 files changed

+44
-3
lines changed

lib/elixir/lib/inspect.ex

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ defprotocol Inspect do
6767
* `:optional` - (since v1.14.0) a list of fields that should not be
6868
included when they match their default value. This can be used to
6969
simplify the struct representation at the cost of hiding
70-
information.
70+
information. Since v1.19.0, the `:all` atom can be passed to
71+
mark all fields as optional.
7172
7273
Whenever `:only` or `:except` are used to restrict fields,
7374
the struct will be printed using the `#User<...>` notation,
@@ -159,11 +160,19 @@ defprotocol Inspect do
159160

160161
only = Keyword.get(options, :only, fields)
161162
except = Keyword.get(options, :except, [])
162-
optional = Keyword.get(options, :optional, [])
163163

164164
:ok = validate_option(:only, only, fields, module)
165165
:ok = validate_option(:except, except, fields, module)
166-
:ok = validate_option(:optional, optional, fields, module)
166+
167+
optional =
168+
case Keyword.get(options, :optional, []) do
169+
:all ->
170+
fields
171+
172+
optional ->
173+
:ok = validate_option(:optional, optional, fields, module)
174+
optional
175+
end
167176

168177
inspect_module =
169178
if fields == Enum.sort(only) and except == [] do
@@ -226,6 +235,13 @@ defprotocol Inspect do
226235
end
227236

228237
defp validate_option(option, option_list, fields, module) do
238+
if not is_list(option_list) do
239+
raise ArgumentError,
240+
"invalid value #{Kernel.inspect(option_list)} in #{Kernel.inspect(option)} " <>
241+
"when deriving the Inspect protocol for #{Kernel.inspect(module)} " <>
242+
"(expected a list)"
243+
end
244+
229245
case option_list -- fields do
230246
[] ->
231247
:ok

lib/elixir/test/elixir/inspect_test.exs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,17 @@ defmodule Inspect.MapTest do
715715
end
716716
end
717717

718+
test "passing a non-list to the :only option" do
719+
assert_raise ArgumentError,
720+
"invalid value :not_a_list in :only when deriving the Inspect protocol for Inspect.MapTest.StructInvalidListInOnlyOption (expected a list)",
721+
fn ->
722+
defmodule StructInvalidListInOnlyOption do
723+
@derive {Inspect, only: :not_a_list}
724+
defstruct [:a, :b]
725+
end
726+
end
727+
end
728+
718729
defmodule StructWithExceptOption do
719730
@derive {Inspect, except: [:b, :c]}
720731
defstruct [:a, :b, :c, :d]
@@ -772,6 +783,20 @@ defmodule Inspect.MapTest do
772783
assert inspect(struct) ==
773784
"#Inspect.MapTest.StructWithExceptOptionalAndOrder<d: nil, a: nil, ...>"
774785
end
786+
787+
defmodule StructWithOptionalAll do
788+
@derive {Inspect, optional: :all}
789+
defstruct [:a, :b, :c, :d]
790+
end
791+
792+
test "struct with :optional set to :all" do
793+
struct = %StructWithOptionalAll{a: 1, b: 2}
794+
795+
assert inspect(struct) == "%Inspect.MapTest.StructWithOptionalAll{a: 1, b: 2}"
796+
797+
struct = %StructWithOptionalAll{}
798+
assert inspect(struct) == "%Inspect.MapTest.StructWithOptionalAll{}"
799+
end
775800
end
776801

777802
defmodule Inspect.OthersTest do

0 commit comments

Comments
 (0)