【问题标题】:Is there an elegant way to test if one instance method is an alias for another?有没有一种优雅的方法来测试一个实例方法是否是另一个实例方法的别名?
【发布时间】:2010-10-06 05:21:18
【问题描述】:

在单元测试中,我需要测试由 alias_method 定义的别名方法是否已正确定义。我可以简单地对用于其原件的别名使用相同的测试,但我想知道是否有更明确或更有效的解决方案。例如,有没有办法 1) 取消引用方法别名并返回其原始名称,2) 获取并比较某种底层方法标识符或地址,或 3) 获取并比较方法定义?例如:

class MyClass
  def foo
    # do something
  end

  alias_method :bar, :foo
end

describe MyClass do
  it "method bar should be an alias for method foo" do
    m = MyClass.new
    # ??? identity(m.bar).should == identity(m.foo) ???
  end
end

建议?

【问题讨论】:

标签: ruby reflection alias-method


【解决方案1】:

根据Method 的文档,

两个方法对象相等,如果 绑定到同一个对象并且 包含相同的主体。

调用Object#method 并比较它返回的Method 对象将验证方法是否等效:

m.method(:bar) == m.method(:foo)

【讨论】:

  • 我确定我记得这不起作用,但我只是尝试确认它在 Ruby 1.8、1.9 和 MacRuby 中始终如一地工作。但我仍然没有在 RubySpec 中看到它,所以它很可能无法在不相关的实现上工作。
  • 此外,一般来说,仅具有相同主体但不相互复制的方法强调相等。证明:Class.new{def foo() end; def bar() end; puts instance_method(:foo)==instance_method(:bar)}
  • @Chuck:感谢您指出这一点。我应该尝试一下。
  • 另外,github.com/rubyspec/rubyspec/blob/master/core/method/… + github.com/rubyspec/rubyspec/blob/master/core/method/shared/… 中的“在别名方法上返回 true”似乎涵盖了 m.method(:bar) == m.method(:foo),其中一个是另一个的别名。
【解决方案2】:

bk1e的方法大部分时间都有效,但我刚好碰到了不起作用的情况:

class Stream
  class << self
    alias_method :open, :new
  end
end

open = Stream.method(:open)
new = Stream.method(:new)
p open, new                   # => #<Method: Stream.new>, #<Method: Class#new>
p open.receiver, new.receiver # => Stream, Stream
p open == new                 # => false

输出是在 Ruby 1.9 中生成的,不确定这是否是一个错误,因为 Ruby 1.8 为最后一行生成了true。因此,如果您使用的是 1.9,请小心为继承的类方法(如 Class#new)设置别名,这两个方法绑定到同一个对象(类对象 Stream),但它们被认为不等效红宝石 1.9。

我的解决方法很简单 - 再次为原始方法设置别名并测试两个别名的相等性:

class << Stream; alias_method :alias_test_open, :new; end
open = Stream.method(:open)
alias_test_open = Stream.method(:alias_test_open)
p open, alias_test_open                   # => #<Method: Stream.new>, #<Method: Stream.new>
p open.receiver, alias_test_open.receiver # => Stream, Stream
p open == alias_test_open                 # => true

希望这会有所帮助。

更新:

http://bugs.ruby-lang.org/issues/7613

所以Method#== 在这种情况下应该返回false,因为super 调用会调用不同的方法;这不是错误。

【讨论】:

    【解决方案3】:

    调用MyClass.instance_method(:foo) 将产生UnboundMethod 实例,该实例具有eql? 方法。

    所以答案是:

    describe MyClass do
      subject { described_class }
    
      specify do
        expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar))
      end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-10-15
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 2018-07-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多