Instance_eval не имеет доступа к классу в модуле

Я столкнулся с проблемой с instance_eval и включением модуля.

Пожалуйста, взгляните на следующий код:


module B
  class C
    def initialize
      puts 'This is C'
    end
  end

  def hello
    puts 'hello'
  end
end

class A
  include B

  def initialize(&block)
    hello
    C.new
    instance_eval(&block)
  end
end

A.new do
  hello
  C.new
end

Когда я запускаю этот код, я получаю


hello
This is C
hello
-:25:in `block in ': uninitialized constant C (NameError)
    from -:19:in `instance_eval'
    from -:19:in `initialize'
    from -:23:in `new'
    from -:23:in `'

Я понимаю, что это связано с привязками и тем, как методы и объекты привязаны к классу. Чего я не могу понять, так это того, почему у меня есть доступ к C в A, но не когда я оцениваю block. Я ожидаю, что они будут в той же области.

Спасибо!


person José P. Airosa    schedule 06.03.2014    source источник


Ответы (1)


В приведенном ниже коде

A.new do
  hello
  C.new
end

Вы пытаетесь создать объект C, как если бы он был определен в области видимости класса Object. Нет это не так. класс C определен внутри области модуля B. И вам нужно сказать это явно как B:C.new.

Приведенное выше объяснение относится к ошибке -:25:in 'block in': неинициализированная константа C (NameError).

Чего я не могу понять, так это почему у меня есть доступ к C внутри A?

У Module#constants есть ответ для вас: -

Возвращает массив имен констант, доступных в mod. Сюда входят имена констант во всех включенных модулях (пример в начале раздела), если для параметра наследования не задано значение false.

Посмотрите на пример :

module M
  X = 10
  class D; Y = 10 ;end
end
class C
  include M
  def initialize
    p self.class.constants
  end
end

C.new
# >> [:X, :D]

Теперь применим к вашему примеру:

module B
  class C
    def initialize
      'This is C'
    end
  end

  def hello
    'hello'
  end
end

class A
  include B

  def initialize(&block)
    p self.class.constants
    C.new  # it will work
    #instance_eval(&block)
  end
end

A.new do
  hello
  C.new # but this will throw error.
end

# it confirms that C is accessible, within the method.
# That is the same reason you got the output "This is C"
# >> [:C]

Надеюсь, это поможет.

person Arup Rakshit    schedule 06.03.2014
comment
Спасибо. Это действительно облегчает понимание того, что не так. Есть ли способ сделать это без указания полного пространства имен? - person José P. Airosa; 07.03.2014