Классы Ruby, include и scope - PullRequest
       17

Классы Ruby, include и scope

1 голос
/ 26 сентября 2011

Как включение модуля влияет на область действия? В частности, в этом примере:

module ModuleA
  class ClassA
    def initialize
      puts "test passed"
    end
  end
end

module ModuleB
  include ModuleA

  # test 1
  C = ClassA.new

  class ClassB
    def initialize
      c = ClassA.new
    end
  end
end

# test 2 and 3 fail without this
#include ModuleB

module ModuleC
  # this doesn't help
  include ModuleB

  # test 2
  ClassB.new

  # test 3
  ModuleB::ClassB.new
end

тест 1 работает нормально, но тест 2 и тест 3 завершаются неудачно без закомментированного import ModuleB.

  • Почему ClassA находится в области видимости внутри ModuleB (тест 1), а не в ClassB?
  • Почему import ModuleB приносит ClassA в область действия ClassB?

Ответы [ 2 ]

7 голосов
/ 26 сентября 2011

Ключевые слова class , module и def - это так называемые "области видимости". Они создают новые возможности.

#!/usr/bin/env ruby

module ModuleA
  class ClassA
    def initialize
      puts "test passed"
    end
  end
end

module ModuleB
  include ModuleA

  # test 1
  c = ClassA.new  # this works as ModuleA has been included into this module

  class ClassB  # class is a scope gate, creates new scope
    def initialize  # def is a scope gate, creates new scope
      c = ModuleA::ClassA.new  # must fully qualify ClassA
    end
  end

  ClassB2 = Class.new do  # no scope gate
    define_method :initialize do # no scope gate
      c = ClassA.new  # this works, no need to fully qualify
    end
  end
end

b = ModuleB::ClassB.new
b2 = ModuleB::ClassB2.new

Я начал понимать области действия в Ruby после прочтения книги "Метапрограммирование Ruby" . Это действительно поучительно.

Редактировать : В ответ на комментарий ниже.

Класс - это, по сути, константа Ruby (обратите внимание, что это объект с заглавным именем). Константы имеют определенный алгоритм поиска в пределах области видимости. Язык программирования Ruby Книга О'Рейли хорошо объясняет это в разделе 7.9. Это также кратко описано в этом сообщении в блоге .

Константы верхнего уровня, определенные вне какого-либо класса или модуля, похожи на методы верхнего уровня: они неявно определены в Object. Когда на константу верхнего уровня ссылаются из класса, она разрешается во время поиска иерархии наследования. Если на константу ссылаются в определении модуля, она выполняет явную проверку объекта после поиска предков модуля.

Именно поэтому включение ModuleB на верхнем уровне делает класс в ModuleB видимым во всех модулях, классах и методах.

0 голосов
/ 26 сентября 2011

Причина (я думаю) связана с привязками. Подсказка для меня заключается в том, что следующее также не будет работать:

module ModuleB
 include ModuleA

 class ClassB
  def initialize
   c = ClassA.new
  end
 end

 ClassB.new
end

ClassA ничего не значит в определении ClassB, потому что это не константа в ClassB - модуль был включен только в его родительский модуль. Внесение этого изменения должно заставить все работать:

module ModuleB
  include ModuleA
  class ClassB
    def initialize
      c = ModuleA::ClassA.new
    end
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...