diff --git a/lib/elixir/lib/inspect.ex b/lib/elixir/lib/inspect.ex index 793f27df9e9..e57a3de142f 100644 --- a/lib/elixir/lib/inspect.ex +++ b/lib/elixir/lib/inspect.ex @@ -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 diff --git a/lib/elixir/test/elixir/inspect_test.exs b/lib/elixir/test/elixir/inspect_test.exs index accf3561ee4..91475f78185 100644 --- a/lib/elixir/test/elixir/inspect_test.exs +++ b/lib/elixir/test/elixir/inspect_test.exs @@ -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" 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