privados - programacion con objetos ruby
¿Cómo crear un método de clase privado? (7)
A partir de ruby 2.3.0
class Check
def self.first_method
second_method
end
private
def self.second_method
puts "well I executed"
end
end
Check.first_method
#=> well I executed
¿Cómo funciona este enfoque de crear un método de clase privado?
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
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 la "metaclase" o "clase propia". private
no es una palabra clave, sino un método ( Module#private ).
Esta es una llamada al método self#private
/ A#private
que "alterna" el acceso privado en todas las definiciones de métodos de instancia venideras hasta que se active de otra manera:
class A
private
def instance_method_1; end
def instance_method_2; end
# .. and so forth
end
Como se señaló anteriormente, los métodos de clase son realmente métodos singleton definidos en la clase singleton.
def A.class_method; end
O usando una sintaxis especial para abrir el cuerpo de definición de la clase anónima de singleton A:
class << A
def class_method; end
end
El receptor del "mensaje privado" - auto - dentro de la class A
es el objeto de clase A. self dentro de la class << A
bloque es otro objeto, la clase singleton.
El siguiente ejemplo es, en realidad, llamando a dos métodos diferentes llamados privados , que utilizan dos destinatarios o destinos diferentes para la llamada. En la primera parte, definimos un método de instancia privada ("en la clase A"), en este último definimos un método de clase privado (es de hecho un método singleton en el objeto de clase singleton de A).
class A
# self is A and private call "A.private()"
private def instance_method; end
class << self
# self is A''s singleton class and private call "A.singleton_class.private()"
private def class_method; end
end
end
Ahora, reescribe este ejemplo un poco:
class A
private
def self.class_method; end
end
¿Puedes ver el error [que los diseñadores del lenguaje Ruby] hicieron? Alterne el acceso privado para todos los métodos de instancia de próxima aparición de A, pero proceda a declarar un método singleton en una clase diferente, la clase singleton.
Por defecto, todos los métodos de clase son públicos. Para hacerlos privados, puede usar Module#private_class_method private_class_method, como @tjwallace, los escribió o los definió de manera diferente, como lo hizo:
class << self
private
def method_name
...
end
end
class << self
opens the self''s singleton class, de modo que los métodos puedan ser redefinidos para el objeto self actual. Esto se usa para definir el método de clase / módulo ("estático"). Solo ahí, la definición de métodos privados realmente te da métodos privados de clase.
Solo por la integridad, 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.
private_class_method def self.method_name
....
end
Yo también, creo que Ruby (o al menos mi conocimiento de esto) es corto de la marca en esta área. Por ejemplo, el siguiente hace lo que quiero, pero es torpe,
class Frob
attr_reader :val1, :val2
Tolerance = 2 * Float::EPSILON
def initialize(val1, val2)
@val2 = val1
@val2 = val2
...
end
# Stuff that''s likely to change and I don''t want part
# of a public API. Furthermore, the method is operating
# solely upon ''reference'' and ''under_test'' and will be flagged as having
# low cohesion by quality metrics unless made a class method.
def self.compare(reference, under_test)
# special floating point comparison
(reference - under_test).abs <= Tolerance
end
private_class_method :compare
def ==(arg)
self.class.send(:compare, val1, arg.val1) &&
self.class.send(:compare, val2, arg.val2) &&
...
end
end
Mi problema 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 el código engorroso. Para que el código funcione como yo quiero y para silenciar las métricas, debo hacer compare () un método de clase. Como no quiero que forme parte de la API pública de la clase, necesito que sea privada, sin embargo, "privada" por sí sola no funciona. En su lugar, me veo obligado a utilizar ''private_class_method'' o algo parecido. 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.
private
no parece funcionar si está definiendo un método en un objeto explícito (en su caso, self
). Puede usar private_class_method
para definir los métodos de clase como privados (o como lo describió).
class Person
def self.get_name
persons_name
end
def self.persons_name
"Sam"
end
private_class_method :persons_name
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
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 usarlo de la siguiente manera:
class Person
def self.get_name
persons_name
end
private_class_method def self.persons_name
"Sam"
end
end
puts "Hey, " + Person.get_name
puts "Hey, " + Person.persons_name
ExiRe escribió:
Tal comportamiento de ruby es realmente frustrante. Quiero decir que si pasas a la sección privada self.method entonces NO es privado. Pero si lo mueve a la clase << self, entonces de repente funciona. Es simplemente desagradable.
Confundirlo probablemente es frustrante, pero desagradable definitivamente no lo es.
Tiene sentido una vez que comprenda el modelo de objetos de Ruby y el flujo de búsqueda de métodos correspondiente, especialmente si se tiene en cuenta que private
no es un modificador de acceso / visibilidad, sino una llamada a método (con la clase como destinatario) como se explica here . . No hay tal cosa como "una sección privada" en Ruby.
Para definir los métodos de instancia privados, llame a private
en la clase de la instancia para establecer la visibilidad predeterminada para los métodos definidos posteriormente en privado ... y por lo tanto tiene mucho sentido definir los métodos de clase private
llamando a private
en la clase de la clase, es decir. su metaclass.
Otros lenguajes OO autoproclamados de la corriente principal pueden darle una sintaxis menos confusa, pero definitivamente la cambia por un modelo de objetos confuso y menos consistente (¿inconsistente?) Sin la potencia de las funciones de metaprogramación de Ruby.