Comprendre les méthodes privées dans Ruby

class Example private def example_test puts 'Hello' end end e = Example.new e.example_test 

Cela ne fonctionnera bien sûr pas, car nous avons spécifié un récepteur explicite – instance de l’exemple ( e ), et cela contre une “règle privée”.

Mais je ne peux pas comprendre pourquoi on ne peut pas faire en Ruby ceci:

 class Foo def public_m self.private_m # <= end private def private_m puts 'Hello' end end Foo.new.public_m 

L’object actuel dans la définition de la méthode public_m (c’est-à-dire self ) est l’instance de Foo. Alors pourquoi est-ce interdit? Pour résoudre ce problème, je dois remplacer self.private_m par private_m . Mais pourquoi cela diffère, le self n’est-il pas une instance de Foo dans public_m ? Et qui est le destinataire de l’appel private_m ? N’est-ce pas ce que vous omettez en réalité parce que Ruby le fera pour vous (appellera private_m sur soi-même)?

J’espère que je n’ai pas trop confondu, je suis toujours frais avec Ruby.


EDIT: Merci pour toutes les réponses. En les regroupant, j’ai pu (finalement) saisir l’évidence (et pas si évidente pour quelqu’un qui n’a jamais vu des choses comme Ruby): ce self même peut être explicite et implicite et faire la différence. Donc, il y a deux règles, si vous voulez appeler une méthode privée: self doit être un récepteur implicite, et self doit être une instance de la classe courante ( Example dans ce cas – et cela ne se produit que si self lors de l’exécution de cette méthode). S’il vous plait corrigez moi si je me trompe.

 class Example # self as an explicit receiver (will throw an error) def explicit self.some_private_method end # self as an implicit receiver (will be ok) def implicit some_private_method end private def some_private_method; end end Example.new.implicit 

Message à tous ceux qui pourraient trouver cette question dans les sentiers de Google: cela peut être utile – http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

Voici le court et le long de celui-ci. Ce que signifie privé dans Ruby, une méthode ne peut pas être appelée avec un récepteur explicite, par exemple some_instance.private_method (value). Donc, même si le récepteur implicite est auto, dans votre exemple, vous utilisez explicitement self afin que les méthodes privées ne soient pas accessibles.

Pensez-y de cette manière, vous attendriez-vous à pouvoir appeler une méthode privée en utilisant une variable que vous avez assignée à une instance d’une classe? Non, l’auto est une variable et doit suivre les mêmes règles. Cependant, lorsque vous appelez simplement la méthode dans l’instance, cela fonctionne comme prévu car vous ne déclarez pas explicitement le destinataire.

Ruby étant ce que vous pouvez réellement appeler des méthodes privées en utilisant instance_eval:

 class Foo private def bar(value) puts "value = #{value}" end end f = Foo.new begin f.bar("This won't work") rescue Exception=>e puts "That didn't work: #{e}" end f.instance_eval{ bar("But this does") } 

J’espère que c’est un peu plus clair.

— modifier —

Je suppose que vous saviez que cela fonctionnera:

 class Foo def public_m private_m # Removed self. end private def private_m puts 'Hello' end end Foo.new.public_m 

La définition de private dans Ruby est “ne peut être appelée sans récepteur explicite”. Et c’est pourquoi vous ne pouvez appeler des méthodes privées sans récepteur explicite. Il n’y a pas d’autre explication.

Notez qu’il existe effectivement une exception à la règle: en raison de l’ambiguïté entre les variables locales et les appels de méthode, les éléments suivants seront toujours résolus pour être une affectation à une variable locale:

 foo = :bar 

Alors, que faites-vous si vous voulez appeler un écrivain appelé foo= ? Eh bien, vous devez append un récepteur explicite, car sans le récepteur, Ruby ne saura tout simplement pas que vous voulez appeler la méthode foo= au lieu d’affecter la variable locale foo :

 self.foo = :bar 

Mais que faites-vous si vous voulez appeler un écrivain private appelé foo= ? Vous ne pouvez pas écrire self.foo = car foo= est private et ne peut donc pas être appelé avec un récepteur explicite. Eh bien, en fait pour ce cas particulier (et ce seul cas), vous pouvez réellement utiliser un récepteur explicite de self pour appeler un écrivain private .

C’est bizarre, mais beaucoup de choses à propos des modificateurs de visibilité de Ruby sont étranges. Même si self est le récepteur implicite, le fait de l’exprimer le rend explicite aux yeux de Ruby runtime. Quand il dit que les méthodes privées ne peuvent pas être appelées avec un récepteur explicite, c’est ce que cela signifie, même l’ self compte.

Les méthodes privées d’IIRC n’autorisent que le récepteur implicite (qui est toujours auto, bien sûr).

Désolé pour ma réponse précédente. Je ne comprends tout simplement pas votre question.

J’ai changé votre code comme ceci:

 class Foo def public_m private_m # < = end def Foo.static_m puts "static" end def self.static2_m puts "static 2" end private def private_m puts 'Hello' end end Foo.new.public_m Foo.static_m Foo.static2_m 

Voici une méthode d'appel d'instance:

  def public_m private_m # < = end 

Voici un appel de méthodes de classe:

  def Foo.static_m puts "static" end def self.static2_m puts "static 2" end Foo.static_m Foo.static2_m 

Ajout de quelques améliorations à la solution User Gates. L’appel d’une méthode privée à une méthode de classe ou à une méthode d’instance est pratiquement possible. Voici les extraits de code. Mais pas recommandé.

Méthode de classe

 class Example def public_m Example.new.send(:private_m) end private def private_m puts 'Hello' end end e = Example.new.public_m 

Méthode d’instance

 class Example def self.public_m Example.new.send(:private_m) end private def private_m puts 'Hello' end end e = Example.public_m 

Ne répond pas exactement à la question, mais vous pouvez appeler des méthodes privées de cette façon

 class Example private def example_test puts 'Hello' end end e = Example.new e.send(:example_test)