diff --git a/lib/enumerize/attribute.rb b/lib/enumerize/attribute.rb index b22bb7c..4790875 100644 --- a/lib/enumerize/attribute.rb +++ b/lib/enumerize/attribute.rb @@ -18,8 +18,12 @@ def initialize(klass, name, options={}) value_class = options.fetch(:value_class, Value) @values = Array(options[:in]).map { |v| value_class.new(self, *v).freeze } - @value_hash = Hash[@values.map { |v| [v.value.to_s, v] }] - @value_hash.merge! Hash[@values.map { |v| [v.to_s, v] }] + # Two passes (value keys first, then name keys) so that name keys win on + # collision, matching the previous Hash#merge! behavior, without building + # the intermediate arrays and hashes that merge! required. + @value_hash = {} + @values.each { |v| @value_hash[v.value.to_s] = v } + @values.each { |v| @value_hash[v.to_s] = v } if options[:default] @default_value = find_default_value(options[:default]) diff --git a/lib/enumerize/value.rb b/lib/enumerize/value.rb index a9672fc..a49c266 100644 --- a/lib/enumerize/value.rb +++ b/lib/enumerize/value.rb @@ -11,7 +11,11 @@ class Value < String def initialize(attr, name, value=nil) @attr = attr - @value = value.nil? ? name.to_s : value + # Deduplicate the frozen string for plain-symbol enums so every value + # named e.g. "active" across the whole app shares one String object. It + # stays a plain (non-Value) String, so it's still safe to feed to + # write_attribute and friends. + @value = value.nil? ? -name.to_s : value super(name.to_s)