rails - Comprender los métodos privados en Ruby
ruby documentation pdf (7)
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
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
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
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).
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
.
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)
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