有没有一种优雅的方法来测试一个实例方法是否是另一个实例方法的别名?

发布于 2024-09-26 06:17:13 字数 436 浏览 9 评论 0原文

在单元测试中,我需要测试 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

建议?

In a unit test I need to test whether alias methods defined by alias_method have been properly defined. I could simply use the same tests on the aliases used for their originals, but I'm wondering whether there's a more definitive or efficient solution. For instance, is there a way to 1) dereference a method alias and return its original's name, 2) get and compare some kind of underlying method identifier or address, or 3) get and compare method definitions? For example:

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

Suggestions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

星軌x 2024-10-03 06:17:13

根据方法的文档,

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

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

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

According to the documentation for Method,

Two method objects are equal if they
are bound to the same object and
contain the same body.

Calling Object#method and comparing the Method objects that it returns will verify that the methods are equivalent:

m.method(:bar) == m.method(:foo)
绝影如岚 2024-10-03 06:17:13

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),但它们Ruby 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 调用会调用不同的方法;这不是一个错误。

bk1e's method works most of the time, but I just happened to hit the case where it doesn't work:

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

The output is produced in Ruby 1.9, not sure if it's a bug or not since Ruby 1.8 produces true for the last line. So, if you are using 1.9, be careful if you are aliasing an inherited class method (like Class#new), These two methods are bound to the same object (the class object Stream), but they are considered not equivalent by Ruby 1.9.

My workaround is simple - alias the original method again and test the equality of the two aliases:

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

Hope this helps.

UPDATE:

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

So Method#== should return false in this case since a super call would invoke different methods; it is not a bug.

送舟行 2024-10-03 06:17:13

调用 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

Calling MyClass.instance_method(:foo) will result UnboundMethod instance, which has eql? method.

So the answer is:

describe MyClass do
  subject { described_class }

  specify do
    expect(subject.instance_method(:foo)).to be_eql(subject.instance_method(:bar))
  end
end
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文