2010-09-11 34 views
0

如何使用來自兩個不同名稱空間的方法?使用兩個不同範圍的方法?

class Bar 
    def self.configure &block 
    new.instance_eval &block 
    end 

    def method2 
    puts "from Bar" 
    end 
end 

class Foo 
    def method1 
    puts "from Foo" 
    end 

    def start 
    Bar.configure do 
     method1 
     method2 
    end 
    end 
end 

Foo.new.start 

在上面的示例中,method1不能被調用,因爲它不是從Bar範圍中調用的。如何使兩個範圍的方法可以同時調用?

回答

3

訣竅是缺少轉發方法調用的Foo實例:

class Bar 
    def self.configure(&block) 
     o = new 
     context = eval('self', block.binding) 

     class << o; self; end.send(:define_method, :method_missing) do |meth, *args| 
      context.send(meth, *args) 
     end 

     o.instance_eval &block 
    end 

    def method2 
     puts "from Bar" 
    end 
end 

class Foo 
    def method1 
     puts "from Foo" 
    end 

    def start 
     Bar.configure do 
      method1 
      method2 
     end 
    end 
end 

Foo.new.start #=> "from Foo" 
       #=> "from Bar" 
+0

+1爲context.send技巧。如果Bar也有方法1,這會繼續嗎? – Sudhanshu 2010-09-11 18:53:15

+0

@Sudhanshu,是的,但'Bar'中的'method1'會優先 – horseyguy 2010-09-12 02:19:27

1

試試這個:

class Bar        
    def initialize(foo) 
    puts "init" 
    @f = foo 
    end 

    def self.configure(foo, &block) 
    new(foo).instance_eval &block 
    end 

    def method2 
    puts "from Bar" 
    end 
end 

class Foo 
    def method1 
    puts "from Foo" 
    end 

    def start 
    Bar.configure(self) do 
     @f.method1 
     method2 
    end 
    end 
end 

這使得@f吧,當你初始化酒吧的使用新的(富)在Bar.configure對象被設置的類級實例變量。傳遞的塊假定存在@f,其中包含對Foo類對象的引用。

這是一個複雜的方式 - 我想不出任何更好的東西。知道用例會很有趣。

+0

修復了一個小錯誤。 – Sudhanshu 2010-09-11 08:44:15

1

也許,這是最簡單的方法。它不需要修改Bar。

class Bar 
    def self.configure &block 
    new.instance_eval &block 
    end 

    def method2 
    puts "from Bar" 
    end 
end 

class Foo 
    def method1 
    puts "from Foo" 
    end 

    def start 
    foo = self # add 
    Bar.configure do 
     foo.method1 # modify 
     method2 
    end 
    end 
end 

Foo.new.start 
1

如下我會簡化代碼:

class Bar 
    def self.configure &block 
    obj = new 
    block.call(obj) 
    obj 
    end 

    def method2 
    puts "from Bar" 
    end 
end 

class Foo 
    def method1 
    puts "from Foo" 
    end 

    def start 
    Bar.configure do |obj| 
     method1 
     obj.method2 
    end 
    end 
end 

Foo.new.start 

塊邏輯是乾淨和執行不需要上下文切換。您正在使用將參數傳遞給塊的標準ruby功能。