How to resolve name collision between i18n's Hash#slice and ActiveSupport's Hash#slice

627 views Asked by At

I'm working on a Rails 2.3.14 project, which uses 0.6.0 of the i18n gem and 2.3.14 of the ActiveSupport gem. Both of these define a Hash#slice method (i18n's; ActiveSupport's), but they function differently: the i18n version uses Hash#fetch, and so raises an i18n/core_ext/hash.rb:4:in 'fetch': key not found (IndexError) exception if any requested key is missing, while the ActiveSupport version happily ignores missing keys, and the rest of ActiveSupport depends on that happy ignoring.

In my app, the i18n version is loading first (because, incidentally, faker is loading it as a dependency), so when ActiveSupport tries to depend on the ignore-missing-keys behavior I get the exception.

Is there a way to tell Rails to load ActiveSupport before faker and i18n?

4

There are 4 answers

0
Eugene On BEST ANSWER

You could also monkey patch the Hash class after the gems are required. You could just paste the contents of ActiveSupport's hash/slice.rb into your app somewhere. The URL can be found here:

https://github.com/lifo/docrails/blob/master/activesupport/lib/active_support/core_ext/hash/slice.rb

That would override the definitions from the gems though, so YMMV.

1
TALlama On

I used @Eugene's idea of reverting back to ActiveSupport's method (and so he gets the happy green checkmark), but did it in such as way as to avoid duplicating the code. First we test to see if we're using the i18n version, and if we are we use remove_method to wipe it out (it was added by opening the class) and let the ActiveSupport 2.3.14 module fill in (note I didn't use undef, which also wipes out the module's override).

So into an initializer goes the code:

begin
    {}.slice(:a) # ActiveSupport's slice is fine with this; i18n's is not
rescue IndexError
    class Hash
        remove_method :slice #kill i18n's implementation, allow the ActiveSupport module to work
    end
end
2
ian On

If you can't control the order of loading, you could try the method in this blog post http://banisterfiend.wordpress.com/2010/11/04/baking-module-methods-into-classes-with-alias_method/

I've used it and it worked for me, but that was with modules I'd written myself.

0
Brett On

I've opened an issue on the i18n project to make slice more safe, and created a PR to implement it. You can find the issue / PR at https://github.com/svenfuchs/i18n/pull/292.

To manually patch yourself, you can just add if has_key?(key) after the fetch.