Question

I've came across an issue with instance_eval and module inclusion.

Please take a look at the following code:


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

When I run this code I get


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 `'

I understand that it has to do with bindings and how methods and objects are binded to class. What I cannot understand is how come I have access to C within A, but not when I eval the block. I would expect them to be in the same scope.

Thanks!

Was it helpful?

Solution

In the below code

A.new do
  hello
  C.new
end

You are are trying to create the object of C, as if it is defined in the scope of the class Object. No, it is not. class C is defined inside the scope of module B. And you need to tell that explicitly as B:C.new.

Above explanation is for the error -:25:in 'block in ': uninitialized constant C (NameError).

What I cannot understand is how come I have access to C within A ?

Module#constants has the answer for you :-

Returns an array of the names of the constants accessible in mod. This includes the names of constants in any included modules (example at start of section), unless the inherit parameter is set to false.

Look at the example :

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]

Now applying to your example :

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]

Hope that helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top