tnodaの日記: 「メタプログラミング Ruby 」読書ノート - 第4章 木曜日: クラス
今日 Ruby について学んだこと:
(1) カレントクラス
(2) 特異メソッド、特異クラス
今日学んだ魔術:
(a) クラスインスタンス変数
(b) クラスマクロ
(c) アラウンドエイリアス
(1) カレントクラス
------------------------------
* クラス定義の中では self は定義されたクラス、カレントクラスは self
* メソッド定義 = カレントクラスのインスタンスメソッド定義
- トップレベルでメソッドを定義すると、main のクラスである
Object のインスタンスメソッドになる
* Module#class_eval()
- 既存クラスのコンテキストでブロックを評価
- class より柔軟 = class は定数のみ、class_eval は変数可/フラットスコープ
(2) 特異メソッド、特異クラス
--------------------------------------------------
* 特異メソッド定義
def object.method
# メソッド定義
end
- object => オブジェクトの参照、クラス名の定数、self
- クラスメソッドはクラスの特異メソッド
* 特異クラスをオープンしてメソッド定義 → クラスメソッド
class MyClass
class << self
def my_method; end
end
end
* MyClass のインスタンスではなく、MyClass に属性を定義したいときは、
MyClass の特異クラスに属性を定義すればいい
class MyClass
class << self
attr_accessor :c
end
ed
* クラス拡張とオブジェクト拡張
- Object#extend() は、
特異クラスにモジュールをインクルードするためのショートカット
* Ruby の世界では、特異クラス eigenclass, 特異メソッド singleton method
魔術サイド
=========================
(a) クラスインスタンス変数
-------------------------------------------
* クラスのインスタンス変数とオブジェクトのインスタンス変数は別物
* 多くの Rubyist はクラス変数よりクラスインスタンス変数を好む
∵クラス変数がクラス階層に属しているから
* 例: Time や Date など実行毎に異なる値を返すクラスに依存したコードを
テストするテクニック
class Loan
...
def initialize
...
@time = Loan.time_class.new
end
...
def self.time_class
@time_class || Time
end
...
ユニットテスト時には、
Loan.instance_eval { @time_class = FakeTime }
(b) クラスマクロ
---------------------------------
* クラス定義の中で使える単なるクラスメソッド
(c) アラウンドエイリアス
----------------------------------------------
外部ライブラリなど編集できないメソッドをラップして機能追加する。
1. メソッドをエイリアスして、新しい名前をつける
2. 新しいメソッドを定義して、新しいメソッドに元の名前をつける
3. 元の名前がついた新しいメソッドから、
新しい名前のついた古いメソッドを呼び出す
アラウンドエイリアスの 2 つの潜在的な落とし穴
* モンキーパッチなので既存のコードを壊しかねない
* 2 回読み込んではいけない
「メタプログラミング Ruby 」読書ノート - 第4章 木曜日: クラス More ログイン