web-dev-qa-db-ja.com

Rubyで 'Monkey Patching'とはどういう意味ですか?

ウィキペディアによると、 monkey patch は次のとおりです。

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

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

Rubyでは、猿パッチという用語はクラスに対する動的な変更を意味するものと誤解されており、実行時にクラスを動的に変更するための同義語としてよく使用されます。

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

class String
  def foo
    "foo"
  end
end
62
Yaser Sulaiman

短い答えは、「正確な」意味はないということです。なぜなら、それは新しい用語であり、異なる人々がそれを異なる方法で使用しているからです。少なくともそれはウィキペディアの記事から識別できます。 「ランタイム」コード(ビルトインクラス、私が思う)にのみ適用されると主張する人もいれば、クラスのランタイム変更を参照するためにそれを使用する人もいます。

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

Rubyでは、猿パッチという用語はクラスに対する動的な変更を意味するものと誤解されており、実行時にクラスを動的に変更するための同義語としてよく使用されます。

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

44
Joshua Swink

モンキーパッチ/ダックパンチングについて聞いた最高の説明は、パトリックユーイングによる RailsConf 2007

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

62
RSK

モンキーパッチは、実行時のクラスのメソッドreplacenot他の人が説明したように新しいメソッドを追加する)です。

コードを変更するための非常に非自明でデバッグが困難な方法であることに加えて、スケールしません。サルのパッチ適用方法を開始するモジュールが増えるにつれて、変更が互いに踏みつけ合う可能性が高まります。

19
Ana Betts

Rubyの最も強力な側面の1つは、クラスを再度開き、そのメソッドを変更する機能です。

はい、そうです。実際にクラスを再開して、動作を変更できます。これには、標準のRubyクラスが含まれます

String, Array or Hash!

今、これは明らかに危険です。メソッドの期待される結果を変更できると、あらゆる種類の奇妙な動作が発生し、バグを追跡するのが難しくなります。

しかし、それでも、クラスを「Monkey Patch」する機能は非常に強力です。 Rubyは鋭利なナイフのようなもので、非常に効果的ですが、通常は自分で切断するのはあなた自身の責任です。

最初に、Lorem Ipsumテキストを生成するための便利なメソッドを追加します。

class String
  def self.lipsum
    "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
  end
end

この例では、Stringコアクラスを再度開き、リップサムクラスメソッドを追加しました。

String.lipsum
=> "Lorem ipsum dolor sit amet, consectetur adipiscing elit."

ただし、コアStringクラスにメソッドを追加できるだけでなく、既存のメソッドの動作を変更することもできます!

class String
  def upcase
    self.reverse
  end
end

この例では、upcaseメソッドをハイジャックし、代わりにreverseメソッドを呼び出しています!

"hello".upcase
=> "olleh"

ご覧のとおり、既存のクラスを所有していない場合やRubyのコアの一部である場合でも、既存のクラスにメソッドを追加または変更するのは非常に簡単です。

Monkey Patchingはいつ使用すべきですか?

まれに。

Rubyは、強力な強力なツールを提供します。ただし、ツールが強力であるという理由だけで、ツールが仕事に適したツールになるわけではありません。

特にモンキーパッチングは非常に強力なツールです。しかし、間違った手で強力なツールを使用すると、無限の痛みと苦痛が生じます。

クラスにモンキーパッチを適用するたびに、将来のある時点で問題が発生したときに頭痛の種になる可能性があります。

Monkey Patchedされたクラスは、理解とデバッグがより困難です。注意を怠ると、表示されるエラーメッセージから、実際に問題が何であるかについてほとんど手掛かりが得られない可能性があります。

メソッドにMonkey Patchを適用すると、その動作に依存しているコードダウンストリームが破壊される可能性があります。

Monkey Patchingを使用して既存のクラスに新しいメソッドを追加すると、予測できない奇妙なEdgeケースを開く可能性があります。

Monkey Patchはいつ大丈夫ですか?

そうは言っても、実際にそれらを使用しなければ、Monkey Patchingのような強力なツールを使用しても意味がありません。

クラスを再度開くことが理にかなっている場合があります。

たとえば、副作用のない便利なメソッドを追加するだけのMonkey Patchesがよく見られます。 Rubyは非常に美しい構文を持っているので、Monkey Patchがクラスをaいメソッド呼び出しをより読みやすいものに変えるように誘惑するかもしれません。

または、所有しているクラスをMonkey Patchする必要があるかもしれません。

Monkey Patchで問題ない場合は多くありますが、最初に選択する武器ではないはずです。

Monkey Patchingは、特定の問題に対して既知のデザインパターンを実際にリファクタリングまたは実装するよりも、怠zyな開発者の好みにすぎないことがよくあります。

Monkey Patchingがあなたに簡単な解決策を提供するからといって、常にその道を進むべきだという意味ではありません。

http://culttt.com/2015/06/17/what-is-monkey-patching-in-Ruby/

6
Subhash Chandra

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

4
davetron5000

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

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

そして、呼び出されたときにのみ時折を壊します。注意を払っている人には、その理由はすでにわかっていますが、.timesクラスメソッドを持つfloat型については知らず、my_special_numberは整数であると自動的に仮定したと想像してください。パラメーターが整数、整数、または浮動小数点数である場合は、常に正常に機能します(浮動小数点の残りがある場合を除き、整数全体が返されます)。しかし、10進数のエリアに何でも入った数字を渡すと、確実に壊れます!

これがあなたのgem、Railsプラグイン、そしてあなたのプロジェクトのあなた自身の同僚によっても起こる頻度を想像してください。このような1つまたは2つの小さな方法があり、見つけて修正する時間です。


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

3
Robert K

In Python monkeypatchingは、恥ずかしさの兆候とよく言われます: "という理由で、このクラスにmonkeypatchしなければなりませんでした..."(Zopeを扱うときに最初に遭遇しました。上流のクラスを保持し、実際のクラスで修正したり、サブクラスで修正したりするためにロビー活動の代わりに実行時に修正する必要があったと言われていました。私の経験ではRubyサルパッチングについては、特に悪いことや注目に値するとは考えられていないので、人々はあまり語りません(「ダックパンチ」)。明らかに、使用されるメソッドの戻り値の変更には注意する必要があります。その他の依存関係、ただしactive_supportとfacetsが行う方法でクラスにメソッドを追加することは完全に安全です。

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

2
method

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

主題のよいフォローアップ:

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

1
maurycy

コードなしの概念の説明:

正確な概念の議論は、必要以上に学術的で微妙すぎます。次の例で簡単にしましょう。

車の通常の操作

普段どのように車を始動しますか?簡単です。イグニッションを回し、車が始動し、レースに出ます。

車にパッチを適用する猿

しかし、他の誰かが車を作った場合、およびその動作を変更したい場合はどうなりますか?

これらの変更を行うために自動車製造工場に行く必要はありません。ボンネットの下に隠れてこっそりとこっそり再配線し、あちこちにいくつかの入in者を追加することにより、単に「猿パッチ」することができます。これを行うときは、自分が何をしているのかを本当に知る必要があります。そうしないと、結果が非​​常に爆発的になります。

ファブリツィオ、どこへ行くの?

ブーム!

Monday, Tuesday, Wed-nes-day, Thursday, Friday, Sat-a-day. Image is free and open source from unsplash - https://unsplash.com/photos/dyrehVIidQk

「ソースコードを近づけてください。ただし、猿のパッチを近づけてください。」

0
BKSpurgeon