2012-02-03 11 views
5

Con cuerdas se puede hacer esto:manera genérica para reemplazar un objeto en su propio método

a = "hello" 
a.upcase! 
p a #=> "HELLO" 

Pero ¿cómo voy a escribir mi propio método de esa manera?

Algo parecido (aunque eso no funciona, obviamente):

class MyClass 
    def positify! 
    self = [0, self].max 
    end 
end 

Sé que hay algunos trucos que uno puede utilizar en cadena, pero si lo que estoy tratando de hacer algo como esto para los objetos?

Respuesta

4

Bueno, el método upcase! no cambia la identidad del objeto, solo cambia su estructura interna (s.object_id == s.upcase!.object_id).

Por otro lado, los números son objetos inmutables y, por lo tanto, no puede cambiar su valor sin cambiar su identidad. AFAIK, no hay forma de que un objeto cambie su identidad, pero, por supuesto, puede implementar el método positify! que cambia las propiedades de su objeto, y este sería un análogo de qué upcase! lo hace por cuerdas.

2

La asignación o vinculación de variables locales (utilizando el operador =) está incorporada en el lenguaje central y no hay forma de anularlo o personalizarlo. Sin embargo, podría ejecutar un preprocesador sobre su código Ruby que convertiría su propia sintaxis personalizada en un Ruby válido. También podría pasar un Binding a un método personalizado, que podría redefinir las variables de forma dinámica. Sin embargo, esto no logrará el efecto que está buscando.

Comprenda que self = nunca funcionará, porque cuando dice a = "string"; a = "another string" no está modificando ningún objeto; estás volviendo a vincular una variable local a un objeto diferente. Dentro de su método personalizado, se encuentra en un ámbito diferente y cualquier variable local que vincule solo existirá en ese ámbito; no tendrá ningún efecto en el alcance desde el que llamó al método.

2

No puede cambiarse a sí mismo para apuntar a otra cosa que no sea su objeto actual. Puede realizar cambios en las variables de instancia, como en la cadena de casos que cambia los caracteres subyacentes a mayúsculas.

Como se señaló en esta respuesta: Ruby and modifying self for a Float instance

Hay un truco mencionado aquí que es un trabajo alrededor, que es escribir que la clase como una envoltura alrededor del otro objeto. Entonces su clase contenedora puede reemplazar el objeto envuelto a voluntad. Sin embargo, dudo en decir que esta es una buena idea.

7

Muchas clases son inmutables (por ejemplo Numeric, Symbol, ...), por lo que no tienen ningún método que le permite cambiar su valor.

Por otro lado, cualquier Object puede tener variables de instancia y estas pueden ser modificadas.

Hay una manera fácil de delegar el comportamiento a un objeto conocido (digamos 42) y poder cambiar, más adelante, a otro objeto, usando SimpleDelegator.En el siguiente ejemplo, se comporta como un quacks_like_an_intInteger:

require 'delegate' 
quacks_like_an_int = SimpleDelegator.new(42) 
quacks_like_an_int.round(-1) # => 40 
quacks_like_an_int.__setobj__(666) 
quacks_like_an_int.round(-1) # => 670 

Se puede utilizar para diseñar una clase también, por ejemplo:

require 'delegate' 
class MutableInteger < SimpleDelegator 
    def plus_plus! 
    __setobj__(self + 1) 
    self 
    end 

    def positify! 
    __setobj__(0) if self < 0 
    self 
    end 
end 

i = MutableInteger.new(-42) 
i.plus_plus! # => -41 
i.positify! # => 0 
Cuestiones relacionadas