方法名称在Object#singleton_methods返回的列表中,但无法使用Object#singleton_method

时间:2018-04-01 10:34:18

标签: ruby activesupport

我对Object#singleton_methodObject#singleton_methods之间的区别感到困惑。

我认为Object#singleton_methods中的结果是!!Object#singleton_method(:name)的真实集合,但似乎有所不同。

以下是示例脚本:

require "active_support/deprecation"
# [:debug=, :debug]
ActiveSupport::Deprecation.singleton_methods(false).grep(/debug/)
# [:debug=, :debug]
ActiveSupport::Deprecation.singleton_methods.grep(/debug/) 

begin
  ActiveSupport::Deprecation.singleton_method(:debug) # exception
rescue => e
  puts e.backtrace
  raise
end

Gemfile是

# frozen_string_literal: true

source "https://rubygems.org"

git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }

# gem "rails"
gem 'activesupport', '5.1.6'

结果如下:

% bundle install
Fetching gem metadata from https://rubygems.org/..............
Resolving dependencies...
Using concurrent-ruby 1.0.5
Using i18n 1.0.0
Using minitest 5.11.3
Using thread_safe 0.3.6
Using tzinfo 1.2.5
Using activesupport 5.1.6
Using bundler 1.16.1
Bundle complete! 1 Gemfile dependency, 7 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
% bundle exec ruby test.rb
test.rb:8:in `singleton_method'
test.rb:8:in `<main>'
Traceback (most recent call last):
    1: from test.rb:8:in `<main>'
test.rb:8:in `singleton_method': undefined singleton method `debug' for `ActiveSupport::Deprecation' (NameError)

我希望ActiveSupport::Deprecation.singleton_method(:debug)会返回#<Method: ActiveSupport::Deprecation.debug>,但会引发异常。

我不明白为什么。当然,我知道singleton_methodsingleton_methods中的基本用法:

# everything is OK!
class Sample; end

class << Sample
  def test_method; end
end

# These two expressions behave as I expect.
## [:test_method]
Sample.singleton_methods(false).grep(/test_method/) 
## #<Method: Sample.test_method>
Sample.singleton_method(:test_method)

感谢。

1 个答案:

答案 0 :(得分:2)

更新:看起来这是Ruby中的一个错误。 Vasiliy Ermolovich创建了an issue以及一个补丁来解决它。修复程序已经合并,因此将在即将发布的更新中解决。

这不是我害怕的问题的完整答案,但经过一些挖掘后,我已经能够制作一个最小的例子来演示同样的事情而不依赖于Active Support。我认为这可能对您的调查仍然有用,或者可能会帮助其他可以提供完整解释的人。

singleton_method的意外行为似乎来自使用Module.prepend使用ActiveSupport::Deprecation heremodule Empty; end class MyClass singleton_class.prepend(Empty) def self.my_method puts "my method called" end end p MyClass.singleton_methods(:false) m = MyClass.singleton_method(:my_method) m.call

这个小例子可以看到同样的错误:

❯ ruby example.rb
[:my_method]
Traceback (most recent call last):
    1: from example.rb:11:in `<main>'
example.rb:11:in `singleton_method': undefined singleton method `my_method' for
`MyClass' (NameError)

运行此命令:

prepend

删除了对❯ ruby example.rb [:my_method] my method called 的调用后,会按照您的预期运行:

active