¿Se puede alias a los operadores de Ruby?
-
05-07-2019 - |
Pregunta
Estoy interesado en cómo se podría lograr que esto funcione:
me = "this is a string"
class << me
alias :old<< :<<
def <<(text)
old<<(text)
puts "appended #{text}"
end
end
Me gustaría que cuando algo se agregue a la variable me
, el objeto utilizará el método redefinido.
Si intento ejecutar esto, obtengo syntax error, unexpected ':', expecting kEND
en :<<
.
Solución
:old<<
parece " :old
<<
" ;. Pruebe simplemente :"old<<"
, o si realmente quiere, <=> (pero diviértase llamándolo con ese nombre).
Otros consejos
Solo se permiten ciertos caracteres en literales de símbolos. Estás buscando:
alias :"old<<" :"<<"
Como otros ya han explicado, el problema es simplemente que old<<
no es un identificador legal de Ruby. Puede, con trucos, crear un método con ese nombre, pero no puede llamarlo de la manera normal, y ciertamente no será reconocido como un operador.
Sin embargo, todas las respuestas hasta ahora, aunque ciertamente han respondido a su pregunta, han ignorado por completo el problema subyacente : ¡ese método ni siquiera debería tener un nombre en primer lugar! Y si no tiene un nombre, entonces el problema de que el nombre sea ilegal simplemente ni siquiera surge.
#!/usr/bin/env ruby
require 'test/unit'
require 'stringio'
class TestOperatorDecorator < Test::Unit::TestCase
def setup; @old_stdout, $> = $>, (@fake_stdout = StringIO.new) end
def teardown; $> = @old_stdout end
def test_that_me_dot_append_writes_to_stdio
me = 'this is a string'
class << me
old_method = instance_method :<<
define_method :<< do |text|
old_method.bind(self).(text)
puts "appended #{text}"
end
end
me << 'Test'
assert_equal "appended Test\n", @fake_stdout.string
end
end
En este caso, el método nunca se nombra, lo que no solo significa que no tenemos que inventar un nombre para él, sino que también contamina el espacio de nombres.
El problema es con :old<<
. Se interpreta como :old <<
, es decir, un símbolo :old
seguido del operador <<
, por lo que es un error de sintaxis. Quizás puedas probar :"old<<"
?
Si bien estoy de acuerdo con thenduks y ephemient, puede alias al operador de esa manera y luego usar send para llamarlo, pero también puede usar herencia de clase. por ejemplo:
me = "is a string"
class << me
def <<(text)
super
puts "appended #{text}"
end
end
me << " bob"
puts me #=> is a string appended bob