hashie/hashie

Missing roundtrip methods

chocolateboy opened this issue · 3 comments

Several Hash methods in Ruby's standard library return a hash. As expected, many of these methods roundtrip in the same way when called on hashes with Hashie extensions i.e. they return a hash with the same type and behavior as the receiver.

class HashieTest < Hash                                                               
  include Hashie::Extensions::IndifferentAccess                                     
  include Hashie::Extensions::MergeInitializer                                      
end

puts HashieTest.new(foo: "bar").merge(baz: "quux").class # => HashieTest
puts HashieTest.new(foo: "bar").clear.class # => HashieTest
puts HashieTest.new(foo: "bar").replace({}).class # => HashieTest

But I've just noticed that slice doesn't behave in this way e.g.:

puts HashieTest.new(foo: "bar").slice(:foo).class # => Hash

And in fact there are several methods which return a plain Hash rather than an extended Hash:

  • compact
  • invert
  • reject
  • select
  • slice
  • transform_keys
  • transform_values
  • update

Makes sense, please PR!

This is due to Hash#slice being implemented in C, specifically that it creates the new hash with the C function rb_hash_new() or rb_hash_new_with_size(). Please see my talk at RubyConf 2018 for more information as to why this happens.

It's not clear how we could handle this. In this specific case, with Hash#slice, we could override the method to make sure the new Hash is of the same singleton class as the generator, but I'm not really sure what that would look like. Would every extension have to implement #slice in the same way? That's the only thing I can think of.

Closed via #481