`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 выполняться в той же области видимости, что и добавленный метод? Или он будет работать вне его?

Каковы предостережения и подводные камни, связанные с этим?


person Thermatix    schedule 29.01.2015    source источник
comment
хм, моя проблема частично решена, все же я хотел бы знать, что люди могут сказать в любом случае   -  person Thermatix    schedule 29.01.2015


Ответы (2)


Ваш метод 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
person Max    schedule 29.01.2015
comment
что значит "нет операции"? - person Thermatix; 30.01.2015
comment
Это сокращение от «нет операции», что означает инструкцию программирования, которая ничего не делает. - person Max; 30.01.2015

Давай выясним!

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.

person Cary Swoveland    schedule 29.01.2015