[英]Calling a singleton method within an instance method in a module that extends itself
我自己擴展了Kernel
,並且在實例方法Kernel#abort
的定義中,我調用了單例方法Kernel.abort
:
module Kernel
extend self
def abort
puts "Press ENTER to exit..."
gets
Kernel.abort
end
end
abort
當我調用Kernel#abort
,似乎方法定義中的Kernel.abort
調用引用了原始Kernel#abort
Kernel.abort
(擴展為Kernel.abort
)。
Ruby如何知道當我編寫Kernel.abort
,我的意思是原始的abort
方法,而不是我剛創建的方法? 我將如何遞歸調用剛剛創建的新abort
方法?
Kernel.abort
的定義是首先定義一個實例方法Kernel#abort
,然后使它成為一個帶有module_function
的單例方法。 ( 這在Rubinius中肯定是這種情況 ;我在MRI源中找不到它,但見下文。) module_function
復制了該方法。 重新定義abort
,重新定義實例方法,但不重新定義單例副本。
Object
包括Kernel
,所以當你說abort
你得到了你重新定義的實例方法,但是當你說Kernel.abort
你會得到你沒有重新定義的單例方法。
如果您真的想在abort
使用遞歸,或者只是為了證明這種解釋是正確的,請在重新定義方法后調用module_function :abort
。 單例方法將更新為與實例方法相同,並且兩種方法都將遞歸。
請注意,您不需要extend self
來重新定義abort
的實例版本。 由於Kernel
已包含在Object
,因此您只需要為所有對象重新定義實例方法以查看重新定義的版本。 另一方面,如果Kernel
首先使用extend self
來暴露#abort
,我們可以重新定義它而不會出現任何復雜情況。
下面演示了用戶定義的純Ruby方法缺少遞歸,即module_function
是負責人而本機方法不是:
$ cat foo.rb
module Foo
def bar
puts "old version"
end
module_function :bar
end
module Foo
def bar
puts "new version"
Foo.bar
end
end
Object.include Foo
bar
$ ruby foo.rb
new version
old version
你應該做這樣的事情:
module Kernel
class << self
alias :real_abort :abort
def abort
puts "press enter"
gets
puts "invoking real abort"
real_abort
end
end
end
IRB調用原始中止而不是您定義的abort
的原因是因為IRB repl有一個中止它的C語言變體的中止方法。
你可以通過在pry上做show-source
來看到它
[1] pry(main)> show-source abort
From: process.c (C Method):
Owner: Kernel
Visibility: private
Number of lines: 22
VALUE
rb_f_abort(int argc, const VALUE *argv)
{
rb_check_arity(argc, 0, 1);
if (argc == 0) {
if (!NIL_P(GET_THREAD()->errinfo)) {
ruby_error_print();
}
rb_exit(EXIT_FAILURE);
}
else {
VALUE args[2];
args[1] = args[0] = argv[0];
StringValue(args[0]);
rb_io_puts(1, args, rb_stderr);
args[0] = INT2NUM(EXIT_FAILURE);
rb_exc_raise(rb_class_new_instance(2, args, rb_eSystemExit));
}
UNREACHABLE;
}
在您提到的代碼中,正在執行的中止不是Kernel.abort,而是從命令行調用它時映射到IRB的C語言中止
如果你想要它被屏蔽你可以做這樣的事情,以便IRB repl中的abort
將執行你重新定義的abort
def abort; Kernel.abort; end
然后,如果你運行abort
,它將調用你重新定義的內核的中止單例方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.