@znz blog

ZnZ の memo のようなもの

Ruby 2.1.1のHash#rejectの不具合対策

| Comments

Ruby 2.1.1 に含まれる Hash#reject の不具合について という話があって、 自分で書くコードでは普通は Hash を継承することはない (is-a にせずに has-a にすることが多い) ので影響はないのですが、 Rails の中の ActiveSupport が影響を受けるということで対処を入れました。

他にもバックポート漏れのコミットをあてた独自ビルドを使うとか、 Ruby 2.1.0 を使う、という対処もあるようです。

Rails の Issue #14188 で話があるようにセキュリティ修正ではないため、 Rails 3.2 系にこの修正は入らないので、 モンキーパッチを入れることにしました。

bugs.ruby-lang.org では https://github.com/ruby/bugs.ruby-lang.org/blob/ro-2-5/lib/redmine/core_ext.rb のように対処していたのを参考にして、 以下のようなコードを config/initializers/hash_reject.rb に置いて対処することにしました。

config/initializers/hash_reject.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# monkey patch for regression of Hash#reject in Ruby 2.1.1
# see https://www.ruby-lang.org/ja/news/2014/03/10/regression-of-hash-reject-in-ruby-2-1-1/
# or https://www.ruby-lang.org/en/news/2014/03/10/regression-of-hash-reject-in-ruby-2-1-1/
require 'active_support/hash_with_indifferent_access'
require 'active_support/ordered_hash'

module ActiveSupport
  class HashWithIndifferentAccess
    def select(*args, &block)
      dup.tap { |hash| hash.select!(*args, &block) }
    end

    def reject(*args, &block)
      dup.tap { |hash| hash.reject!(*args, &block) }
    end
  end

  class OrderedHash
    def select(*args, &block)
      dup.tap { |hash| hash.select!(*args, &block) }
    end

    def reject(*args, &block)
      dup.tap { |hash| hash.reject!(*args, &block) }
    end
  end
end

ここのコードが実行される前に読み込まれていれば問題ないのですが、 ここでクラス定義してしまうと元々の定義が autoload されなくなるので、 念のため require しています。

Comments