annotate (2.7.2)のコードリーディングをしました。

bin/annotateはRubyによる実行ファイルでOptionParserでオプション解析・取得しつつ AnnotateModels.do_annotations  や AnnotateRoutes.do_annotations を呼び出します。

Annotate.bootstrap_rakeではRakefileをロードしています。Railsの場合、Rakefileでconfig/application.rbを読み出すので、Railsがこの時点でロードされます。

ただし、Railsアプリをロードするだけではモデルのファイルはロードされないので Annotate.eager_load経由でRails::Applicationのサブクラス(=実体のアプリケーションのクラス)の eager_load!メソッドを叩いてモデルファイルをロードしています。

実際にアノテーションするのは AnnotateModels.do_annotationsの部分になります

markdownでなければheader変数は # == Schema Information が入ります。get_model_filesで対象のモデルファイルを抽出しています。

モデルのディレクトリからconernsを除いたファイルを [モデルディレクトリ, モデルディレクトリからのファイルパス] のArrayのArrayで返します。

ここで取得したファイルに対してannotate_model_fileでアノテーションしていきます。

get_model_classでファイル名からクラスをロードします。クラスのロードは ActiveSupport::Inflector.constantize で行っています。

annotateではモデルのクラスからスキーマ情報を取得して、annotate_one_fileメソッドを呼び出します。

annotate_one_fileでファイルの中身を変更しています。処理が長いので割愛しますが、パターンマッチと置換でinfo_blockのコメントをマジックコメントの下、モデル定義の上の部分に差し込みます。

実際に記述されるコメントはget_schema_infoで生成されます。ActiveRecord::Base.columnsでカラムを取得し、カラムの情報を元にコメントを生成します。こちらも処理が長いので一部割愛していますが全体としてはこんな感じです↓

ちなみにannotateは -rオプションを付けることでconfig/routes.rbにもアノテートできます。内容は rake routesの実行結果をヘッダに入れておりAnnotateRoutes.app_routes_mapで書き出すコメントをセットしています。