メタプログラミングRuby読みメモ 6
9章 Active Record の設計
ActiveRecord::Base
- Active Record は、Active Support と Active Modelの2つのライブラリに大きく依存している
- ActiveSupport::Autoloadモジュールのautoloadを用いて多くのモジュールのincludeを実現している
- autoload https://docs.ruby-lang.org/ja/latest/method/Module/i/autoload.html
モジュール名を最初に参照したときに自動的にソースを探してrequireする
ActiveRecors::Base はモジュールの外側にある機能をまとめている
- オートローディングのおかげでソースコードを先にrequireしなくてもincludeできる
- ActiveRecordはデータベースの操作とオブジェクトモデルの操作の二つに分割された
- データベースの操作はActiveRecordに残り、オブジェクトモデルの操作はActiveModelに移動した
10章 Active Support の Concern モジュール
- Rails のモジュールは、モジュールをインクルードするとインスタンスメソッドとクラスメソッドの両方が手に入る
Concern 以前の Rails
- ActiveRecord::Validation で定義されていた
- ActiveRecord::Base が Validations をインクルードすると
- Validations のインスタンスメソッドが Base クラスのインスタンスメソッドになる
- ValidationsのincludedというフックメソッドをActiveRecord::Baseを引数にして呼び出す
- フックメソッドではActiveRecord::BaseクラスをActiveRecord::Validations::ClassMethodモジュールでextendしている。
- これはクラス拡張なので、ClassMethods のメソッドは Base のクラスメソッドになる
- その結果、Base はインスタンスメソッドとクラスメソッドの両方を手に入れることができた
11章 alias_method_chain の盛衰
alias_method_chain ターゲットのメソッドの名前, 追加機能の名前
とすると- メソッドwith追加機能
- メソッドwithout追加機能
- という二つのメソッドを作り出す
- これは元のメソッドを新しい追加機能で包んだメソッドを作り出してくれる
- 古いバージョンのActiveRecord::Validationsはsaveとsave!をハックしてvalidationを追加している
- validationしたくないsaveをするのであればsave_without_validationを使えば良い
alias_method_chainの衰退
- validationしたくないsaveをするのであればsave_without_validationを使えば良い
- alias_method_chainはRailsの中でメソッドのリネームやシャッフルを繰り返した結果、どのバージョンを使っているのかわからなくなってしまう問題があった
- オブジェクト指向には別のモジュールにメソッドを定義し、元のモジュールをインクルードするという使い方ができる
- alias_method_chain を使わずともsuperを用いて周囲に機能を追加することができる
Module#prepend の誕生
- 継承チェーンの高い位置にあるメソッドをオーバーライドするモジュールを使いたい場合superで呼び出すことができない
- この時中間モジュールを作り継承チェーンに差し込むことで実現できるが、Railsのライブラリなど、直接コードを触りたくない場合もある
- Module#prepend を用いることで継承チェーンの下に目的のモジュールを差し込むことで解決している
12章 アトリビュートメソッドの進化
- ActiveRecordはカラムをみて
カラム=
,カラム?
などのアクセサメソッドを自動的に生成する - はじめはmethod_missingを使ったゴーストメソッドだったが、存在しないメソッドを用いると継承チェーンを1周して探してしまう
- 動的メソッドを用いて問い合わせ用のアクセサを全て作成するという方法もあったが、Railsはそれらを両方取り入れた
- はじめにmethod_missingを呼び、その後にdefine_attribute_methodを呼び出す
- 2回目以降はゴーストメソッドではなく、実体を呼び出せるようになる
- その後のRailsではアトリビュートメソッドはさらに改善されている
- アトリビュートアクセサを定義する時にUnboundMethodに変更してからキャッシュに保存
- 別のクラスが同じアトリビュート名で同じアクセサを必要とした場合これを使い回している!
13章 最後の教訓
- メタプログラミングはただのプログラミング