variable programacion privados polimorfismo objetos herencia con clases clase atributos ruby access-specifier

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.