RubyのMonkeypatchとは?
身近な言葉のモンキー・パンチ、ではなく、パッチですね。
MonkeypatchはRubyでクラス・モジュールを開いて、その一部・もしくは全部を書き換えるということです。
Rubyの最大の魅力点でもありながら、あまりやらない方がいいとも言われています。
実はRailsに入っているActiveSupportというものがあって、その中にはMonkeypatchがいっぱい集まっています。
Twitter上でこれがいいことかどうかについて時々炎上しています。
Stringクラスで簡単な例
class String
def neko
replace "cat"
end
end
cat = "neko"
cat.neko
cat
# => "cat"
module CatHelper
def neko
replace "neko"
end
end
String.prepend CatHelper
cat = "neko"
cat.neko
cat
# => "neko"
# String.include での結果も試してみて!
なので、安全にモンキーパッチングを楽しみましょう!
Monkeypatchを利用した時の話
さきほど翻訳機能をStringに入れるGem, sampokuokkanen/ActiveTranslateSelfにI18nバックエンドとしてDBを使っている場合、
翻訳がない場合は自動的に翻訳するという機能です。パッチででこのGemの中のメソッドを変えたかったです。
最初は以下のような感じで書こうと思っていました:
module I18n
module Backend
class ActiveRecord
module Missing
def store_default_translation(locale, key, interpolations)
translation = ActiveRecord::Translation.new locale: locale.to_s, key: key
default = I18n.t(key, locale: I18n.default_locale
translation.value = default.public_send "to_#{locale}" if default.respond_to?("to_#{locale}")
translation.interpolations = interpolations
translation.save
end
end
end
end
end
ただ、これだと結構見にくいですし、フォルダー構成も結構奥まってしまいますし、あまりキレイではないです。
余談ですが、
Railsの中だとActiveRecordはモジュールとして定義されていて、ここだとクラス、ということでもZeitwerkに怒られていましたが。¥
どうやってもっとキレイに書けるかというと、prepend
を使います。
(今まで正直あまりprepend
使ってなかったです)
モジュールを呼び出す前に、モジュールの中を一部差し替えたいので、こちらのパッチは以下のように定義します:
module ActiveTranslateSelf
module Missing
def store_default_translation(locale, key, interpolations)
translation = I18n::Backend::ActiveRecord::Translation.new locale: locale.to_s, key: key
# デフォルトに設定されている言語の翻訳から訳します
default = I18n.t(key, locale: I18n.default_locale)
# ここで実際に値を訳しています
translation.value = default.public_send "to_#{locale}" if default.respond_to?("to_#{locale}")
translation.interpolations = interpolations
translation.save
end
end
end
ネームスペースも自分のGem配下になっていて、かなりわかりやすいかと思います。
では、実際にパッチを適用しましょう!
I18n::Backend::ActiveRecord::Missing.prepend ActiveTranslateSelf::Missing
I18n::Backend::Simple.include I18n::Backend::ActiveRecord::Missing
prepend
使っているので、どの段階でどこが変わっているのがわかりやすいかと思います。
面白いので仕事のRailsアプリでも活用しよう!・・・というわけにはいかない
結構責任も問いますので、普通にRailsをやている時はほとんど必要になることはないかと思います。
Gemアップデートの時に壊れやすくもなりますので、あまり使いたくいないです。
他にやり方があれば、Monkeypatchは避けましょう!
誘惑に負けないことです!