4

タイトルが示すように、あるクラスで定義されたすべてのインスタンス メソッドを別のクラスに割り当てたいと考えています。ClassA次のように、コピー元のメソッドのリストを取得できることを知っていますClassB

ClassA.instance_methods(false)

そして、私はそれらを次のように定義できると思いますClassB:

ClassA.instance_methods(false).each do |method_name|
  ClassB.method_define(method_name, [body here??])
end

対応するメソッド本体を取得する方法はありますか?もしそうなら、このメソッドは機能しますか? そうでない場合、これを行う方法はありますか?

4

4 に答える 4

10

他の人はすでにサブクラス化するように言っています。しかし、あなたの文字通りの質問に答えるために、私たちはUnboundMethodオブジェクトに関与することになります:

class Object
  def kokot; 'kokot' end
end

o = Object.new
o.kokot
#=> kokot

3.kokot
#=> kokot

ここまでは順調ですね。kokot次に、メソッドを再定義しましょうNumeric:

class Numeric
  def kokot; 'pica' end
end

o.kokot
#=> kokot
3.kokot
#=> pica

kokotしかし、その新しい方法は数値には優れているが、複素数だけは古いkokot方法を使用し続ける必要があると判断した場合はどうなるでしょうか。次のように実行できます。

um = Object.instance_method :kokot
#=> #<UnboundMethod: Object#kokot>
Complex( 2, 3 ).kokot # gives the redefined kokot method
#=> pica
Complex.module_exec { define_method :kokot, um }
# Now we've just bound the old kokot to Complex
Complex( 2, 3 ).kokot
#=> kokot

つまり、関連するクラス間でメソッドを「コピー アンド ペースト」する方法があります。ターゲットは、バインドされていないメソッド ソースのサブクラスである必要があります。メソッドが定義されている#source_locationファイルと行を示します。#kokot

um.source_location
#=> ["(irb)", 2]

組み込みメソッドの場合、 を#source_location返しますnil。Ruby 2.0 では、RubyVMクラスにはメソッドがあり#disassembleます。

RubyVM::InstructionSequence.disassemble( um )
#=> ( program listing goes here )

いずれにせよ、Ruby のバイトコードはそれほど美しくありません。元のニーズに戻ると、メソッドを互換性のないオブジェクトにバインドすることさえでき#define_methodません。UnboundMethod#bindこれは、再定義などのトリックでごまかすことはできません#kind_of?。ネイティブ コードで CLASS_OF() 関数をごまかす必要があります...

利用可能な gem のうち、SourcifyRubyParser、およびSorcererが興味深いものです。(ありがとう、@Casper。)これらを使用すると、理論的には、#eval抽出されたメソッドソースを介して互換性のないオブジェクト間でコードを移植できます。長い道のりですが、実行時にソースが利用できない場合 (自己変更ソースなど) は常に失敗するため、この手法は実現可能なメソッド転送にはまだ不十分です。

于 2013-01-03T06:16:52.677 に答える
3

あなたが望むのはミックスインのようです:

http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_modules.htmlから取得

module Debug
  def whoAmI?
    "#{self.type.name} (\##{self.id}): #{self.to_s}"
  end
end
class Phonograph
  include Debug
  # ...
end
class EightTrack
  include Debug
  # ...
end
ph = Phonograph.new("West End Blues")
et = EightTrack.new("Surrealistic Pillow")
ph.whoAmI?  »   "Phonograph (#537766170): West End Blues"
et.whoAmI?  »   "EightTrack (#537765860): Surrealistic Pillow"
于 2013-01-03T04:45:55.350 に答える
0

その場合、classB継承する必要がありclassAます。

于 2013-01-03T04:55:45.523 に答える