2010-11-13 21 views
13

Je souhaite qu'une classe ruby ​​héritée connaisse son nom de classe via une méthode de classe. Ceci est mieux illustré par un exemple artificiel:Méthode de classe pour «connaître» le nom de classe dans Ruby?

class Parent 
    def self.whoami 
    ?? 
    end 
end 

class Child < Parent 
    #No code should be needed. 
end 

donc je devrais pouvoir appeler:

Parent.whomai 

et attendre un retour de « Parent » Je puis être en mesure d'appeler:

Child.whoami 

et d'attendre un retour de "Enfant" J'ai le sentiment que dans des langages conventionnels cela pourrait ne pas être possible. Mais le modèle de métaprogrammation de Ruby m'a déjà étonné. Des pensées? Merci d'avance.

Répondre

20

Une méthode de classe est une méthode où la classe est le récepteur, afin de trouver l'objet sur lequel la méthode est invoquée (ce que vous semblez essayer de faire ici) inspecter simplement la valeur de self.

class Parent 
    def self.whoami 
    self 
    end 
end 

class Child < Parent 
end 

puts Parent.whoami #=> Parent 
puts Child.whoami #=> Child 
+0

Cela semblait trop facile. Merci. –

+0

Qu'est-ce qui ne va pas avec ['Module # name'] (http://Ruby-Doc.Org/ruby-1.9/classes/Module.html#M000913) et pourquoi le double' puts'? –

+1

Il n'y a pas de raison d'avoir une méthode qui retourne self, utilisez directement l'objet: 'met Parent'. Puts appelle Parent.to_s en coulisse pour obtenir un nom de chaîne de la classe. –

2

N'est-ce pas ce que vous dira Parent.class?

class Parent 
    def self.whoami 
    self.to_s 
    end 
end 

class Child < Parent 
end 

> Parent.whoami 
=> "Parent" 
> Child.whoami 
=> "Child" 
+0

Si sa méthode de classe, 'self' retournera la classe –

+2

Quel est le problème avec [' Module # name'] (http://Ruby-Doc.Org/ruby -1,9/classes/Module.html # M000913)? –

+0

@ Jörg Je supposais qu'il faisait quelque chose d'un peu plus compliqué qu'une méthode de classe qui renvoyait un nom, mais vous avez raison que 'Module # name' est la bonne façon de le faire. –

15

La méthode pour obtenir le nom d'une classe (module, en fait) est juste Module#name. Il n'y a pas besoin d'écrire votre propre:

Parent.name # => 'Parent' 
Child.name # => 'Child' 

Cependant, Ruby, il n'y a vraiment pas une telle chose comme un « nom de la classe », comme il y a dans d'autres langues. Dans Ruby, une classe est simplement un objet comme tout autre objet assigné à une variable comme n'importe quelle autre variable.

Toute la méthode Module#name fait une boucle sur toutes les constantes dans le système et vérifie si le module a été assigné à l'un d'entre eux, et retourne le nom de cette constante ou nil s'il n'en trouve pas. Ainsi, tout comme n'importe quel autre objet, le "nom" d'une classe est vraiment rien que la variable que vous utilisez pour s'y référer.

Exemple:

foo = Class.new 
foo.name # => nil 

Maintenant, le "nom" de la classe est foo. Toutefois, Module#name renvoie nil, car foo n'est pas une constante.

bar = foo 
bar.name # => nil 

Maintenant, le "nom" de la classe est à la fois foo et bar, mais Module#name évidemment retourne encore nil.

BAZ = foo 
foo.name # => 'BAZ' 

Maintenant, puisque la classe a été attribuée à une constante, le nom de cette constante sera considérée comme le nom & hellip de cette classe;

BAZ = nil 
foo.name # => 'BAZ' 

& hellip; même après que la constante a été assignée à quelque chose de différent et & hellip;

QUX = foo 
QUX.name # => 'BAZ' 

& hellip; même après que la classe a été affectée à une constante différente.

Module#to_s utilise Module#name si ce ne nil, donc, d'imprimer le nom d'une classe, vous faites simplement

puts Parent 

Il n'y a vraiment absolument pas besoin de toutes les peluches complexes dans les autres réponses.

1

Supposons que vous classe:

class ABC 
def self.some_method 
    self.name #it will return 'ABC' 
    self.name.constantize #it will return ABC 
end 
end