Могут ли операторы Ruby иметь псевдонимы?
-
05-07-2019 - |
Вопрос
Мне интересно, как можно заставить это работать:
me = "this is a string"
class << me
alias :old<< :<<
def <<(text)
old<<(text)
puts "appended #{text}"
end
end
Мне бы хотелось, чтобы при добавлении чего-либо в переменную me
объект использовал переопределенный метод.
Если я попытаюсь выполнить это, я получу syntax error, unexpected ':', expecting kEND
на :<<
.
Решение
:old<<
выглядит как " :old
<<
" ;. Попробуйте просто :"old<<"
, или, если хотите, <=> (но получайте удовольствие, называя это через это имя).
Другие советы
В символьных литералах допускаются только определенные символы. Вы ищете:
alias :"old<<" :"<<"
Как уже объясняли другие, проблема в том, что old<<
не является допустимым идентификатором Ruby. С помощью хитростей вы можете создать метод с таким именем, но вы не можете вызывать его обычными способами, и он, безусловно, не будет распознаваться как оператор.
Тем не менее, все ответы, хотя они наверняка ответили на ваш вопрос, полностью проигнорировали проблему , лежащую в основе : у этого метода вообще не должно быть имени! И если у него нет имени, то проблема его незаконности просто не возникает.
#!/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
В этом случае метод никогда не получает имя, что означает не только то, что нам не нужно придумывать имя для него, но и то, что он не загрязняет пространство имен.
Проблема в :old<<
. Он интерпретируется как :old <<
, то есть символ :old
, за которым следует оператор <<
, поэтому это синтаксическая ошибка. Может быть, вы можете попробовать :"old<<"
?
Хотя я согласен с thenduks и ephemient, вы можете использовать псевдоним оператора таким образом, а затем использовать send для его вызова, вы также можете использовать наследование классов. например:.
me = "is a string"
class << me
def <<(text)
super
puts "appended #{text}"
end
end
me << " bob"
puts me #=> is a string appended bob