代码之家  ›  专栏  ›  技术社区  ›  Eli

将方法包含到块中

  •  2
  • Eli  · 技术社区  · 15 年前

    如果可能的话,有人知道怎么让它工作吗?

    class Foo
      def self.go(&block)
        class << block
          include Bar
        end    
        puts "Within Foo#go: #{block.methods.include? 'baz'}"
        block.call
      end
    end
    
    module Bar
      def baz
        puts "I'm happily in my place!"
      end
    end
    
    Foo.go { 
      puts "Within actual block: #{methods.include? 'baz'}"
      baz
    }
    

    这将获得输出:

    Within Foo#go: true
    Within actual block: false
    NameError: undefined local variable or method ‘baz’ for main:Object
    

    编辑:当我在foo go中打印出块的类时,它是proc,但是当我在proc中打印出来时,它是object。这有关系吗?

    3 回复  |  直到 11 年前
        1
  •  3
  •   Chuck    15 年前

    你不能这么做。你看到的原因是这里有两种不同的背景。一个是块的上下文,它 closes over 定义它的上下文。另一个是proc对象包装器的上下文,它与任何其他对象上下文相同,并且与块本身的上下文完全无关。

    我想你最接近的是 instance_eval 使用具有所需方法的上下文对象的块,但该块将无法访问 self 存在于它被定义的地方。这取决于你想写的方法是否合理。

    另一种选择是向块传递 baz 方法。

        2
  •  3
  •   rampion    11 年前

    你可以用 eval 具有 Proc#binding :

    module Bar
      def baz
        puts "hi from baz!"
      end
    end
    def go(&block)
      eval('include Bar', block.binding)
      block[]
    end
    
    baz #=> NameError
    go { baz } #=> "hi from baz!"
    baz #=> "hi from baz!"
    

    但是,除非使用mixin/mixout框架(如mixico或mixology),否则将把包含模块中的方法放入词法作用域中,这样在块返回后它们仍然可以访问。

    require 'rubygems'
    require 'mixico'
    
    module Bar
      def baz
        puts "hi from baz!"
      end
    end
    def go(&block)
      Module.mix_eval(Bar, &block)
    end
    
    baz #=> NameError
    go { baz } #=> "hi from baz!"
    baz #=> NameError
    

    Here 这是一篇关于从块中使用DSL的不同方法的好文章。

        3
  •  2
  •   horseyguy    15 年前

    另一种选择是,从rampion开始,在混合到块之前复制块的上下文,这样你就不会在完成后弄乱上下文。

    module Bar
      def baz
        puts "hi from baz!"
      end
    end
    def go(&block)
      dup_context = eval('self', block.binding).dup
      dup_context.send(:include, Bar)
      dup_context.instance_eval &block
    end
    

    注意,只有在块中没有运行任何mutator方法时,这才对您有用

    推荐文章