4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

メタプログラミングRuby勉強会 復習 イントロスペクション・オープンクラス・モンキーパッチ

Posted at

概要

メタプログラミングRuby
alt

RubyGoldを合格する上でも、Classへの理解は必須。
メタプロ本を教科書とした、会社で行われた勉強会の内容について復習

イントロスペクションとメタプログラミング

対象物について、その素性、カバーする範囲、
そして可能な事を判断するために、調査できる機能のことを指す。それがイントロスペクション
(例)
 1.methods
 → 結果:Fixnumで定義されているメソッド一覧が取得される

何気なくModelを生成するときに利用している、ActiveRecord::Baseについて。
Active Recordがイントロスペクションを使って クラス名を調査し、そのクラス名を複数形に置き換えた
名称のテーブルに対し存在するカラムを調査し、カラム毎にアクセッサメソッドを自動で定義している。

RailsではActiveRecordのようなメタプログラミングが駆使されたclassが多数存在する

オープンクラス

定義済のクラスを再オープンして、あらたな機能を付けてクラスを上書き保存することができる。
標準クラスにおいても対応できてしまうため、オブジェクト指向により沿ったプログラミングが可能

Stringを更新するようなメソッドを、StringUtilsといったclassを新たに定義しメソッドを定義するのではなく
Stringクラスをオープンして、メソッドを定義することができる。

Railsでオープンクラスが用いられている例

railsc
# 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
# 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
4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?