Ruby运算符可以别名吗?

时间:2009-10-22 18:11:34

标签: ruby operators metaprogramming monkeypatching

我对如何让这个工作变得感兴趣:

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 个答案:

答案 0 :(得分:7)

符号文字中只允许使用某些字符。您正在寻找:

alias :"old<<" :"<<"

答案 1 :(得分:3)

:old<<看起来像“:old <<”。试试:old,或者如果你真的想要,:"old<<"(但请通过该名称来调用它)。

答案 2 :(得分:2)

正如其他人已经解释的那样,问题只是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

在这种情况下,该方法永远不会被命名,这不仅意味着我们不必为它创建一个名称,它还意味着它不会污染命名空间。

答案 3 :(得分:1)

问题在于:old<<。它被解释为:old <<,即符号:old后跟<<运算符,因此它是语法错误。也许你可以试试:"old<<"

答案 4 :(得分:0)

虽然我同意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