diff --git a/CHANGELOG.md b/CHANGELOG.md index ff45070..91e04fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,6 @@ ### 1.2.1 (Next) +* [#62](https://github.com/dblock/ruby-enum/issues/62): Fixed `values`, `value?` and `key` to not return a superclass' overridden value when a subclass redefines a key, matching the behavior of `to_h` and other methods - [@dblock](https://github.com/dblock). * Your contribution here. ### 1.2.0 (2026/8/14) diff --git a/lib/ruby-enum/enum.rb b/lib/ruby-enum/enum.rb index 70ded84..b9ef27e 100644 --- a/lib/ruby-enum/enum.rb +++ b/lib/ruby-enum/enum.rb @@ -124,15 +124,9 @@ def keys _enum_hash.values.map(&:key) end - # Returns all enum values. + # Returns all enum values, including those defined in a superclass. def values - result = _own_enum_hash.values.map(&:value) - - if superclass < Ruby::Enum - superclass.values + result - else - result - end + _enum_hash.values.map(&:value) end # Iterate over all enumerated values, including those defined in a superclass. @@ -186,12 +180,16 @@ def _enum_hash # Returns the enums-by-value hash for this class merged with all of its # superclasses, with values defined in this class taking precedence over # those inherited from a superclass. + # + # Derived from _enum_hash (keyed by key) rather than merged directly by + # value, so that a superclass' stale value for a key overridden in this + # class doesn't linger, e.g. when a subclass redefines a key with a new + # value, the superclass' old value should no longer be found via value? + # or key. def _enums_by_value - @_enums_by_value ||= if superclass < Ruby::Enum - superclass.send(:_enums_by_value).merge(_own_enums_by_value) - else - _own_enums_by_value - end + @_enums_by_value ||= _enum_hash.each_with_object({}) do |(_key, enum), hash| + hash[enum.value] = enum + end end def upper?(s) diff --git a/spec/ruby-enum/enum_spec.rb b/spec/ruby-enum/enum_spec.rb index dc64fdd..ac7513b 100644 --- a/spec/ruby-enum/enum_spec.rb +++ b/spec/ruby-enum/enum_spec.rb @@ -432,8 +432,15 @@ class EmptyEnums expect(SubclassRedefiningParentKey.to_h).to eq(RED: 'crimson', GREEN: 'green') end - it 'includes both the parent and its own redefined value in values' do - expect(SubclassRedefiningParentKey.values).to eq(%w[red green crimson]) + it "does not include the parent's overridden value, only its own redefined value, in values" do + expect(SubclassRedefiningParentKey.values).to eq(%w[crimson green]) + end + + it "does not recognize the parent's overridden value via value? or key" do + expect(SubclassRedefiningParentKey.value?('red')).to be false + expect(SubclassRedefiningParentKey.key('red')).to be_nil + expect(SubclassRedefiningParentKey.value?('crimson')).to be true + expect(SubclassRedefiningParentKey.key('crimson')).to eq :RED end it "the parent class' own value is unaffected" do