2

class_eval and instance_eval are quite predictable in such cases like defining methods. I also understand the difference between class's instance and class's singleton (aka eigenclass).

BUT

I cannot figure out the only thing like following: Let's say, for some strage purposes, we want make existing class to be singleton.

class A; end
class B; end

A.class_eval do
  private :new
end

B.instance_eval do
  private :new
end

in both cases got

NameError: undefined method 'new' for class
Did you mean?  new

yes, I mean exactly this method.

Moreover, these two variants give the same result, like self points at class object in both cases

A.class_eval do
  class << self
    private :new
  end
end

A.new
=> NoMethodError: private method 'new' called for A:Class

B.instance_eval do
  class << self
    private :new
  end
end

B.new
=> NoMethodError: private method 'new' called for B:Class

How come? Can anybody shed the light on this?

bernstein7
  • 111
  • 5
  • `new` in classes in Ruby is actually defined using `initialize`. Try replacing `:new` with `:initialize` – casraf Dec 07 '16 at 16:57
  • @casraf That's not correct. `new` is defined by Class (the superclass of all classes) and does two things (from [the docs](https://ruby-doc.org/core-2.3.1/Class.html#method-c-new)): "Calls `allocate` to create a new object of *class*’s class, then invokes that object’s `initialize` method, passing it *args*. This is the method that ends up getting called whenever an object is constructed using .new." When you define (override) `initialize` in a class it does not define or change `new`, and `new` can be overridden like any other class method (though I can't think of a reason to). – Jordan Running Dec 07 '16 at 18:58
  • My bad. Thanks for clarifying :) – casraf Dec 08 '16 at 09:59

1 Answers1

0

Lets take a peek into what self is here:

class A
  puts self.inspect

  class << self
    puts self.inspect
  end
end

A.class_eval {
  puts self.inspect

  class << self
    puts self.inspect
  end
}

A.instance_eval{
  puts self.inspect

  class << self
    puts self.inspect
  end
}

We get the following output:

A
#<Class:A>
A
#<Class:A>
A
#<Class:A>

The class_eval method is defined for modules (and thus classes) and evaluates within the context of the module (class). The instance_eval method evaluates within the context of a BasicObject. It seems that in these cases the two (three actually) are the same thing.

However, I know for a fact that if methods are created inside the eval block that class_eval creates instance methods and instance_eval creates class methods. There is already an excellent posting for that observation:

Peter Camilleri
  • 1,882
  • 15
  • 17