Могут ли операторы Ruby иметь псевдонимы? - PullRequest
1 голос
/ 22 октября 2009

Меня интересует, как можно заставить это работать:

me = "this is a string"
class << me
  alias :old<< :<<
  def <<(text)
    old<<(text)
    puts "appended #{text}"
  end
end

Мне бы хотелось, чтобы при добавлении чего-либо к переменной me объект использовал переопределенный метод.

Если я попытаюсь запустить это, я получу syntax error, unexpected ':', expecting kEND на :<<.

Ответы [ 5 ]

7 голосов
/ 22 октября 2009

В символьных литералах допускаются только определенные символы. Вы ищете:

alias :"old<<" :"<<"
3 голосов
/ 22 октября 2009

:old<< выглядит как ":old <<". Попробуйте просто :old, или, если вы действительно хотите, :"old<<" (но получайте удовольствие, называя это через это имя).

2 голосов
/ 24 октября 2009

Как уже объяснили другие, проблема в том, что 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

В этом случае метод никогда не получает имя, что означает не только то, что нам не нужно придумывать имя для него, но и то, что он не загрязняет пространство имен.

1 голос
/ 22 октября 2009

Проблема с :old<<. Он интерпретируется как :old <<, то есть символ :old, за которым следует оператор <<, так что это синтаксическая ошибка. Может быть, вы можете попробовать :"old<<"?

0 голосов
/ 01 июля 2010

Хотя я согласен с thenduks и ephemient, вы можете использовать псевдоним оператора таким образом, а затем использовать send для его вызова, вы также можете использовать наследование классов. e.g.:

me = "is a string"

class << me
  def <<(text)
    super
    puts "appended #{text}"
  end
end

me << " bob"
puts me #=> is a string appended bob
...