2011-11-10 5 views
2

ミックスインを使用してクラスに追加できるメソッドのセット(この例ではC)を定義します。これらのメソッドは、別のクラス(この例ではA)から継承し、受信側インスタンス(Cインスタンス)でメソッドを呼び出すことができるすべてのクラスによって定義できます。別のクラスに呼び出すことができるメソッドセットを使ってミックスインを作成する

私はこのコードのスニペットを持っている:

M = Module.new 

class A 
    class << self 
    def init(method) 
     if block_given? 
     M.send(:define_method, method) do 
      instance_exec &Proc.new 
     end 
     else 
     block = self.method(method).to_proc 
     M.send(:define_method, method) do 
      yield block.call 
     end 
     end 
    end 
    end 
end 

class B < A 
    init(:foo) do 
    "foo+".concat(c_method) 
    end 

    def self.bar 
    "bar+".concat(c_method) 
    end 

    init(:bar) 
end 

C = Class.new do 
    def c_method 
    "c_method" 
    end 
end 

c = C.new 

c.extend(M) 

puts c.foo 

puts c.bar 

は、ブロックの作品を使用してメソッドを追加するが、最後の行が失敗した:(

foo+c_method 
test.rb:28:in `bar': undefined local variable or method `c_method' for B:Class (NameError) 
from test.rb:15:in `call' 
from test.rb:15:in `block in init' 
from test.rb:46:in `<main>' 

私が間違って何をやってるか、これは意味がありませんか?

おかげ

フアン

答えて

1

ifステートメント内にinstance_exec &Proc.newを準備すると、このステートメントはコンテキストとしてCクラスのインスタンス内で実行されます。 init(:foo)のブロック内にputs selfを追加して確認できます。 一方、yield block.callを呼び出すと、Bクラスオブジェクト(このクラスのインスタンスではありません:)のコンテキストにスレッド実行が生成されます)。あなたのコードのこの場所はC :: c_methodについて何も知らず、これがエラーの原因です。

+0

です。正しいですか。私はBからメソッドをバインドしてCにバインドしようとしましたが、それは動作しません。私は私の質問に答えようとしていましたが、私には特権がありません。数時間待つことはできません:) [このリンクはこの問題について説明しています](http://ruby-metaprogramming.rubylearning.com/yugui_blog_translation_1.html) – juandebravo

0

私がしようとしているのは、メソッドをバインド解除することです:BからのバーとCへのバインド、それは許可されていません。詳細はthis great post

M = Module.new 

class A 
    class << self 
    def init(method) 
     if block_given? 
     M.send(:define_method, method) do 
      instance_exec &Proc.new 
     end 
     else 
     block = self.method(method).unbind 
     M.send(:define_method, method) do 
      m = block.bind(self) 
      puts m 
     end 
     end 
    end 
    end 
end 

class B < A 
    init(:foo) do 
    "foo+".concat(c_method) 
    end 

    def self.bar 
    "bar+".concat(c_method) 
    end 

    init(:bar) 
end 

C = Class.new do 
    def c_method 
    "c_method" 
    end 
end 

c = C.new 

c.extend(M) 

puts c.foo 

puts c.bar 

foo+c_method 
test.rb:16:in `bind': singleton method called for a different object (TypeError) 
from test.rb:16:in `block in init' 
from test.rb:48:in `<main>' 
関連する問題