9

私はまだ Ruby を使い始めたばかりで、基本的に Cooper の本を読み終わった後、最初のマイクロプログラムを書いたところです。私はサルのパッチを避ける方向を指摘されましたが、問題は、同じ動作を実現するための代替手段がわからないことです。基本的に、すべての文字列オブジェクトからアクセスできる新しいメソッドを追加したいと考えています。明らかなモンキーパッチの方法は次のとおりです。

class String
  def do_magic
    ...magic...
  end
end

String.send を使用する方法があることを思い出します。しかし、それがどのように行われたのか、どこで読んだのか思い出せません。そのメソッドを String クラスと子オブジェクトで使用できるようにする代替手段を誰か指摘できますか?

4

6 に答える 6

15

これを行う他の方法は、サルのパッチを適用するためのより扱いにくい構文になります。sendandを含むさまざまな方法がありますがevalなぜですか? 先に進んで、それを明白な方法で行ってください。

大規模なプロジェクトや依存関係がある場合は、モンキー パッチに注意する必要があります。複数の手が同じ場所をいじると、競合が発生する可能性があるからです。これは、同じことを実現する別の構文を探すという意味ではありません。つまり、自分のものではないコードに影響を与える可能性のある変更を行うときは注意する必要があるということです。これはおそらく、特定のケースでは問題になりません。これは、大規模なプロジェクトで対処する必要があるかもしれないものです。

Ruby での 1 つの代替方法は、単一のオブジェクトにメソッドを追加できることです。

a = "Hello"
b = "Goodbye"
class <<a
  def to_slang
    "yo"
  end
end
a.to_slang # => "yo"
b.to_slang # NoMethodError: undefined method `to_slang' for "Goodbye":String
于 2009-03-29T22:28:48.180 に答える
6

すべての文字列オブジェクトにアクセスできる新しいメソッドを追加したい場合は、今までの方法でそれを行うことが、それを実現する方法です。

コア オブジェクトの拡張機能を別のファイル ( など) またはサブディレクトリ ( や など) に配置することをお勧めしstring_ex.rbます。このようにして、何が拡張されたかが明確になり、誰かがどのように拡張または変更されたかを簡単に確認できます。extensionscore_ext

モンキー パッチがうまくいかないのは、コア オブジェクトの既存の動作を変更して、元の機能が正しく動作しないことを予期している他のコードを引き起こす場合です。

于 2009-03-30T05:04:30.413 に答える
2

objectクラスは を定義し、すべてのオブジェクトはこれsendを継承します。オブジェクトをsendメソッドに「送信」します。メソッドのsendパラメーターは、呼び出したいメソッドの名前のシンボルであり、その後に任意の引数とオプションのブロックが続きます。も使用できます__send__

>> "heya".send :reverse
=> "ayeh"

>> space = %w( moon star sun galaxy )
>> space.send(:collect) { |el| el.send :upcase! }
=> ["MOON", "STAR", "SUN", "GALAXY"]

編集..

define_methodおそらく次のメソッドを使用したいと思うでしょう:

String.class_eval {
  define_method :hello do |name|
    self.gsub(/(\w+)/,'hello') + " #{name}"
  end
}

puts "Once upon a time".hello("Dylan")
# >> hello hello hello hello Dylan

これにより、インスタンス メソッドが追加されます。クラスメソッドを追加するには:

eigenclass = class << String; self; end
eigenclass.class_eval {
  define_method :hello do
    "hello"
  end
}

puts String.hello
# >> hello

ただし、ブロックを期待するメソッドを定義することはできません。

Why's Poignant Guide からこの章を読むのは良いことかもしれません。「Dwemthy's Array」までスキップして、メタプログラミングの内容に進むことができます。

于 2009-03-29T22:56:09.207 に答える
1

みんなありがとう。

提案されたすべての実装作業。さらに重要なことに、私は手元にあるケースを検討し、コア(またはライブラリ)クラスを再度開くことが良い考えかどうかを判断することを学びました。

sendFWIW、友人は私が探していた実装を指摘しました。しかし、今私がそれを見ると、それは他のすべての実装よりもモンキーパッチにさらに近いです:)

module M
    def do_magic
    ....
    end
end
String.send(:include, M)
于 2009-03-30T18:49:34.610 に答える
0

あなたが説明する「モンキーパッチ」は、他の誰かがあなたのコードを要求したい場合(たとえば、宝石として)、実際に問題になる可能性があります。do_magic と呼ばれる String メソッドも追加したくないと誰が言えますか? 1 つのメソッドが他のメソッドを上書きするため、デバッグが困難になる可能性があります。コードがオープン ソースになる可能性がある場合は、独自のクラスを作成することをお勧めします。

class MyString < String
  def initialize(str)
    @str = str
  end
  def do_magic
    ...magic done on @str
    @str
  end
end

do_magic が必要な場合は、次のことができます。

magic_str = MyString.new(str).do_magic
于 2016-04-06T22:18:08.087 に答える