Comprensione dei metodi privati ​​in Ruby

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

Questo ovviamente non funzionerà, perché abbiamo specificato il ricevitore esplicito – istanza di Esempio ( e ), e questo è contro una “regola privata”.

Ma non riesco a capire, perché non si può fare in Ruby questo:

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

L’object corrente all’interno della definizione del metodo public_m (cioè self ) è l’istanza di Foo. Quindi perché non è permesso? Per risolvere il problema devo cambiare self.private_m su private_m . Ma perché questo differisce, non è il self un’istanza di Foo all’interno di public_m ? E chi è il ricevitore della chiamata private_m parole private_m ? Non è questo self – cosa in realtà ometti perché, Ruby lo farà per te (chiamerà private_m su se stesso)?

Spero di non averlo confuso troppo, sono ancora fresco con Ruby.


EDIT: Grazie per tutte le risposte. Mettendoli tutti insieme sono stato in grado (finalmente) di ingannare l’ovvio (e non così ovvio per qualcuno che non ha mai visto cose come Ruby): il self stesso può essere un ricevitore esplicito e implicito e questo fa la differenza. Quindi ci sono due regole, se si desidera chiamare un metodo privato: self deve essere un ricevitore implicito e quell’auto deve essere un’istanza della class corrente ( Example in tal caso – e che ha luogo solo se self all’interno della definizione del metodo di istanza, durante l’esecuzione di questo metodo). Perfavore, correggimi se sbaglio.

     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 

    Messaggio per chiunque possa trovare questa domanda durante i percorsi di google: può essere utile: http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

    Ecco il corto e il lungo. Quali mezzi privati ​​in Ruby è un metodo non può essere chiamato con un destinatario esplicito, ad es. Some_instance.private_method (valore). Quindi, anche se il ricevente implicito è self, nel tuo esempio utilizzi esplicitamente il sé in modo che i metodi privati ​​non siano accessibili.

    Pensaci in questo modo, ti aspetteresti di poter chiamare un metodo privato usando una variabile che hai assegnato a un’istanza di una class? No. Il sé è una variabile, quindi deve seguire le stesse regole. Tuttavia, quando si chiama il metodo all’interno dell’istanza, funziona come previsto perché non si sta dichiarando esplicitamente il destinatario.

    Essendo Ruby, in realtà puoi chiamare metodi privati ​​usando 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") } 

    Spero che sia un po ‘più chiaro.

    — modificare —

    Presumo che tu sappia che funzionerà:

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

    La definizione di private in Ruby è “può essere chiamata solo senza un destinatario esplicito”. Ed è per questo che puoi solo chiamare metodi privati ​​senza un ricevitore esplicito. Non c’è altra spiegazione.

    Si noti che in realtà esiste un’eccezione alla regola: a causa dell’ambiguità tra le variabili locali e le chiamate al metodo, verrà sempre risolto il problema di essere un’assegnazione a una variabile locale:

     foo = :bar 

    Quindi, cosa fai se vuoi chiamare uno scrittore chiamato foo= ? Bene, devi aggiungere un ricevitore esplicito, perché senza il ricevitore Ruby semplicemente non saprà che vuoi chiamare il metodo foo= invece di assegnare alla variabile locale foo :

     self.foo = :bar 

    Ma cosa fai se vuoi chiamare uno scrittore private chiamato foo= ? Non puoi scrivere self.foo = perché foo= è private e quindi non può essere chiamato con un ricevitore esplicito. Bene, in realtà per questo caso specifico (e solo in questo caso), puoi effettivamente usare un ricevitore esplicito di self per chiamare uno scrittore private .

    È strano, ma molte cose sui modificatori di visibilità di Ruby sono strane. Anche se self è il ricevitore implicito, in realtà lo spelling lo rende esplicito agli occhi del runtime di Ruby. Quando dice che i metodi privati ​​non possono essere chiamati con un ricevitore esplicito, questo è ciò che significa, anche il conteggio di self .

    IIRC, i metodi privati ​​consentono solo il ricevente implicito (che è sempre auto, ovviamente).

    Scusa per la mia risposta precedente. Non capisco la tua domanda.

    Ho cambiato il tuo codice in questo modo:

     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 

    Ecco una chiamata del metodo di istanza:

      def public_m private_m # <= end 

    Ecco una chiamata di metodi di class:

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

    Aggiunta di alcuni miglioramenti alla soluzione User Gates. Chiamare un metodo privato al metodo di class o un metodo di istanza è praticamente ansible. Ecco i frammenti di codice. Ma non raccomandato.

    Metodo di class

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

    Metodo di istanza

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

    Non risponde esattamente alla domanda, ma puoi chiamare metodi privati ​​in questo modo

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