`instance_eval`和范围

时间:2015-01-29 18:09:22

标签: ruby eval instance-eval

我有以下代码:

class A
  def self.scope
    yield
  end
  def self.method_added method
    self.instance_eval %{
      # do something involving the added method 
    }
  end
end

class B < A
  scope do 
    def foo
    end
  end
end

method_added挂钩被触发时,instance_eval内的代码是否会在与添加的方法相同的范围内运行?或者,它会在它之外运行吗?

这涉及到什么警告和陷阱?

2 个答案:

答案 0 :(得分:1)

让我们找出来!

class A
  def self.scope
    yield
  end
  def self.method_added method
    puts "In method_added, method = #{method}, self = #{self}" 
    instance_eval 'puts "In instance_eval, method = #{method}, self = #{self}"'
  end
end

class B < A
  scope do
    puts "In scope's block, self = #{self}" 
    def foo
    end
  end
end

  # In scope's block, self = B
  # In method_added, method = foo, self = B
  # In instance_eval, method = foo, self = B

请注意,self.中不需要self.instance_eval

答案 1 :(得分:1)

您的scope方法基本上是无操作。将块传递给产生的方法时,将在当前范围内计算块。观察:

class A
  def self.scope
    yield
  end
end

A.scope { p self }
# main

由于没有对块进行任何操作,并且没有对yield的返回值进行任何操作,因此块中运行的任何代码都将在scope块之外运行。

instance_eval不是这种情况。当instance_eval运行一个块时,块中的self被设置为接收器(而不是块的范围内的self)。像这样:

class A
end

A.instance_eval { p self }
# A

但请注意,这意味着self.instance_eval { ... }也是一个奇特的无操作,因为您正在将块self更改为块外的同一self

所以你的代码等同于:

class A
  def self.method_added method
    # do something involving the added method 
  end
end

class B < A
  def foo
  end
end