Ruby のグローバル プロシージャは、実際にはグローバル プロシージャではありません。それらは、他のすべてと同様にメソッドです。特に、グローバル プロシージャのように見えるものを定義すると、実際には のプライベート インスタンス メソッドを定義することになりますObject
。Ruby のすべてのコードはオブジェクトのコンテキストで評価されるため、これらのメソッドをグローバル プロシージャであるかのように使用できself
ます。self
Object
したがって、この:
# file1.rb
def foo
puts 123
end
実際には同等です
# file1.rb
class Object
private
def foo
puts 123
end
end
これで、 という「グローバル プロシージャ」foo
ができました。これは、次のように呼び出すことができます。
foo
このように呼び出すことができる理由は、この呼び出しが実際には
self.foo
祖先チェーンにself
含まれるオブジェクトであるため、プライベートメソッドを継承します。Object
foo
[注: 正確には、プライベート メソッドは明示的なレシーバーで呼び出すことはできませんself
。したがって、本当に詳しく言うと、実際には同等でself.send(:foo)
あり、そうではありませんself.foo
。]
A.new.foo
あなたのfile2.rb
場合はニシンです:Object.new.foo
または[].foo
または42.foo
を試しても同じ結果が得られます。
ところで、puts
とrequire
はそれ自体がそのような「グローバル プロシージャ」の例であり、実際には のプライベート メソッドですObject
(より正確には、Kernel
が に混在するプライベート メソッドですObject
)。
補足:への呼び出しをクラス定義内に置くのは本当に悪いスタイルです。これは、 d コードが何らかの形でクラス内でスコープまたは名前空間化されているように見えるためです。これはもちろん false です。ファイル内のコードを実行するだけで、それ以上は何もありません。require
require
require
だから、その間
# file2.rb
class A
require 'file1.rb'
end
は完全に有効なコードですが、非常に紛らわしいものでもあります。次の意味的に同等のコードを使用する方がはるかに優れています。
# file2.rb
require 'file1.rb'
class A
end
そうすれば、file1.rb
内でスコープや名前空間がまったく設定されていないコードの読者には完全に明確になりますA
。
また、一般に、ファイル拡張子を付けないこと、require 'file1'
つまりrequire 'file1.rb'
. これにより、Ruby ファイルをネイティブ コード (MRI、YARV、Rubinius、MacRuby、JRuby の場合)、.jar
または.class
ファイル内の JVM バイト コード (JRuby の場合)、ファイル内の CIL バイト コード.dll
(IronRuby の場合)、およびrequire
呼び出しを変更する必要はありません。
最後のコメント: アクセス保護を回避する慣用的な方法は、 ではsend
なくを使用することです。instance_eval
つまり、A.new.send(:foo)
の代わりに使用しA.new.instance_eval {foo}
ます。