具有自定义定义上下文的instance_eval

时间:2014-01-12 14:35:15

标签: ruby class-eval instance-eval

我试图为现有的lib创建DSL自定义,我对Ruby块上下文有一些误解。

假设我们将一个块保存为proc

some_block = Proc.new do 
   def testing; end
   puts self.inspect
   if self.kind_of? Class 
     puts self.instance_methods.include? :testing
   else
     puts self.methods.include? :testing
   end
   puts self.singleton_class.instance_methods.include? :testing
   implicit_calling_context
end

def implicit_calling_context
  "implicit calling context is definition context"
end

当我们简单地产生一个块时,这个块的自我上下文不会改变

class N
  def some_method
    yield
  end
  def self.implicit_calling_context
    puts "implicit calling context is N"
  end

  def implicit_calling_context
    puts "implicit calling context is N instance"
  end
end

N.new.some_method &some_block
# => main       # block self context stays definition one (closure) 
#    false
#    false
#    implicit calling context is definition context

当我们打电话时

N.class_eval &some_block

# => N         # block self context changed to N
#  true        # block definition context became N
#  false
#  implicit calling context is N

此块中的self变为N,默认的definee保持不变

当我们在实例

上调用instance_eval时
N.new.instance_eval &some_block
# => #<N:0x007fc0422294f8>
#    true
#    true
#    implicit calling context is N instance
some_block中的

自身上下文切换到N实例,但默认的definee变为N个实例元类

有没有方便的方法在实例和代理定义上下文的上下文中产生块?

例如,我有一个Delegator实例,其中包含一些类,我想代理它的定义上下文:

class Definee
end

class MyDelegator < SimpleDelegator
  def work *args
     puts "some additional work"
     __getobj__.work *args
  end
end

MyDelegator.new(Definee).instance_eval do
  work "some base work"
  def test_my_work
     "should be defined on Definee"
  end
end

# I expecting that test_my_work should be defined as Definee instance method
# and :work should be called on MyDelegator.new(Definee) instance
# with "some base work" arg.

所以Definee已经实现了DSL,我用instance_eval覆盖它,但定义上下文不正确。 Class_eval将被委托给Definee,并且不会调用MyDelegator的任何方法,因此它也无法解决问题。

也许有更优雅的方式来做这样的事情。有什么想法吗?

编辑:

解决了我使用继承自Module的类作为委托者来定义上下文切换的问题。

class Definee
end

class MyDelegator < Module
  def initialize definee, &block
    @definee = definee
    self.class_eval &block
    @definee.include self
  end
  def work *args
    puts "some additional work"
    @definee.work *args
  end

  def method_missing *args, &block
    @definee.send *args, &block
  end
end

MyDelegator.new(Definee) do
  work "some base work"
  def test_my_work
     "should be defined on Definee"
  end
end

0 个答案:

没有答案