Почему я получаю сообщение об ошибке, пытаясь сослаться на вложенный класс в Ruby? - PullRequest
1 голос
/ 22 июля 2010

Почему в следующем примере возникает ошибка?

class ClassA
  class ClassB
  end
  class ClassC
    def test
      ClassB.new
    end
  end
end

p ClassA::ClassC.new.test # => #<ClassA::ClassB:0x0000010103f860>

class ClassA
  class ClassD
    def test
      ClassB.new
    end
  end
end

p ClassA::ClassD.new.test # => #<ClassA::ClassB:0x0000010103f010>

class ClassA::ClassE
  def test
    ClassB.new
  end
end

p ClassA::ClassE.new.test # => NameError: uninitialized constant ClassA::ClassE::ClassB

Есть ли другой способ создать ClassE, не набрав class ClassA; class ClassE?

Ответы [ 2 ]

1 голос
/ 23 июля 2010

Что ж, да, если вы определите свой метод тестирования для возврата ClassA::ClassB.new: -)

Вы также можете поиграть с const_missing, чтобы он вызывал ClassA.const_get.

В противном случае ClassB не входит в текущую область, которая на данный момент составляет только ClassA::ClassE и Object. Когда вы сначала открываете ClassA, затем ClassE, поиск для ClassB выполняется сначала в ClassA::ClassE, затем в ClassA (где он найден), а также будет выглядеть в Object.

0 голосов
/ 23 июля 2010

Пользовательский метод Object#const_missing, предложенный Марк-Андре Лафортун , будет тогда

def Object.const_missing(name)
  @looked_for ||= {}
  key = self.to_s + '~' + name.to_s
  raise "Class not found: #{name}" if @looked_for[key] == key
  return @looked_for[key] if @looked_for[key]
  @looked_for[key] = key
  if self.to_s.include? '::'
    klass = Object
    self.to_s.split('::')[0..-2].each do |klass_string|
      klass = klass.const_get klass_string
    end
    return @looked_for[key] = klass.const_get(name) if klass # klass.is_a?(Class)
  end
  raise "Class not found: #{name}"
end

Некоторые связанные вопросы:

  1. Предоставляет ли Ruby путь к пространству имен, например, что-то вроде [: A,: B] для класса A :: B :: C?
  2. Если я определю метод класса в Ruby Objectкласс, как я могу получить имя дочернего класса, вызывающего этот метод?
  3. Как мне получить объект класса из строки «A :: B :: C» в Ruby?
...