どうも、株式会社Fusicでプリンシパルエンジニアやってる南部です。この記事はFusic その2 Advent Calendar 2019の2日目の記事です。
経緯
エンジニアは怠惰であれ、という言葉は誰が言ったのか、知るよしもありませんが、私もその例にもれず、怠惰な人間です。
ルーチンで作るものは5秒でつくってしまって、本当に頭を使うべきものに時間を割きたいと思うのは私だけではないでしょう。
RailsにはGeneratorをGenerateするGeneratorGeneratorというものがあります。もう何を言ってるのかわかりませんが、とにかくそういうものがあるのです。
これを導入すると、ルーチンワークを5秒で終わらせる夢が叶います。
みなさんも是非お試しください。
GeneratorGeneratorでGeneratorのテンプレートを作ろう
$ bundle exec rails generate generator nantoka
create lib/generators/nantoka
create lib/generators/nantoka/nantoka_generator.rb
create lib/generators/nantoka/USAGE
create lib/generators/nantoka/templates
このようにlib/generators/nantoka
の中にファイルやディレクトリが作られます。
本体になるのはnantoka_generator
です。
class NantokaGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
end
まず、試しにこんなコードを書いてみます。
class NantokaGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
def step1
puts "step1: #{self.name}"
end
def step2
puts "step2: #{self.name}"
end
end
$ bundle exec rails g nantoka hoge
step1: hoge
step2: hoge
おわかりの通りに、このGeneratorに実装されたメソッドが順番に実行されるようです。
ファイルを作る
ファイルを作るにはcreate_file
を使って実装します。
class NantokaGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
def create_generator_test_file
create_file "generator_test.txt", "これはgeneratorのテストです: #{self.name}"
end
end
create_fileは第一引数がRailsのrootパスからの相対パスを指定し、第二引数はそのファイルに書かれる内容です。
$ bundle exec rails g nantoka hoge
create generator_test.txt
$ cat generator_test.txt
これはgeneratorのテストです: hoge
ちゃんとファイルができてますね。
テンプレートからファイルを作る
create_fileはちょっとした内容をファイルに出力するには便利ですが、コードを出力するには結構難ありです。
やっぱりテンプレートエンジンほしくないですか?ほしいですよね?
ほら、我らがERBがあるじゃないですか。
class NantokaGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
def create_generator_test_file
template "generator_test.txt.erb", "generator_test.txt"
end
end
this is test
<%= name %>
これを実行してみましょう。
$ bundle exec rails g nantoka hoge
create generator_test.txt
$ cat generator_test.txt
this is test
hoge
引数がほしい
引数がほしい?じゃあ、作ればいいじゃない。
class NantokaGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
# 引数を追加
argument :words, type: :array, default: []
def create_graphql_schema
template "generator_test.txt.erb", "generator_test.txt"
end
end
this is test
<%= name %>
<% words.each do |word| -%>
<%= word %>
<% end -%>
$ bundle exec rails g nantoka hoge arg-foo arg-bar
create generator_test.txt
$ cat generator_test.txt
this is test
hoge
arg-foo
arg-bar
実際何に使うか?
例えば、graphql-ruby
を使ってスキーマ定義したりするとき、似たようなRubyのコードがいっぱい出てくると思います。
そういうときに、一つGeneratorをつくっておけば、あら簡単。
どこかでバグが見つかっても、作り直すことも簡単です。
時間を無駄に浪費して残業してしまうなんてことがなくなりますように。
まとめ
エンジニアとは自らの幸せを自ら掴み取る人間である