70

ウィキペディアによると、モンキー パッチは次のとおりです。

元のソース コードを変更せずに、動的言語のランタイム コードを拡張または変更する方法 [...]。

同じエントリからの次のステートメントは、私を混乱させました。

Ruby では、モンキー パッチという用語は、クラスへの動的な変更を意味すると誤解されており、実行時に任意のクラスを動的に変更することの同義語としてよく使用されます。

Rubyでのモンキーパッチの正確な意味を知りたいです。次のようなことをしていますか、それとも別のことですか?

class String
  def foo
    "foo"
  end
end
4

8 に答える 8

65

モンキーパッチ/ダックパンチについて聞いた最も良い説明は、RailsConf2007のPatrickEwingによるものです。

...それがアヒルのように歩き、アヒルのように話すなら、それはアヒルですよね?したがって、このアヒルがあなたが望むノイズを与えていない場合、あなたはそれがあなたが期待するものを返すまでそのアヒルをパンチする必要があります。

于 2011-08-18T17:41:36.510 に答える
49

簡単に言うと、「正確な」意味はありません。これは新しい用語であり、人によって使い方が異なるためです。少なくともそれは、ウィキペディアの記事から識別できます。「ランタイム」コード (おそらく組み込みクラス) にのみ適用されると主張する人もいれば、任意のクラスのランタイム変更を参照するために使用する人もいます。

個人的には、より包括的な定義を好みます。結局のところ、組み込みクラスの変更のみにこの用語を使用する場合、他のすべてのクラスの実行時の変更をどのように参照するのでしょうか? 私にとって重要なことは、ソース コードと実際に実行されているクラスには違いがあるということです。

Ruby では、モンキー パッチという用語は、クラスへの動的な変更を意味すると誤解されており、実行時に任意のクラスを動的に変更することの同義語としてよく使用されます。

上記のステートメントは、Ruby の使用法が正しくないと主張していますが、用語は進化しており、それは必ずしも悪いことではありません。

于 2008-12-26T19:58:57.853 に答える
21

モンキーパッチは、実行時にクラスのメソッドを置き換えるときです(他の人が説明したように新しいメソッドを追加するのではありません)。

コードを変更する方法が非常に目立たず、デバッグが困難であることに加えて、拡張性がありません。モンキー パッチ手法を開始するモジュールが増えるにつれて、変更が互いに衝突する可能性が高くなります。

于 2008-12-26T20:06:09.850 に答える
4

これはモンキーパッチです:

class Float
  def self.times(&block)
    self.to_i.times { |i| yield(i) }
    remainder = self - self.to_i
    yield(remainder) if remainder > 0.0
  end
end

これは時々役立つかもしれないと思いますが、ルーチンを見たら想像してみてください。

def my_method(my_special_number)
  sum = 0
  my_special_number.times { |num| sum << some_val ** num }
  sum
end

そして、呼び出されたときにたまにしか壊れません。注意を払っている人には、すでに理由はわかっていますが、float 型に class-method があることを知らず、それが整数.timesであると自動的に仮定したと想像してください。my_special_numberパラメータが整数、整数、または浮動小数の場合はいつでも、正常に機能します (浮動小数点の剰余がある場合を除き、整数全体が返されます)。しかし、小数領域に何かを含む数値を渡すと、確実に壊れます!

あなたの gem、Rails プラグイン、さらにはプロジェクトの同僚によってさえ、これがどのくらいの頻度で発生するか想像してみてください。このような小さなメソッドが 1 つまたは 2 つあると、見つけて修正するのに時間がかかる場合があります。


なぜ壊れるのか疑問に思う場合sumは、 が整数であり、浮動小数点の剰余が返される可能性があることに注意してください。さらに、指数記号は型が同じ場合にのみ機能します。面倒な数値を浮動小数点数に変換したため、修正されたと思うかもしれません...合計が浮動小数点の結果を取得できないことがわかりました。

于 2008-12-26T19:34:53.267 に答える
4

あなたは正しいです; サブクラス化するのではなく、既存のクラスを変更または拡張する場合です。

于 2008-12-26T19:34:58.883 に答える
3

Pythonでは、モンキーパッチは困惑の兆候とよく呼ばれます。「このクラスをモンキーパッチしなければならなかったのは...」(記事に記載されているZopeを扱っているときに最初に遭遇しました)。これは、実際のクラスで不要な動作を修正したり、サブクラスで修正したりするためにロビー活動を行うのではなく、アップストリームクラスを取得して実行時に修正する必要があると言っていました。私の経験では、Rubyの人々はモンキーパッチについてあまり話しません。なぜなら、モンキーパッチは特に悪いとか、注目に値するものとは見なされていないからです(したがって「アヒルのパンチ」)。明らかに、他の依存関係で使用されるメソッドの戻り値の変更には注意する必要がありますが、active_supportとfacetsが行う方法でクラスにメソッドを追加することは完全に安全です。

10年後の更新:最後の文を「比較的安全」と修正します。コアライブラリクラスを新しいメソッドで拡張すると、他の誰かが同じアイデアを取得して同じメソッドを異なる実装またはメソッドシグネチャで追加した場合、または拡張メソッドをコア言語機能と混同した場合に問題が発生する可能性があります。どちらの場合も、Rubyでよく発生します(特にactive_supportメソッドに関して)。

于 2008-12-26T23:31:37.457 に答える
1

通常は、Ruby オープン クラスを使用し、低品質のコードを頻繁に使用するアドホックな変更を意味します。

この件に関する良いフォローアップ:

http://www.infoq.com/articles/ruby-open-classes-monkeypatching

于 2008-12-26T19:57:08.917 に答える