¿Cómo funciona este enfoque de crear un método de clase privada?
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)"
Pero esto no:
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 millas
fuente
fuente
Respuestas:
private
no parece funcionar si está definiendo un método en un objeto explícito (en su casoself
). Puede usarprivate_class_method
para definir métodos de clase como privados (o como usted describió).Alternativamente (en ruby 2.1+), dado que la definición de un método devuelve un símbolo del nombre del método, también puede usar esto de la siguiente manera:
fuente
ExiRe escribió:
Probablemente sea confuso, frustrante puede ser, pero asqueroso definitivamente no lo es.
Tiene mucho sentido una vez que comprenda el modelo de objetos de Ruby y el flujo de búsqueda del método correspondiente , especialmente cuando se considera que NO
private
es un modificador de acceso / visibilidad, sino una llamada al método (con la clase como su destinatario) como se discute aquí ... No hay tal cosa como "una sección privada" en Ruby.Para definir métodos de instancias privadas , llama
private
a la clase de la instancia para establecer la visibilidad predeterminada para los métodos definidos posteriormente como privados ... y, por lo tanto, tiene mucho sentido definir métodos de clases privadas llamandoprivate
a la clase de la clase, es decir. su metaclaseOtros lenguajes OO autoproclamados convencionales pueden darle una sintaxis menos confusa, pero definitivamente lo intercambia con un modelo de objeto confuso y menos consistente (¿inconsistente?) Sin el poder de las instalaciones de metaprogramación de Ruby.
fuente
private_class_method :method_name
, podrías hacerprivate_class_method def method_name...
.send(private_method)
También es accesible fuera del objeto.private_class_method def self.method_name
Por defecto, todos los métodos de clase son públicos. Para hacerlos privados, puede usar el Módulo # private_class_method como @tjwallace escribió o definirlos de manera diferente, como lo hizo:
class << self
abre la clase singleton de self para que los métodos se puedan redefinir para el self object actual. Esto se utiliza para definir el método de clase / módulo ("estático"). Solo allí, la definición de métodos privados realmente le brinda métodos de clase privada.fuente
Solo por lo completo, también podemos evitar declarar private_class_method en una línea separada. Personalmente no me gusta este uso, pero es bueno saber que existe.
fuente
Yo también, encuentro Ruby (o al menos mi conocimiento de él) por debajo de la marca en esta área. Por ejemplo, lo siguiente hace lo que quiero pero es torpe,
Mis problemas con el código anterior es que los requisitos de sintaxis de Ruby y las métricas de calidad de mi código conspiran para crear un código engorroso. Para que el código funcione como quiero y para silenciar las métricas, debo hacer que compare () sea un método de clase. Como no quiero que sea parte de la clase 'API pública', necesito que sea privada, pero 'privado' por sí solo no funciona. En cambio, me veo obligado a usar 'private_class_method' o alguna solución alternativa. Esto, a su vez, fuerza el uso de 'self.class.send (: compare ...' para cada variable que pruebo en '== ()'. Ahora eso es un poco difícil de manejar.
fuente
Los métodos de instancia se definen dentro de un bloque de definición de clase. Los métodos de clase se definen como métodos singleton en la clase singleton de una clase, también conocida informalmente como "metaclase" o "clase propia".
private
no es una palabra clave, sino un método ( Módulo # privado ).Esta es una llamada al método
self#private
/A#private
que "activa" el acceso privado para todas las próximas definiciones de métodos de instancia hasta que se active de otra manera:Como se señaló anteriormente, los métodos de clase son realmente métodos singleton definidos en la clase singleton.
O utilizando una sintaxis especial para abrir el cuerpo de definición de la clase anónima singleton de A:
El receptor del "mensaje privado" - self - inside
class A
es el objeto de clase A. self dentro delclass << A
bloque es otro objeto, la clase singleton.El siguiente ejemplo es en realidad llamar a dos métodos diferentes llamados privados , utilizando dos destinatarios u objetivos diferentes para la llamada. En la primera parte, definimos un método de instancia privada ("en la clase A"), en la última definimos un método de clase privada (de hecho, es un método singleton en el objeto de clase singleton de A).
Ahora, reescribe este ejemplo un poco:
¿Puedes ver el error que cometieron [los diseñadores de lenguaje Ruby]? Alterna el acceso privado para todos los métodos de instancia próximos de A, pero procede a declarar un método singleton en una clase diferente, la clase singleton.
fuente
Ruby parece proporcionar una solución pobre. Para explicar, comience con un ejemplo simple de C ++ que muestre el acceso a métodos de clase privada:
Ejecutando lo anterior
Ahora Ruby no parece proporcionar el equivalente. Las reglas de Ruby, creo, son que no se debe acceder a los métodos privados con un receptor. Es decir,
Eso está bien para los métodos de instancia privada, pero causa problemas con los métodos de clase privada.
Me gustaría que Ruby funcionara de esta manera:
Pero, por desgracia, lo anterior no funciona. ¿Alguien sabe una mejor manera?
Cuando veo 'enviar' antes de un método, es una señal clara de que el código está violando la intención del diseñador de la API, pero en este caso el diseño es específicamente para que un método de instancia de la clase llame al método de clase privada.
fuente
A partir de ruby 2.3.0
fuente
private def self.second_method
antes de cada notación de método, que no funcionaba en mi ruby 2.3.3. Pero esta notación funciona para mí.Check.second_method
también funcionarían sin problemas, por lo que no es realmente privado.private_class_method :second_method