きのうのやつまだ解決してないんだけども、ああいうことができるならinitializeとかもoverrideできるのかもと思ってやってみる。
そもそも標準で用意されてるクラスにinitializeがあるのか調べてみる。
てっとり早くDateでやってみる。
ちなみにDate.methodsにはなかったので手当り次第やってみたら
[1] pry(main)> require "date" => true [2] pry(main)> Date.private_methods.sort => [:Array, :Complex, ~ :included, :inherited, :initialize, :initialize_copy, :iterator?, ~
あった。
ということでoverrideしてみる。
require "date" class Date def initialize(*args) p "kita!" end def aaa "aaa" end end p dd = Date.new(2013, 1, 31) p dd.day p dd.aaa $ ruby buildin.rb #<Date: 2013-01-31 ((2456324j,0s,0n),+0s,2299161j)> 31 "aaa"
ならない。
というかまったく通ってない。
newしてるからinitialize通ると思うんだけどなあと思っていろいろぐぐってみると
instance method Object#initialize
このメソッドは Class#new から新しく生成されたオブ ジェクトの初期化のために呼び出されます。他の言語のコンストラクタに相当します。 デフォルトの動作ではなにもしません。
initialize には Class#new に与えられた引数がそのまま渡されます。
サブクラスではこのメソッドを必要に応じて再定義されること が期待されています。
initialize という名前のメソッドは自動的に private に設定され ます。
なるほど、newか。
そしてprivate_methodsに引っかかったのも自動的にprivateになるからということらしい。
自身のインスタンスを生成して返します。 このメソッドの引数はブロック引数も含め Object#initialize に渡されます。
new は Class#allocate でインスタンスを生成し、 Object#initialize で初期化を行います。
とりあえずnewをoverrideしてみればいけそうな気がする。
newは特異メソッド、要はstaticなのでselfを付ける。
やってみる。
require "date" class Date def self.new(*args) p "new!" super *args end def initialize(*args) p "kita!" end def aaa "aaa" end end p dd = Date.new(2013, 1, 31) p dd.day p dd.aaa $ ruby builtin.rb "new!" "kita!" #<Date: -4712-01-01 ((0j,0s,0n),+0s,2299161j)> 1 "aaa"
今度は来た。
けど、initializeで引数を処理してないのでもう一回。
require "date" class Date def self.new(*args) p "new!" super *args end def initialize(*args) p "kita!" super *args end def aaa "aaa" end end p dd = Date.new(2013, 1, 31) p dd.day p dd.aaa $ ruby builtin.rb "new!" "kita!" builtin.rb:9:in `initialize': wrong number of arguments(3 for 0) (ArgumentError) from builtin.rb:9:in `initialize' from builtin.rb:5:in `new' from builtin.rb:5:in `new' from builtin.rb:16:in `<main>'
まあsuperにぶん投げた所でDateの親の引数とあうかわかんないから当然としても、Dateのinitializeにそのまま投げたいんだけどどうしたらいいかわからない。
そもそも、Dateでもないsuperにぶん投げてるのが間違ってる気がする。
newでインスタンスを作ったときに引数も内部にセットされてるのではないか。
で、initializeはその名の通り初期化するだけと。
newに別名付けて自分自身にぶん投げてみてはどうか。
やってみる。
require "date" class Date alias_method :orgnew, :new def self.new(*args) p "new!" orgnew *args end def initialize(*args) p "kita!" end def aaa "aaa" end end p dd = Date.new(2013, 1, 31) p dd.day p dd.aaa $ ruby builtin.rb builtin.rb:3:in `alias_method': undefined method `new' for class `Date' (NameError) from builtin.rb:3:in `<class:Date>' from builtin.rb:2:in `<main>'
Dateにnewがないって怒られた。
考え方は間違ってない気がしないでもないので「クラスメソッド 別名 ruby」とかでぐぐってみたらいいのがみつかった。
Rubyのクラスメソッドの別名定義(alias) - 山本隆の開発日誌
できるっぽい。
なんか class << self って使ってるけどなんなのかぐぐってみる。
class << selfを調べてたら特異メソッドとか特異クラスとか出てきた - マグネシウムライト
ざっくりいうと、自分自身に特異クラスを作れるってことらしい。
普段ならselfくっつけて書けばいいじゃんって思ってたはずなので、今回みたいなことがなかったらすごいって思わなかった気がする。
やってみる。
require "date" class Date class << self alias_method :orgnew, :new def new(*args) p "xxx" orgnew *args end end def initialize(*args) p "kita!" end def aaa "aaa" end end p dd = Date.new(2013, 1, 31) p dd.day p dd.aaa $ ruby builtin.rb "xxx" #<Date: 2013-01-31 ((2456324j,0s,0n),+0s,2299161j)> 31 "aaa"
すごい、きた。
でもinitializeを通ってない。
状況を振り返ると
- 普通にinitializeをoverrideしても通らなかった
- superにぶん投げたら通った
- Dateクラス自身に投げたら通らなくなった
- 作ったオブジェクトにはinitializeがある(private_methodsで確認)
なぜなのか。
まったくわからない。