Rubyのオブジェクトは生物なんかじゃない、トップレベルこそが生物なんだ!
RubyのTopLevelは不思議だ。Rubyはオブジェクト指向言語だから普通まずクラスでオブジェクトを定義し、これをインスタンス化し、この生まれたオブジェクトにメッセージを送る、という手続きを経てプログラムが組成される。
class Person
def initialize(name)
@name = name
end
def name
@name
end
end
me = Person.new("Charlie")
me.name # => "Charlie"
でもTopLevelではそんな手続きを吹っ飛ばして、いきなりメソッドが実行できたり書けたりする。
rand(10) # => 4
def hello(name)
puts "hello, #{name}"
end
hello("Charlie")
# >> hello, Charlie
なぜ?メソッドのレシーバは誰?此処は一体どこ?
それを知るにはselfが使える。
self # => main
ここはどうやらmainらしい。Rubyの操作対象はすべてオブジェクトだから、mainもきっとオブジェクトに違いない。とすればIDを持っているはずだ。
self.object_id # => 107690
やはりオブジェクトだった。そうなると当然にその基となるクラスが存在するはずだ。
self.class # => Object
クラスはObjectクラスだった。mainはObjectクラスのインスタンスなんだ。だからObjectクラスに定義されたinstanceメソッドが使えるんだな。他にも使えるメソッドを調べてみよう。
self.methods.sort # => ["==", "===", "=~", "__id__", "__send__", "class", "clone", "display", "dup", "enum_for", "eql?", "equal?", "extend", "freeze", "frozen?", "hash", "id", "include", "inspect", "instance_eval", "instance_exec", "instance_of?", "instance_variable_defined?", "instance_variable_get", "instance_variable_set", "instance_variables", "is_a?", "kind_of?", "method", "methods", "nil?", "object_id", "private", "private_methods", "protected_methods", "public", "public_methods", "respond_to?", "send", "singleton_methods", "taint", "tainted?", "tap", "to_a", "to_enum", "to_s", "type", "untaint"]
ずいぶんあるけどちょっと変だな。さっき使ったrandも定義したhelloもこのリストにはないぞ。レシーバがはっきりしたんだから、もう一度レシーバを明示してメソッドを呼んでみよう。
main.rand(10) # =>
# ~> -:10: undefined local variable or method `main' for main:Object (NameError)
main.hello("Charlie") # =>
# ~> -:10: undefined local variable or method `main' for main:Object (NameError)
だめだ。selfでどうかな。
self.hello("Charlie") # =>
# ~> -:10: private method `hello' called for main:Object (NoMethodError)
self.rand(10) # =>
# ~> -:10: private method `rand' called for main:Object (NoMethodError)
あれ?randもhelloもprivateメソッドて書いてあるぞ!
privateメソッドっていうのは確か、レシーバを明示しては呼び出せないメソッドだったよね。じゃあmainのprivateメソッドのリストを見てみようか。
self.private_methods.sort # => ["Array", "Float", "Integer", "String", "__method__", "`", "abort", "at_exit", "autoload", "autoload?", "binding", "block_given?", "callcc", "caller", "catch", "chomp", "chomp!", "chop", "chop!", "eval", "exec", "exit", "exit!", "fail", "fork", "format", "getc", "gets", "global_variables", "gsub", "gsub!", "hello", "initialize", "initialize_copy", "iterator?", "lambda", "load", "local_variables", "loop", "method_missing", "open", "p", "print", "printf", "proc", "putc", "puts", "raise", "rand", "readline", "readlines", "remove_instance_variable", "require", "scan", "select", "set_trace_func", "singleton_method_added", "singleton_method_removed", "singleton_method_undefined", "sleep", "split", "sprintf", "srand", "sub", "sub!", "syscall", "system", "test", "throw", "trace_var", "trap", "untrace_var", "warn"]
リストが長くて見つけられないなあ。じゃあスーパークラスのものを除外して表示してみよう。
self.private_methods(false) # => ["initialize", "hello"]
helloがあったぞ!でも、ずいぶんときれいさっぱり他のメソッドが無くなっちゃったね。randも見つからないし。スーパークラスにあるのかな?
あれ?ちょっと待った。mainのクラスはObjectだったよね。それにスーパークラスなんてあるの?
Object.superclass # => nil
やっぱり無い1。じゃあさっきの長いメソッドリストはどこから来たの?
そうか!きっとモジュールだよ。Objectクラスには他のモジュールがMix-inされていて、そのモジュールにさっきのメソッドたちが定義されてるんだ。調べてみよう。
Object.included_modules # => [Kernel]
KernelというモジュールがMix-inされている。じゃあKernelに定義されているprivateなInstanceメソッドをリストしてみよう。
Kernel.private_instance_methods.sort # => ["Array", "Float", "Integer", "String", "__method__", "`", "abort", "at_exit", "autoload", "autoload?", "binding", "block_given?", "callcc", "caller", "catch", "chomp", "chomp!", "chop", "chop!", "eval", "exec", "exit", "exit!", "fail", "fork", "format", "getc", "gets", "global_variables", "gsub", "gsub!", "initialize_copy", "iterator?", "lambda", "load", "local_variables", "loop", "method_missing", "open", "p", "print", "printf", "proc", "putc", "puts", "raise", "rand", "readline", "readlines", "remove_instance_variable", "require", "scan", "select", "set_trace_func", "singleton_method_added", "singleton_method_removed", "singleton_method_undefined", "sleep", "split", "sprintf", "srand", "sub", "sub!", "syscall", "system", "test", "throw", "trace_var", "trap", "untrace_var", "warn"]
今度は目を凝らしてみつけるぞ。randがあったぞ!randはKernelモジュールに定義されたprivateメソッドだったんだ。するとここに並んでいるメソッドはTopLevelで使えるんだね。じゃあKernelにメソッドを定義して、TopLevelで呼べるか試してみよう。
module Kernel
private
def kernel_private_hello
"hello of Kernel Private called from #{self}"
end
end
kernel_private_hello # => "hello of Kernel Private called from main"
うまくいった。
でも不思議だなあ。mainはオブジェクトなのにKernelのprivateメソッドがなぜ使えるんだろう。ここがObjectクラス内だったら分かるんだけど…
それからなぜオブジェクトにhelloメソッドが定義できたんだろう。メソッド定義はクラスにしかできないと思ってたのに…
もしかして…
そうかSingletonメソッドがあるじゃないか。helloはきっとmainのSingletonメソッドになってるんだよ。
self.singleton_methods # => ["public", "to_s", "include", "private"]
違った…
なんか違うの出てきちゃったな。
試しにSingletonメソッドをTopLevelで定義して、ここにリストアップされるか見てみよう。
def self.toplevel_singleton_hello
"hello of TopLevl Singleton from #{self}}"
end
class << self
def toplevel_singleton_class_hello
"hello of TopLevel Singleton Class from #{self}"
end
end
toplevel_singleton_hello # => "hello of TopLevl Singleton from main}"
toplevel_singleton_class_hello # => "hello of TopLevel Singleton Class from main"
self.singleton_methods # => ["public", "toplevel_singleton_class_hello", "to_s", "include", "toplevel_singleton_hello", "private"]
ちゃんとリストアップされるなあ。やっぱりここはmainオブジェクトだよ。
まさか…
ここはObjectクラス?試しにObjectクラスが持っているprivateなinstanceメソッドを調べてみよう。
Object.private_instance_methods(false) # => ["initialize", "hello"]
あっ!TopLevelで定義したhelloがある!
つまりここは…
Objectクラスの中なんだ!これでprivateメソッドが呼べるのにも筋が通る。
よしもう一つ確かめてみよう。ここがObjectクラスの中なら、そこに定義されるクラスはネストされたクラスになるはずだ。
class Nested
end
Object::Nested # => Nested
::Nested # => Nested
Object::Nested.new # => #<Nested:0x1bf58>
Object.constants.detect{ |c| c =~ /^Ne/ } # => "Nested"
確かにObjectにネストされているぞ。
これで答えが出た。
RubyのTopLevelはObjectクラスであり、かつ、そのインスタンスであるmainオブジェクトだったんだ!だからそこでクラスとしてinstanceメソッドを定義でき、しかもそのメソッドをそのインスタンスとして呼び出せる。
つまり自身で自身を作るという自己増殖の機能を備えている!
そうRubyのTopLevelは…
生物だったんだ!
不思議の国Rubyでは、ClassクラスがClassクラスを生成するように、TopLevelがTopLevelを生成していたんだ!
- Ruby1.9ではBasicObjectがある ↩
blog comments powered by Disqus