2011-02-03 13 views
5

¿Por qué puedes encadenar esto:¿Cómo funciona el encadenamiento Ruby?

"Test".upcase.reverse.next.swapcase 

pero no esto:

x = My_Class.new 
x.a.b.c 

donde

class My_Class 

    def a 
    @b = 1 
    end 

    def b 
    @b = @b + 2 
    end 

    def c 
    @b = @b -72 
    end 

end 
+0

El siguiente enlace http://stackoverflow.com/questions/ 3955688/how-do-i-debug-ruby-scripts/3955730 # 3955730 puede ayudarte a resolver mejor lo que está pasando en Ruby. –

+0

oh, ¿asumes que no ejecuto la depuración? ;) –

+0

¿Has probado 'x.a' (sin' .b.c') antes de hacer la pregunta? –

Respuesta

7

Los upcase, reverse, next y métodos swapcase toda la vuelta String objetos y todos esos métodos son para ... adivinaron, String objetos!

Cuando llama a un método (la mayoría de las veces, como el 99.9999% del tiempo) devuelve un objeto. Este objeto tiene métodos definidos en él que a su vez se puede llamar lo que explica por qué se puede hacer esto:

"Test".upcase.reverse.next.swapcase 

Incluso puede llamar reverse tantas veces como se quiera:

"Test".reverse.reverse.reverse.reverse.reverse.reverse.reverse.reverse 

Todo porque devuelve el mismo tipo de objeto, un objeto String!

Pero no se puede hacer esto con su MyClass:

x = My_Class.new 

x.a.b.c 

Para que funcione, el método a tendría que devolver un objeto que tiene el método b definido en ella. En este momento, parece que solo las instancias de MyClass tendrían eso. Para conseguir que esto funcione usted podría hacer que el valor de retorno de a el objeto en sí, así:

def a 
    @b += 2 
    self 
end 

Extrapolando esto, el método b también tendría que volver self como el método c sólo está disponible en las instancias de la MyClass clase. No importa qué devuelve c en este ejemplo, porque es el final de la cadena. Podría devolver self, no podría. Schrödinger's cat método. Nadie sabe hasta que abrimos la caja.

5

La última expresión de una función es su valor de retorno implícito. Debe devolver self si desea encadenar métodos como ese.

Por ejemplo, su método a está regresando actualmente 1. b no es un método para números. Usted querrá modificarlo así:

def a 
    @b = 1 
    self 
end 
6

Como apoyo a otras respuestas, este código:

"Test".upcase.reverse.next.swapcase 

... es casi exactamente el mismo que ...

a = "Test" 
b = a.upcase 
c = b.reverse 
d = c.next 
e = d.swapcase 

.... excepto que mi código anterior tiene supletoria variables sobrantes apuntando a los resultados intermedios, mientras que el original no deja referencias adicionales alrededor.Si hacemos esto con su código:

x = MyClass.new # x is an instance of MyClass 
y = x.a   # y is 1, the last expression in the a method 
z = y.b   # Error: Fixnums have no method named 'b' 

El uso de Ruby 1.9 tap método, incluso podemos hacer esto más explícito:

irb> "Test".upcase.tap{|o| p o}.reverse.tap{|o| p o}.next.tap{|o| p o}.swapcase 
#=> "TEST" 
#=> "TSET" 
#=> "TSEU" 
=> "tseu" 

irb> class MyClass 
irb> def a 
irb>  @b = 1 
irb> end 
irb> def b 
irb>  @b += 2 
irb> end 
irb> end 
=> nil 

irb(main):011:0> x = MyClass.new 
=> #<MyClass:0x000001010202e0> 

irb> x.a.tap{|o| p o}.b.tap{|o| p o}.c 
#=> 1 
NoMethodError: undefined method `b' for 1:Fixnum 
from (irb):12 
from /usr/local/bin/irb:12:in `<main>' 
+1

muy buena explicación! ¡Vota por ti! – xaxxon

Cuestiones relacionadas