Comprender los métodos privados en Ruby

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

Esto, por supuesto, no funcionará, porque especificamos el receptor explícito – instancia del ejemplo ( e ), y eso está en contra de una “regla privada”.

Pero no puedo entender, por qué no se puede hacer en Ruby esto:

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

El objeto actual dentro de la definición del método public_m (es decir, self ) es la instancia de Foo. Entonces, ¿por qué no está permitido? Para solucionarlo, tengo que cambiar self.private_m a self.private_m . Pero ¿por qué esto difiere? ¿No es el self una instancia de Foo dentro de public_m ? ¿Y quién es el destinatario de la llamada private_m palabras? ¿No es eso self ? ¿Qué es lo que realmente omites porque, Ruby lo hará por ti (llamará private_m a sí mismo)?

Espero no haberlo confundido demasiado, todavía estoy fresco para Ruby.


EDITAR: Gracias por todas las respuestas. Poniéndolos a todos juntos pude (finalmente) asimilar lo obvio (y no tan obvio para alguien, que nunca había visto cosas como Ruby): ese self mismo puede ser receptor explícito e implícito y eso hace la diferencia. Entonces, hay dos reglas, si quiere llamar a un método privado: self debe ser un receptor implícito, y ese self debe ser una instancia de la clase actual ( Example en ese caso, y eso tiene lugar solo cuando está dentro de la definición del método de instancia, durante esta ejecución del método). Por favor, corríjame si estoy equivocado.

 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 

Mensaje para cualquier persona que pueda encontrar esta pregunta durante los rastros de google: esto puede ser útil – http://weblog.jamisbuck.org/2007/2/23/method-visibility-in-ruby

Aquí está el corto y el largo de eso. Qué medios privados en Ruby es un método no se puede llamar con un receptor explícito, por ejemplo some_instance.private_method (value). Por lo tanto, aunque el receptor implícito sea uno mismo, en su ejemplo usted usa explícitamente el self para que los métodos privados no sean accesibles.

Piénselo de esta manera, ¿esperaría poder llamar a un método privado utilizando una variable que ha asignado a una instancia de una clase? No. El yo es una variable, así que debe seguir las mismas reglas. Sin embargo, cuando acaba de llamar al método dentro de la instancia, funciona como se esperaba porque no está declarando explícitamente el receptor.

Ruby siendo lo que es, puedes llamar a métodos privados 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") } 

Espero que sea un poco más claro.

– editar –

Supongo que sabías que esto funcionaría:

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

La definición de private en Ruby es “solo se puede llamar sin un receptor explícito”. Y es por eso que solo puedes llamar a métodos privados sin un receptor explícito. No hay otra explicacion.

Tenga en cuenta que en realidad existe una excepción a la regla: debido a la ambigüedad entre las variables locales y las llamadas a métodos, lo siguiente siempre se resolverá como una asignación a una variable local:

 foo = :bar 

Entonces, ¿qué haces si quieres llamar a un escritor llamado foo= ? Bueno, tienes que agregar un receptor explícito, porque sin el receptor Ruby simplemente no sabrá que quieres llamar al método foo= lugar de asignar a la variable local foo :

 self.foo = :bar 

¿Pero qué haces si quieres llamar a un escritor private llamado foo= ? No puede escribir self.foo = porque foo= es private y, por lo tanto, no puede self.foo = con un receptor explícito. Bueno, en realidad para este caso específico (y solo este caso), puede usar un receptor explícito de self para llamar a un escritor private .

Es extraño, pero muchas cosas sobre los modificadores de visibilidad de Ruby son raras. Incluso si el self es el receptor implícito, en realidad deletrearlo lo hace explícito a los ojos del tiempo de ejecución de Ruby. Cuando dice que los métodos privados no pueden invocarse con un receptor explícito, eso es lo que significa, incluso el self cuenta.

IIRC, los métodos privados solo permiten el receptor implícito (que siempre es uno mismo, por supuesto).

Perdón por mi respuesta anterior. Simplemente no entiendo tu pregunta.

Cambié tu código así:

 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 

Aquí hay un llamado de método de instancia:

  def public_m private_m # < = end 

Aquí hay una llamada de métodos de clase:

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

Añadiendo algunas mejoras a la solución User Gates. Llamar a un método privado para el método de clase o un método de instancia es bastante posible. Aquí están los fragmentos de código. Pero no recomendado.

Método de clase

 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étodo de instancia

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

No responde exactamente la pregunta, pero puede llamar a métodos privados de esta manera

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