概要
RubyGoldを合格する上でも、Classへの理解は必須。
メタプロ本を教科書とした、会社で行われた勉強会の内容について復習
イントロスペクションとメタプログラミング
対象物について、その素性、カバーする範囲、
そして可能な事を判断するために、調査できる機能のことを指す。それがイントロスペクション
(例)
1.methods
→ 結果:Fixnumで定義されているメソッド一覧が取得される
何気なくModelを生成するときに利用している、ActiveRecord::Baseについて。
Active Recordがイントロスペクションを使って クラス名を調査し、そのクラス名を複数形に置き換えた
名称のテーブルに対し存在するカラムを調査し、カラム毎にアクセッサメソッドを自動で定義している。
RailsではActiveRecordのようなメタプログラミングが駆使されたclassが多数存在する
オープンクラス
定義済のクラスを再オープンして、あらたな機能を付けてクラスを上書き保存することができる。
標準クラスにおいても対応できてしまうため、オブジェクト指向により沿ったプログラミングが可能
Stringを更新するようなメソッドを、StringUtilsといったclassを新たに定義しメソッドを定義するのではなく
Stringクラスをオープンして、メソッドを定義することができる。
Railsでオープンクラスが用いられている例
# rails console を起動すると Fixnum クラス に daysというメソッドが定義されている事がわかる
% rails c
[1] pry(main)> 3.class
=> Fixnum
[2] pry(main)> 3.days
=> 3 days
[3] pry(main)> 3.days.class
=> ActiveSupport::Duration
[4] pry(main)>
# irbを起動して確認すると、Fixnum クラス に daysなんてものは無い!ということでエラーになる
% irb
irb(main):001:0> 3.class
=> Fixnum
irb(main):002:0> 3.days
NoMethodError: undefined method `days' for 3:Fixnum
クラスの範囲
オープンクラスにてメソッドを変更した場合、既にnewでインスタンス化されたオブジェクトに対しても有効になる
インスタンス変数はオブジェクトに住んでいるが、
メソッドはオブジェクトではなく、クラスに住んでいるという事
pry(main)> class D
pry(main)* def x
pry(main)* x # 自分で自分をcallするような記載
pry(main)* end
pry(main)* end
=> :x
pry(main)> d1 = D.new
=> #<D:0x007fdeb88a5040>
pry(main)> d1.x # エラーになる
SystemStackError: stack level too deep
pry(main)> class D
pry(main)* def x
pry(main)* "x" # 定義を修正
pry(main)* end
pry(main)* end
=> :x
pry(main)> d1.x # 先ほどと同じオブジェクトに対してx methodを呼び出してもエラーにならない
=> "x"
モンキーパッチ
オープンクラスの技術を用いて、既存メソッドを上書きして別の動きをするクラスができてしまう
通常足し算を行うはずのメソッドが、引き算を行うような動作に変わってしまう 例
pry(main)> a = 3
=> 3
pry(main)> b = 3
=> 3
pry(main)> c = a + b
=> 6
pry(main)> class Fixnum
pry(main)* def +(v)
pry(main)* self - v
pry(main)* end
pry(main)* end
=> :+
pry(main)> c = a + b
=> 0