2017-10-18 11 views
3

que je veux patcher le module Kernel avec une méthode que je viens avec:méthodes du module Ruby noyau utilisées comme méthodes de la classe Object

module Kernel 
    def say_hello 
    puts "hello world" 
    end 
end 

Je peux maintenant faire certainement ceci:

Object.new.say_hello # => hello world 

mais je peux aussi faire ce qui suit que je devrais normalement pas être en mesure de le faire:

Object.say_hello # => hello world 

Depuis Object inclut Kernel il prend ses méthodes d'instance et donc toutes les instances Object doivent répondre à say_hello. Jusqu'ici tout va bien.

Cependant Object.say_hello semble être une méthode de classe qui ne pouvait se justifier que si nous avions fait quelque chose de semblable à ceci:

class << Object 
    def say_hello 
    puts "hello world" 
    end 
end 

Stockage say_hello en classe singleton de Object nous permettrait de l'utiliser comme une classe méthode mais à la place Kernel juste inclus dans Object qui ne devrait pas permettre ce comportement. Mais ça le fait. Est-ce que quelqu'un a une idée pourquoi?

Merci

+3

C'est très simple: 'Object' est un' Class' qui est un 'Object'. C'est pourquoi il répond à 'say_hello' :) –

Répondre

5

Kernel est tout inclus dans Object [...]

C'est exact.

[...] qui ne devrait pas permettre ce comportement.

Vous oubliez que les classes sont aussi des objets.


Voyons où la méthode say_hello vient de se obj est une instance de Object:

obj = Object.new 

obj.method(:say_hello) 
#=> #<Method: Object(Kernel)#say_hello> 

Tout comme prévu.obj est une instance de Object et Object comprend Kernel:

obj.class.include? Kernel 
#=> true 

obj.class.ancestors 
#=> [Object, Kernel, BasicObject] 

Maintenant, nous allons voir ce qui se passe si obj est la classe Object:

obj = Object 

obj.method(:say_hello) 
#=> #<Method: Class(Kernel)#say_hello> 

Cette fois obj est une instance de Class et Class comprend également Kernel:

obj.class.include? Kernel 
#=> true 

obj.class.ancestors 
#=> [Class, Module, Object, Kernel, BasicObject] 

documentation Ruby constate que les méthodes de classe sont en fait que des méthodes d'instance définies sur l'objet de classe: (souligné)

class C 
    def self.my_method 
    # ... 
    end 
end 

Cependant, cela est tout simplement un cas particulier d'un plus grand la puissance syntaxique dans Ruby, la possibilité d'ajouter des méthodes à n'importe quel objet. Les classes étant des objets, ajoutant des méthodes de classe ajoute simplement des méthodes à l'objet Class.