instance_eval против class_eval в модуле - PullRequest
5 голосов
/ 19 августа 2010
class Foo
    include Module.new { class_eval "def lab; puts 'm' end" }

    def lab
      super 
      puts 'c'
    end
end

Foo.new.lab #=> m c

=============================================================================

class Foo
    include Module.new { instance_eval "def lab; puts 'm' end" }

    def lab
      super 
      puts 'c'
    end
end

Обратите внимание, здесь я изменил class_eval на instance_eval

Foo.new.lab rescue nil#=> no super class method lab
Foo.lab #=> undefined method lab for Foo class

Таким образом, похоже, что включение модуля не определило ни метод экземпляра, ни метод класса.

Любое объяснение, что здесь происходит?

Этот код был протестирован на ruby ​​1.8.7 на mac.

Ответы [ 2 ]

10 голосов
/ 19 августа 2010

Сначала подумайте, что делает include.он делает методы instance модуля включаемыми в методы instance включающего класса.т.е. кроме того факта, что ваш рабочий пример использует анонимный модуль, он эквивалентен:

module M1
  def lab
    puts 'm'
  end
end

class Foo
    include M1

    def lab
      super 
      puts 'c'
    end
end

Далее, подумайте, что делает class_eval.Он оценивает данный код в контексте класса или модуля.то есть, точно так же, как вы снова открыли модуль и набрали код, переданный class_eval.Так что MyModule = Module.new { class_eval "def lab; puts 'm' end" } эквивалентно

module MyModule
  def lab
    puts 'm'
  end
end

Надеюсь, это объясняет, что работает.

Когда вы используете instance_eval, вы оцениваете код в контексте принимающего объекта (вв данном случае это экземпляр модуля), поэтому MyMod2 = Module.new { instance_eval "def lab; puts 'm' end" } эквивалентен

module MyMod2
  def MyMod2.lab
    puts 'm'
  end
end

, т. е. он создает метод module , который вы вызываете через MyMod2.lab, и такие методы не добавляютсякак методы экземпляра от include.


Обратите внимание : этот ответ заимствует часть своего объяснения из ответа, который я написал на предыдущий вопрос о instance_eval vsclass_eval , относящийся к примеру из Ruby Programming Language book.Вам также может пригодиться этот ответ.

3 голосов
/ 19 августа 2010

, включая модуль, принимает только методы экземпляра - вы ищете для расширения.к счастью, чтобы получить лучшее из обоих миров, вы можете просто сделать:

module Something
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    def blah
      puts "lol"
    end
  end
end

class Test
  include Something
end 

irb:

>> Test.blah
lol
=> nil
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...