The code below attempts to create a class MyClass which delegates a call to method self.add to the object returned by calling method self.newAdd.
a + b
def self.delegate(*methods, options)
return unless options.has_key?(:to)
methods.each do |method|
define_method method, ->(*args, &prc) do
delegated_to = Object.const_get(options[:to]).call()
delegated_to.send(method, *args, &prc)
class << self
delegate :add, to: :newAdd
NoMethodError: undefined method 'delegate' for #
MyClass.methods - Object.methods #[:newAdd, :delegate]
self.methods - Object.methods #[:nesting]
self # #<Class:MyClass>
self.class # Class
MyClass.class # Class
class << self
class << self
Why is self not the same as MyClass inside of the class << self scope.
Because the class keyword always changes the scope:
class MyClass puts self #=> MyClass class <<self puts self #=>MyClass’s singleton class end end
More specifically, why is the method delegate not available to self inside of class << self?
class MyClass def self.delegate puts "executing MyClass.dellegate()" end class <<self delegate end end --output:-- 1.rb:8:in `singleton class': undefined local variable or method `delegate' for #<Class:MyClass> (NameError) from 1.rb:7:in `<class:MyClass>' from 1.rb:1:in `<main>'
Note that the following constructs are equivalent:
class MyClass def self.delegate puts "executing MyClass.dellegate()" end end MyClass.delegate --output:-- executing MyClass.dellegate()
class MyClass class <<self def delegate puts "executing MyClass.dellegate()" end end end MyClass.delegate --output:-- executing MyClass.dellegate()
Therefore, your code is equivalent to:
class MyClass class <<self def delegate puts "executing MyClass.dellegate()" end delegate end end
If you ignore the outer MyClass for a moment, then you defined a class like this:
class <<self def delegate puts "executing MyClass.dellegate()" end delegate end
That same structure can be replicated like this:
class Dog def bark puts “woof” end bark end
which will produce the same type of error:
1.rb:7:in `<class:Dog>': undefined local variable or method `bark' for Dog:Class (NameError) from 1.rb:1:in `<main>'
When you call a method and you don't specify a receiver, ruby uses whatever object is currently assigned to the self variable as the receiver.
Inside a method, ruby assigns the object that called the method to the self variable. The object that called the method is not the same thing as the class (object) in which the method is defined.
Inside a class, but outside of any method definitions, ruby assigns the class (object) to self.
I don't understand really what a class method on an eignclass is however.
Personally, I don't use the term
eigenclass. In my opinion, ruby has made a decision that the term is
singleton class. If you look through the docs for the Object class, there are no method names that have
eigenclass in them, yet there are method names with
singleton class in them.
All objects have a singleton class. A singleton class is an object. Therefore, every singleton class also has a singleton class--which means that the chain of singleton classes is infinite:
class Dog end s1 = Dog.singleton_class puts s1 s2 = s1.singleton_class puts s2 s3 = s2.singleton_class puts s3 --output:-- #<Class:Dog> #<Class:#<Class:Dog>> #<Class:#<Class:#<Class:Dog>>>
However, I've never seen anyone use a singleton class of a singleton class (s2) before in their code. I did it once to answer a question, and nobody had any idea what I was talking about.
There are some method lookup diagrams here, which might prove useful.