方法名称在 Object#singleton_methods 返回的列表中,但无法使用 Object#singleton_method 访问
Method name is in list returned by Object#singleton_methods but not accessible using Object#singleton_method
我对 Object#singleton_method
和 Object#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)
会 return #<Method: ActiveSupport::Deprecation.debug>
,但引发异常。
我不明白为什么。当然,我知道singleton_method
和singleton_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)
谢谢。
更新: 看起来这是 Ruby 中的错误。 Vasiliy Ermolovich has created an issue 以及解决该问题的补丁。该修复程序已合并,因此将在即将发布的更新中解决。
恐怕这不是您问题的完整答案,但经过一些挖掘我已经能够制作一个最小的示例来演示相同的事情而不依赖于 Active Support。我认为这可能对您的调查仍然有用,或者可能会帮助其他人提供完整的解释。
似乎 singleton_method
的意外行为来自对 Module.prepend
的使用,而 ActiveSupport::Deprecation
使用 here。
这个小例子可以看出同样的错误:
module 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
我对 Object#singleton_method
和 Object#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)
会 return #<Method: ActiveSupport::Deprecation.debug>
,但引发异常。
我不明白为什么。当然,我知道singleton_method
和singleton_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)
谢谢。
更新: 看起来这是 Ruby 中的错误。 Vasiliy Ermolovich has created an issue 以及解决该问题的补丁。该修复程序已合并,因此将在即将发布的更新中解决。
恐怕这不是您问题的完整答案,但经过一些挖掘我已经能够制作一个最小的示例来演示相同的事情而不依赖于 Active Support。我认为这可能对您的调查仍然有用,或者可能会帮助其他人提供完整的解释。
似乎 singleton_method
的意外行为来自对 Module.prepend
的使用,而 ActiveSupport::Deprecation
使用 here。
这个小例子可以看出同样的错误:
module 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