'<<' como método ordinario
En la mayoría de los casos, '<<' es un método definido como el resto de ellos, en su caso significa "agregar al final de esta matriz" (ver también aquí ).
Ese es en su caso particular, pero también hay muchas otras ocasiones en las que encontrará el método "<<". No lo llamaré 'operador' ya que en realidad es un método que se define en algún objeto que puede ser anulado por usted o implementado para sus propios objetos. Otros casos de '<<'
- Concatenación de cadenas: "a" << "b"
- Escritura de salida en un IO: io << "Una línea de texto \ n"
- Escritura de datos en un resumen de mensajes, HMAC o cifrado: sha << "Texto para aplicar hash"
- desplazamiento a la izquierda de un OpenSSL :: BN: bn << 2
- ...
Definición de clase singleton
Luego está el misterioso cambio del alcance actual (= cambio de uno mismo) dentro del flujo del programa:
class A
class << self
puts self
end
end
a = A.new
class << a
puts self
end
El misterio class << self
me hizo preguntarme e investigar sobre las partes internas allí. Mientras que en todos los ejemplos que mencioné <<
es realmente un método definido en una clase, es decir
obj << stuff
es equivalente a
obj.<<(stuff)
la class << self
construcción (o cualquier objeto en lugar del yo) es verdaderamente diferente. Es realmente una característica incorporada del lenguaje en sí, en CRuby se define en parse.y como
k_class tLSHFT expr
donde tLSHFT es un token '<<', k_class es la palabra clave 'class' y expr es una expresión arbitraria. Es decir, puedes escribir
class << <any expression>
y se 'desplazará' a la clase singleton del resultado de la expresión. La secuencia tLSHFT se analizará como una expresión 'NODE_SCLASS', que se denomina definición de clase Singleton (cf. node.c)
case NODE_SCLASS:
ANN("singleton class definition");
ANN("format: class << [nd_recv]; [nd_body]; end");
ANN("example: class << obj; ..; end");
F_NODE(nd_recv, "receiver");
LAST_NODE;
F_NODE(nd_body, "singleton class definition");
break;
Aquí Documentos
Y, cómo podría olvidarme de esos, Here Documents usa '<<' de una manera que nuevamente es totalmente diferente. Puede definir una cadena que abarque varias líneas de manera conveniente declarando
here_doc = <<_EOS_
The quick brown fox jumps over the lazy dog.
...
_EOS_
Para distinguir el 'operador aquí doc', un delimitador de cadena arbitrario debe seguir inmediatamente al '<<'. Todo lo que se encuentre entre ese delimitador inicial y la segunda aparición de ese mismo delimitador será parte de la cadena final. También es posible usar '<< -', la diferencia es que usar este último ignorará cualquier espacio en blanco inicial o final.