Comment fonctionne cette approche de création d'une méthode de classe privée:
class Person
def self.get_name
persons_name
end
class << self
private
def persons_name
"Sam"
end
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name #=> raises "private method `persons_name' called for Person:Class (NoMethodError)"
Mais cela ne signifie pas:
class Person
def self.get_name
persons_name
end
private
def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
ruby
access-specifier
99 milles
la source
la source
Réponses:
private
ne semble pas fonctionner si vous définissez une méthode sur un objet explicite (dans votre casself
). Vous pouvez utiliserprivate_class_method
pour définir des méthodes de classe comme privées (ou comme vous l'avez décrit).Alternativement (dans ruby 2.1+), étant donné qu'une définition de méthode renvoie un symbole du nom de la méthode, vous pouvez également l'utiliser comme suit:
la source
ExiRe a écrit:
Le confondre est probablement, frustrant peut-être, mais dégoûtant ce n'est certainement pas.
Cela prend tout son sens une fois que vous comprenez le modèle d'objet de Ruby et le flux de recherche de méthode correspondant , en particulier lorsque vous prenez en considération ce
private
n'est PAS un modificateur d'accès / visibilité, mais en fait un appel de méthode (avec la classe comme destinataire) comme discuté ici ... il n'y a pas de "section privée" dans Ruby.Pour définir des méthodes d' instance privées , vous appelez
private
la classe de l'instance pour définir la visibilité par défaut des méthodes définies par la suite sur private ... et il est donc parfaitement logique de définir des méthodes de classe privée en faisant appelprivate
à la classe de la classe, c'est-à-dire. sa métaclasse.D'autres langages OO autoproclamés courants peuvent vous donner une syntaxe moins déroutante, mais vous échangez certainement cela contre un modèle d'objet déroutant et moins cohérent (incohérent?) Sans la puissance des installations de métaprogrammation de Ruby.
la source
private_class_method :method_name
vous pourriez le faireprivate_class_method def method_name...
.send(private_method)
est également accessible en dehors de l'objet.private_class_method def self.method_name
Par défaut, toutes les méthodes de classe sont publiques. Pour les rendre privés, vous pouvez utiliser le module # private_class_method comme @tjwallace l'a écrit ou les définir différemment, comme vous l'avez fait:
class << self
ouvre la classe singleton de self, de sorte que les méthodes peuvent être redéfinies pour l'objet self actuel. Ceci est utilisé pour définir la méthode classe / module ("statique"). Seulement là, définir des méthodes privées vous donne vraiment des méthodes de classe privées.la source
Juste pour être complet, nous pouvons également éviter de déclarer private_class_method dans une ligne distincte. Personnellement, je n'aime pas cet usage mais bon de savoir qu'il existe.
la source
Moi aussi, je trouve Ruby (ou du moins ma connaissance de celui-ci) loin de la marque dans ce domaine. Par exemple, ce qui suit fait ce que je veux mais est maladroit,
Mes problèmes avec le code ci-dessus est que les exigences de syntaxe Ruby et mes métriques de qualité de code conspirent pour faire du code encombrant. Pour que le code fonctionne à la fois comme je le souhaite et pour calmer les métriques, je dois faire de compare () une méthode de classe. Comme je ne veux pas qu'elle fasse partie de la classe 'API publique, j'ai besoin qu'elle soit privée, mais' privée 'en elle-même ne fonctionne pas. Au lieu de cela, je suis obligé d'utiliser 'private_class_method' ou une telle solution de contournement. Ceci, à son tour, force l'utilisation de 'self.class.send (: compare ...' pour chaque variable que je teste dans '== ()'. Maintenant c'est un peu compliqué.
la source
Les méthodes d'instance sont définies dans un bloc de définition de classe. Les méthodes de classe sont définies comme des méthodes singleton sur la classe singleton d'une classe, également connues de manière informelle sous le nom de "métaclasse" ou "classe propre".
private
n'est pas un mot-clé, mais une méthode ( Module # private ).Ceci est un appel à method
self#private
/A#private
qui "bascule" l'accès privé pour toutes les définitions de méthode d'instance à venir jusqu'à ce qu'il soit basculé autrement:Comme indiqué précédemment, les méthodes de classe sont vraiment des méthodes singleton définies sur la classe singleton.
Ou en utilisant une syntaxe spéciale pour ouvrir le corps de définition de la classe singleton anonyme de A:
Le récepteur du "message privé" - self -inside
class A
est l'objet de classe A. self inside theclass << A
block est un autre objet, la classe singleton.L'exemple suivant appelle en réalité deux méthodes différentes appelées privées , en utilisant deux destinataires ou cibles différents pour l'appel. Dans la première partie, nous définissons une méthode d'instance privée ("sur la classe A"), dans la seconde nous définissons une méthode de classe privée (est en fait une méthode singleton sur l'objet classe singleton de A).
Maintenant, réécrivez un peu cet exemple:
Pouvez-vous voir l'erreur [que les concepteurs du langage Ruby] ont commise? Vous basculez sur l'accès privé pour toutes les méthodes d'instance à venir de A, mais continuez à déclarer une méthode singleton sur une classe différente, la classe singleton.
la source
Ruby semble fournir une mauvaise solution. Pour expliquer, commencez par un simple exemple C ++ qui montre l'accès aux méthodes de classe privée:
Exécution de ce qui précède
Maintenant, Ruby ne semble pas fournir l'équivalent. Je pense que les règles de Ruby sont que les méthodes privées ne doivent pas être accessibles avec un récepteur. C'est,
C'est OK pour les méthodes d'instances privées, mais cela pose des problèmes avec les méthodes de classes privées.
J'aimerais que Ruby fonctionne de cette façon:
Mais, hélas, ce qui précède ne fonctionne pas. Quelqu'un connaît-il une meilleure façon?
Lorsque je vois `` envoyer '' avant une méthode, c'est un signe clair que le code viole l'intention du concepteur de l'API, mais dans ce cas, la conception consiste spécifiquement à avoir une méthode d'instance de la classe appelée la méthode de classe privée.
la source
À partir de ruby 2.3.0
la source
private def self.second_method
avant chaque notation de méthode, qui ne fonctionnait pas sur mon ruby 2.3.3. Mais cette notation fonctionne pour moi.Check.second_method
fonctionnerait également sans problème, donc ce n'est pas vraiment privé.private_class_method :second_method