From c39b807e2351333033208f06e3a1d28932912f0b Mon Sep 17 00:00:00 2001 From: sabiwara Date: Sat, 5 Apr 2025 16:39:19 +0900 Subject: [PATCH 1/2] Allow optional: :all when deriving Inspect --- lib/elixir/lib/inspect.ex | 15 ++++++++++++--- lib/elixir/test/elixir/inspect_test.exs | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/elixir/lib/inspect.ex b/lib/elixir/lib/inspect.ex index 793f27df9e9..c0633b1de0a 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 diff --git a/lib/elixir/test/elixir/inspect_test.exs b/lib/elixir/test/elixir/inspect_test.exs index accf3561ee4..d106e7a7a78 100644 --- a/lib/elixir/test/elixir/inspect_test.exs +++ b/lib/elixir/test/elixir/inspect_test.exs @@ -772,6 +772,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 From 7e42321e4ee51292daed5ab0c16ed7778d9cee54 Mon Sep 17 00:00:00 2001 From: sabiwara Date: Sat, 5 Apr 2025 16:44:56 +0900 Subject: [PATCH 2/2] Improve error message when passing a non-list --- lib/elixir/lib/inspect.ex | 7 +++++++ lib/elixir/test/elixir/inspect_test.exs | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/elixir/lib/inspect.ex b/lib/elixir/lib/inspect.ex index c0633b1de0a..e57a3de142f 100644 --- a/lib/elixir/lib/inspect.ex +++ b/lib/elixir/lib/inspect.ex @@ -235,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 d106e7a7a78..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]