Rubyでクラスメソッドを定義する時、いつも
「class < self; end」だっけ?
「class << self; end」だっけ?(←正解)
「self < class; end」だっけ?
「self << class; end」だっけ?
と解らなくなってしまう。
それで「class << self; end」について調べてみれば忘れなくなるかも?と思って調べていたら奇妙な穴にはまってしまった。
この奇妙な仕様について何かご存知の方、すっきり出来るような情報を教えてください!
「class << self; end」と「instance_eval」について
まずは普通にクラスメソッドを定義する。
#!/usr/bin/ruby class ClassA def self.methodA puts "#{self}.#{__method__}" end class << self def methodB puts "#{self}.#{__method__}" end end end ClassA.methodA ClassA.methodB
「class << self; end」って、「selfをclass(self)として扱う」という事なのでは…?(意味不明)
という事はこんな事も出来る…?
class << ClassA def methodC puts "#{self}.#{__method__}" end end ClassA.methodC
出来た!
それってinstance_evalっぽい!
ClassA.instance_eval { def methodD puts "#{self}.#{__method__}" end } ClassA.methodD
出来た!
という事は「class << self; end」とinstance_evalって同じ事が出来るんじゃ…?
class ClassA self.instance_eval { def methodE puts "#{self}.#{__method__}" end } end ClassA.methodE
これも出来た!
Rubyきもい。(褒め言葉)
そもそもselfは何を指しているのか
こんなものを定義した。
class ClassA puts "ClassA instance self: #{self}" puts "ClassA instance self.class: #{self.class}" puts "ClassA instance ClassA==self: #{ClassA==self}" puts class << self puts "ClassA class self: #{self}" puts "ClassA class self.class: #{self.class}" puts "ClassA class ClassA==self : #{ClassA==self}" puts end self.instance_eval { puts "ClassA instance_eval self: #{self}" puts "ClassA instance_eval self.class: #{self.class}" puts "ClassA instance_eval ClassA==self: #{ClassA==self}" puts } end ClassA.instance_eval { puts "global ClassA instance_eval self: #{self}" puts "global ClassA instance_eval self.class: #{self.class}" puts "global ClassA instance_eval ClassA==self: #{ClassA==self}" puts } ClassA.class_eval { puts "global ClassA class_eval self: #{self}" puts "global ClassA class_eval self.class: #{self.class}" puts "global ClassA class_eval ClassA==self: #{ClassA==self}" puts } puts "global ClassA: #{ClassA}"
実行するとこうなる。
ClassA instance self: ClassA ClassA instance self.class: Class ClassA instance ClassA==self: true ClassA class self: #<Class:ClassA> ClassA class self.class: Class ClassA class ClassA==self : false ClassA instance_eval self: ClassA ClassA instance_eval self.class: Class ClassA instance_eval ClassA==self: true global ClassA instance_eval self: ClassA global ClassA instance_eval self.class: Class global ClassA instance_eval ClassA==self: true global ClassA class_eval self: ClassA global ClassA class_eval self.class: Class global ClassA class_eval ClassA==self: true global ClassA: ClassA
なんだかよく解らなくなってきた。
「class << self; end」の中だけ違うものが出力されている。
「class << self; end」とinstance_evalは、全く同じではないという事は解った。
instance_evalのself => 定数として定義されたクラス
「class << self; end」のself => Classクラスのインスタンス
という事なのかな。
よく解らない。
JavaScriptで言う所の、prototypeと__proto__の違いみたいなものなのかな。(JavaScript知らないけど)
外側から「#」ってやつをどうにかして取得したい
これで取れた。
class ClassA class << self @@class_class_instance = self def class_class_instance @@class_class_instance end end end puts ClassA.class_class_instance
それが取得出来ると何かいい事あるの?
さっぱり不明。
参考URL
Rubyのリフレクション解説(eval族のはなし) - このブログは証明できない。
http://d.hatena.ne.jp/shunsuk/20090114/1231934320