メタプログラミングRubyを読んでいます。完全自分用のメモ記事です。
第2章で特に参考になった部分を中心に書いています。
🐯 メタプログラミングとは
コードを記述するためのコードを書くことである
🚜 2章
オープンクラス
require "monetize" |
とある場合、 to_money
は次のように Numeric
クラスを拡張して実装されている。
class Numeric |
Rubyは標準クラスでも気軽に拡張できる。
既存のクラスを再オープンして、気軽に拡張できる。これをオープンクラスという。
安易なパッチはバグを誘発するため、モンキーパッチともいう。
しかしたとえば拡張したメソッドが標準クラスのメソッドだった場合、その影響範囲が大きくなってしまう。
モンキーパッチの代替案としては、Refinements
などを使うことである。
Classの親クラスはモジュール
Class.superclass #=> Module |
Classはオブジェクトの生成やクラスを継承するためのインスタンスメソッドnew, allocate superclassを追加したモジュールである。
loadとrequireの違い
- load => loadはコードを実行するために使う。呼び出す度にファイルを実行する - require => requireはライブラリをインポートするために使う。ファイルは一度しか読み込まない。
モジュールの継承関係
継承チェインはクラスからスーパークラスに向かって進む。
それだけではなく、継承チェインにはモジュールも含まれる。
module M1 |
このようにM1やKernelなどのモジュールも継承関係に含まれていることが分かる。
ちなみに、モジュールがすでにチェインに存在していた場合は、2回目の挿入を無視する。
(何度も継承チェインに同じオブジェクトが含まれることはない)
Rubyにおけるprivateについて
class C |
Refinementsについて
モジュールで限定されたスコープの中でのみ、Stringを限定して拡張できる。
module StringExtensions |
これにより、モンキーパッチで発生するようなグローバルな変更を避けることができる。
ただし、Refinements
は新しい機能で、将来挙動が変わる可能性がある。
そのことを理解したうえで、プログラムを書くべきである。
まとめ
- オブジェクトは複数のインスタンス変数とクラスへのリンクで構成
- インスタンス目ドッドはオブジェクトのClassに住んでいる
- クラスはClassクラスのオブジェクトである。クラスは単なる定数である
- Classはモジュールのサブクラスである
- モジュールは基本的にはメソッドをまとめたものである
- クラスはnewでインスタンス化したり、 superclassで階層構造を作ったりできる
- クラスはそれぞれ、BasicObjectまで続く継承チェインを持っている
- クラスにモジュールをinclude(prepend)すると、そのクラスの継承チェインの真上(下)にモジュールが挿入される
- メソッドを呼び出すときには、レシーバがselfになる
- モジュール(あるいはクラス)を定義するときには、そのモジュールがselfになる
- インスタンス変数は常にselfのインスタンス変数とみなされる
🎃 Tips: トップレベル
self #=> main トップレベルでのselfを表すオブジェクト |
🐮 refinementsの使いドコロの難しさ
refinements
は便利だけど、メソッドの一覧で取得できない場合があり、直感的ではないのでいずれこの仕様は変わる可能性がありそう。
class MyClass |
🎂 サンプルソース
何かの役に立つこともあるかもですので、リポジトリも公開しておきます。
morizyun/meta_programming_ruby2 - GitHub