- ゴーストメソッドを追加。(8/18)
- オープンクラス、名前無しクラスを追加。(8/15)
- extend、sendを追加。(8/31)
TL;DR
- classはClassクラスのオブジェクト、moduleはModuleクラスのオブジェクト、である
- 特異クラスは
class << object
で、あるobjectに特異な(特別な)メソッドをまとめて定義する
- 特異メソッドは
def object.method
で、あるobjectに特異な(特別な)メソッドを定義する
- 他言語でクラスメソッドと呼ばれるものは、rubyではclassオブジェクトの特異メソッドと言える
class << self ... end
では、self.
を付けずにclassオブジェクトの特異メソッド(クラスメソッド)を宣言する
- instance_evalの引数ブロックは、レシーバの特異クラスのコンテキストで実行されるので、アクセサ(getter)の定義されていないインスタンス変数にもアクセスできるし、新たなインスタンス変数を与えることもできる
include module
はミックスインであり、C++の多重継承やJavaのインターフェースが無いRubyにおいて、共通化されたメソッドをオブジェクトに結びつける手段となる
- module_functionはメソッドのprivate指定、かつ、moduleオブジェクトにおける特異メソッド化
- オブジェクトa1のメソッドm14の呼び出しにおいて、instance_evalで新たに与えたインスタンス変数
@j
へアクセスできている点から、オープンクラスのモンキーパッチでclass Aに与えたメソッドm14が、a1の特異クラスのコンテキストで実行されていることが分かる
- class Aのmethod_missingでdefine_methodしたインスタンスメソッドm16を、AのサブクラスA_のインスタンスa3から呼び出すことができる
- sendは可視性を問わずアクセスできるので、private指定したメソッドm18を呼び出せる
プログラム
$ cat meta.rb
puts "== Self check outside of class =="
p self
p self.class
module M
puts "== Self check inside of module =="
p self
p self.class
def m10;p __method__ end
def m11;p __method__ end
def m12;p __method__ end
module_function :m11,:m12
end
class A
puts "== Self check inside of class =="
p self
p self.class
include M
def initialize(i)
puts "== Self check inside of method =="
p self
p self.class
@i=i
end
def m1;p __method__ end
def self.m2;p __method__ end
class << self
def m3;p __method__ end
end
def m12; puts __method__.to_s+"!!" end
end
def A.m4;p __method__ end
a1=A.new(1)
a2=A.new(2)
A_=Class.new(A){|c|
def m15; p __method__ end
}
a3=A_.new(3)
puts "== class check =="
p A.class
p M.class
p a1.class
p a2.class
p a3.class
puts ""
def a1.m5;p __method__ end
puts "== class A methods list == "
p A.methods.grep(/^m[0-9]/)
puts "== class A instance methods list == "
p A.instance_methods.grep(/^m[0-9]/)
puts "== module M methods list == "
p M.methods.grep(/^m[0-9]/)
puts "== module M instance methods list == "
p M.instance_methods.grep(/^m[0-9]/)
puts "== object a1 methods list == "
p a1.methods.grep(/^m[0-9]/)
puts "== object a2 methods list == "
p a2.methods.grep(/^m[0-9]/)
puts ""
puts "== object a1 instance_eval == "
a1.instance_eval{p@i}
a1.instance_eval{@j=@i*10}
a1.instance_eval{p@j}
puts "== object a2 instance_eval == "
a2.instance_eval{p@i}
a2.instance_eval{@i=@i*20}
a2.instance_eval{p@i}
a2.instance_eval{p@j}
puts ""
puts "== Call instance_eval for m6 and m7 =="
instance_eval File.read('meta.txt')
puts ""
puts "== Call define_method for m8 =="
class<<A;define_method(:m8){p __method__}end
puts ""
puts "== Call class_eval and define_method for m9 =="
pc=Proc.new{p __method__}
A.class_eval{define_method(:m9,pc)}
puts ""
puts "== Open class, monkey patch for m13 and m14 =="
class A
def m13; p @i end
def m14; p @j end
end
puts ""
puts "== Define method_missing for class A and its instance =="
class A
def self.method_missing(m,*a)
puts __method__.to_s+"(#{m})"
define_method(m){p __method__}
end
def method_missing(m,*a)
puts __method__.to_s+"<#{m}>"
end
end
puts ""
module M_
def m17;p __method__ end
def m18;p __method__ end
private :m18
end
puts "== Extend M_ with a3 =="
a3.extend(M_)
puts ""
r=(0..18)
puts "== class A methods respond_to? check =="
r.each{|n|print "m#{n} "; if A.respond_to?"m#{n}".to_sym; eval "A.m#{n}"; else puts "-" end}
puts "== module M methods respond_to? check =="
r.each{|n|print "m#{n} "; if M.respond_to?"m#{n}".to_sym; eval "M.m#{n}"; else puts "-" end}
puts "== object a1 methods respond_to? check =="
r.each{|n|print "m#{n} "; if a1.respond_to?"m#{n}".to_sym; eval "a1.m#{n}"; else puts "-" end}
puts "== object a2 methods respond_to? check =="
r.each{|n|print "m#{n} "; if a2.respond_to?"m#{n}".to_sym; eval "a2.m#{n}"; else puts "-" end}
puts "== class A_ methods respond_to? check =="
r.each{|n|print "m#{n} "; if A_.respond_to?"m#{n}".to_sym; eval "A_.m#{n}"; else puts "-" end}
puts "== module M_ methods respond_to? check =="
r.each{|n|print "m#{n} "; if M_.respond_to?"m#{n}".to_sym; eval "M_.m#{n}"; else puts "-" end}
puts "== object a3 methods respond_to? check =="
r.each{|n|print "m#{n} "; if a3.respond_to?"m#{n}".to_sym; eval "a3.m#{n}"; else puts "-" end}
puts ""
puts "== Call m16 from a1, A, a2 and a3 =="
a1.m16
A.m16
a2.m16
a3.m16
puts ""
puts "== Send m17, private method m18 and call m18 from a3 =="
a3.send("m17")
a3.send("m18")
a3.m18
puts ""
$ cat meta.txt
def A.m6;p __method__ end
def a2.m7;p __method__ end
実行結果
$ ruby meta.rb
== Self check outside of class ==
main
Object
== Self check inside of module ==
M
Module
== Self check inside of class ==
A
Class
== Self check inside of method ==
#<A:0x007f86009fb1a8>
A
== Self check inside of method ==
#<A:0x007f86009fb018>
A
== Self check inside of method ==
#<A_:0x007f86009fade8>
A_
== class check ==
Class
Module
A
A
A_
== class A methods list ==
[:m2, :m3, :m4]
== class A instance methods list ==
[:m1, :m12, :m10]
== module M methods list ==
[:m11, :m12]
== module M instance methods list ==
[:m10]
== object a1 methods list ==
[:m5, :m1, :m12, :m10]
== object a2 methods list ==
[:m1, :m12, :m10]
== object a1 instance_eval ==
1
10
== object a2 instance_eval ==
2
40
nil
== Call instance_eval for m6 and m7 ==
== Call define_method for m8 ==
== Call class_eval and define_method for m9 ==
== Open class, monkey patch for m13 and m14 ==
== Define method_missing for class A and its instance ==
== Extend M_ with a3 ==
== class A methods respond_to? check ==
m0 -
m1 -
m2 :m2
m3 :m3
m4 :m4
m5 -
m6 :m6
m7 -
m8 :m8
m9 -
m10 -
m11 -
m12 -
m13 -
m14 -
m15 -
m16 -
m17 -
m18 -
== module M methods respond_to? check ==
m0 -
m1 -
m2 -
m3 -
m4 -
m5 -
m6 -
m7 -
m8 -
m9 -
m10 -
m11 :m11
m12 :m12
m13 -
m14 -
m15 -
m16 -
m17 -
m18 -
== object a1 methods respond_to? check ==
m0 -
m1 :m1
m2 -
m3 -
m4 -
m5 :m5
m6 -
m7 -
m8 -
m9 :m9
m10 :m10
m11 -
m12 m12!!
m13 1
m14 10
m15 -
m16 -
m17 -
m18 -
== object a2 methods respond_to? check ==
m0 -
m1 :m1
m2 -
m3 -
m4 -
m5 -
m6 -
m7 :m7
m8 -
m9 :m9
m10 :m10
m11 -
m12 m12!!
m13 40
m14 nil
m15 -
m16 -
m17 -
m18 -
== class A_ methods respond_to? check ==
m0 -
m1 -
m2 :m2
m3 :m3
m4 :m4
m5 -
m6 :m6
m7 -
m8 :m8
m9 -
m10 -
m11 -
m12 -
m13 -
m14 -
m15 -
m16 -
m17 -
m18 -
== module M_ methods respond_to? check ==
m0 -
m1 -
m2 -
m3 -
m4 -
m5 -
m6 -
m7 -
m8 -
m9 -
m10 -
m11 -
m12 -
m13 -
m14 -
m15 -
m16 -
m17 -
m18 -
== object a3 methods respond_to? check ==
m0 -
m1 :m1
m2 -
m3 -
m4 -
m5 -
m6 -
m7 -
m8 -
m9 :m9
m10 :m10
m11 -
m12 m12!!
m13 3
m14 nil
m15 :m15
m16 -
m17 :m17
m18 -
== Call m16 from a1, A, a2 and a3 ==
method_missing<m16>
method_missing(m16)
:m16
:m16
== Send m17, private method m18 and call m18 from a3 ==
:m17
:m18
method_missing<m18>