scaffoldから学ぶあるコードの間にgenerateしたコードを注入する考え方
目的
自動生成したコードを既存のコードの末尾に追記ではなく、ある一定の判断基準をもって既存のコードの間に注入したいときにどういう考え方でやるのかが知りたい。
rails generate scaffoldから見る
railsだとgenerate系が充実しててtutorialではまずこれを使ってmodelを作ってみましょうという流れがある。
$ rails generate scaffold Micropost content:string user_id:integer invoke active_record create db/migrate/20160401165016_create_microposts.rb create app/models/micropost.rb invoke test_unit create test/models/micropost_test.rb create test/fixtures/microposts.yml invoke resource_route route resources :microposts invoke scaffold_controller create app/controllers/microposts_controller.rb invoke erb create app/views/microposts create app/views/microposts/index.html.erb create app/views/microposts/edit.html.erb create app/views/microposts/show.html.erb create app/views/microposts/new.html.erb create app/views/microposts/_form.html.erb invoke test_unit create test/controllers/microposts_controller_test.rb invoke helper create app/helpers/microposts_helper.rb invoke test_unit invoke jbuilder create app/views/microposts/index.json.jbuilder create app/views/microposts/show.json.jbuilder invoke assets invoke coffee create app/assets/javascripts/microposts.coffee invoke scss create app/assets/stylesheets/microposts.scss invoke scss identical app/assets/stylesheets/scaffolds.scss
ここのinvoke resource_routeのroute resources: microposts実行されると 以下のようにconfig/routes.rbのイイカンジの所に自動的にinjectされる。
Rails.application.routes.draw do resources :microposts # <- inject at this point # Other codes end
というわけで、どういう考え方でこれをやってるのかが知りたくなった。
code reading
invoke resource_routeの瞬間に実行されているのは以下
https://github.com/rails/rails/blob/master/railties/lib/rails/generators/rails/resource_route/resource_route_generator.rb#L15-L35
ここで生成したroute_stringから不要なスペースや改行コードを弾いてrouteへ渡している。此処が肝っぽい
https://github.com/rails/rails/blob/master/railties/lib/rails/generators/actions.rb#L236-L246
基準地点を正規表現としてルーチンの中で保持しておいて(ここでは/.routes.draw do\s*\n/m)、その基準地点の後のところにrouting_codeを差し込んでいる。
この実際の処理をしているinject_into_fileはThorというself-documenting command line utilities向けのライブラリの機能で、与えられたパスのファイルに対してdataをconfigのルールに従って注入できる。
似た機能で正規表現置換をするgsub_fileがあるらしいけど、そっちと違ってこれは元に戻せる仕組みらしい。
Method: Thor::Actions#inject_into_file — Documentation for wycats/thor (master)