【问题标题】:Can Ruby operators be aliased?Ruby 运算符可以别名吗?
【发布时间】:2009-10-22 18:11:33
【问题描述】:

我对如何让它发挥作用很感兴趣:

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

我希望当某些东西被附加到 me 变量时,该对象将使用重新定义的方法。

如果我尝试运行它,我会在:&lt;&lt; 收到syntax error, unexpected ':', expecting kEND

【问题讨论】:

    标签: ruby operators metaprogramming monkeypatching


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      :old&lt;&lt; 看起来像“:old&lt;&lt;”。试试:old,或者如果你真的想,:"old&lt;&lt;"(但用那个名字叫它很有趣)。

      【讨论】:

      • 假设我真的很想称它为:old&lt;&lt;。调用它的唯一方法是send吗?
      • 我认为这很愚蠢——为什么不直接选择真实姓名呢? -- 但是是的,send(:"old&lt;&lt;", text) 会起作用。顺便说一句,我想不出任何其他方法来调用这样一个奇怪的名字。
      • 我第一次在 Ruby 中为 setter 方法设置别名时实际上做了类似的事情。我将别名命名为“old_value=”。由于明显的原因,这行不通:)
      【解决方案3】:

      正如其他人已经解释的那样,问题只是 old&lt;&lt; 不是合法的 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
      

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

      【讨论】:

        【解决方案4】:

        问题在于:old&lt;&lt;。它被解释为:old &lt;&lt;,即符号:old 后跟&lt;&lt; 运算符,因此这是一个语法错误。或许你可以试试:"old&lt;&lt;"

        【讨论】:

          【解决方案5】:

          虽然我同意 thenduks 和 ehemient,但您可以这样为运算符起别名,然后使用 send 来调用它,您还可以使用类继承。例如:

          me = "is a string"
          
          class << me
            def <<(text)
              super
              puts "appended #{text}"
            end
          end
          
          me << " bob"
          puts me #=> is a string appended bob
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-05-15
            • 1970-01-01
            • 2021-03-28
            • 2012-10-15
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多