使用两个不同范围的方法?

时间:2010-09-11 08:17:43

标签: ruby

如何使用两个不同命名空间中的方法?

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范围。如何从两个范围同时调用方法?

4 个答案:

答案 0 :(得分: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"

答案 1 :(得分: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的类级实例变量,在Bar.configure中使用new(foo)初始化Bar的对象时设置。传递的块假定存在@f,它包含对类Foo的对象的引用。

这是一种令人费解的方式 - 尽管如此,我想不出更好的事情。了解用例会很有趣。

答案 2 :(得分: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

答案 3 :(得分: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功能。