Skip to content

Commit

Permalink
Allow explicit nil to be serialized by enums
Browse files Browse the repository at this point in the history
This commit uses an `UNSET` constant as the default `serialized_val` on
`T::Enum`. This allows the runtime to understand the difference between
an explicit `nil` and an unset default when serializing enum values.
Sorbet already understands statically that a serialized value can be of
type `NilClass`, but the runtime was serializing as a string
representation based on the constant name instead.
  • Loading branch information
thomasmarshall committed May 21, 2024
1 parent 718bc64 commit bc24d25
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 3 deletions.
7 changes: 5 additions & 2 deletions gems/sorbet-runtime/lib/types/enum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -273,8 +273,11 @@ def ===(other)

### Private implementation ###

UNSET = T.let(Module.new.freeze, Module)
private_constant :UNSET

sig {params(serialized_val: SerializedVal).void}
def initialize(serialized_val=nil)
def initialize(serialized_val=UNSET)
raise 'T::Enum is abstract' if self.class == T::Enum
if !self.class.started_initializing?
raise "Must instantiate all enum values of #{self.class} inside 'enums do'."
Expand All @@ -300,7 +303,7 @@ def initialize(serialized_val=nil)
sig {params(const_name: Symbol).void}
def _bind_name(const_name)
@const_name = const_name
@serialized_val = const_to_serialized_val(const_name) if @serialized_val.nil?
@serialized_val = const_to_serialized_val(const_name) if @serialized_val.equal?(UNSET)
freeze
end

Expand Down
5 changes: 4 additions & 1 deletion gems/sorbet-runtime/test/types/enum.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class CardSuitCustom < T::Enum
SPADE = new('_spade_')
DIAMOND = new('_diamond_')
HEART = new('_heart_')
NONE = new(nil)
end
end

Expand All @@ -38,6 +39,7 @@ class CardSuitCustom < T::Enum
assert_equal('_spade_', CardSuitCustom::SPADE.serialize)
assert_equal('_diamond_', CardSuitCustom::DIAMOND.serialize)
assert_equal('_heart_', CardSuitCustom::HEART.serialize)
assert_equal(nil, CardSuitCustom::NONE.serialize)
end
end
end
Expand Down Expand Up @@ -361,10 +363,11 @@ class CustomSerializationEnum < T::Enum
enums do
new('foo')
new
new(nil)
end
end
end
assert_equal('Enum values must be assigned to constants: ["foo", nil]', ex.message)
assert_equal('Enum values must be assigned to constants: ["foo", T::Enum::UNSET, nil]', ex.message)
end
end

Expand Down

0 comments on commit bc24d25

Please sign in to comment.