RailsのGeneratorGeneratorが便利すぎたので早く帰れる

どうも、株式会社Fusicでプリンシパルエンジニアやってる南部です。この記事は[Fusic その2 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/fusic-2)の2日目の記事です。

## 経緯

エンジニアは怠惰であれ、という言葉は誰が言ったのか、知るよしもありませんが、私もその例にもれず、怠惰な人間です。
ルーチンで作るものは5秒でつくってしまって、本当に頭を使うべきものに時間を割きたいと思うのは私だけではないでしょう。

RailsにはGeneratorをGenerateするGeneratorGeneratorというものがあります。もう何を言ってるのかわかりませんが、とにかくそういうものがあるのです。

これを導入すると、ルーチンワークを5秒で終わらせる夢が叶います。
みなさんも是非お試しください。

## GeneratorGeneratorでGeneratorのテンプレートを作ろう

```terminal
$ 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`です。

```ruby:lib/generators/nantoka/nantoka_generator.rb
class NantokaGenerator < Rails::Generators::NamedBase
  source_root File.expand_path('templates', __dir__)
end
```

まず、試しにこんなコードを書いてみます。

```ruby:lib/generators/nantoka/nantoka_generator.rb
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
```

```terminal
$ bundle exec rails g nantoka hoge                                                                                                                                                                                                                            
step1: hoge
step2: hoge
```

おわかりの通りに、このGeneratorに実装されたメソッドが順番に実行されるようです。

## ファイルを作る

ファイルを作るには`create_file`を使って実装します。

```ruby:lib/generators/nantoka/nantoka_generator.rb
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パスからの相対パスを指定し、第二引数はそのファイルに書かれる内容です。

```terminal
$ bundle exec rails g nantoka hoge
    create  generator_test.txt
$ cat generator_test.txt
これはgeneratorのテストです: hoge
```

ちゃんとファイルができてますね。

## テンプレートからファイルを作る

create_fileはちょっとした内容をファイルに出力するには便利ですが、コードを出力するには結構難ありです。
やっぱりテンプレートエンジンほしくないですか？ほしいですよね？
ほら、我らがERBがあるじゃないですか。

```ruby:lib/generators/nantoka/nantoka_generator.rb
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
```

```erb:lib/generators/nantoka/templates/generator_test.txt.erb
this is test

<%= name %>
```

これを実行してみましょう。

```terminal
$ bundle exec rails g nantoka hoge
    create  generator_test.txt
$ cat generator_test.txt
this is test

hoge
```

## 引数がほしい

引数がほしい？じゃあ、作ればいいじゃない。

```ruby:lib/generators/nantoka/nantoka_generator.rb
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

```

```erb:lib/generators/nantoka/templates/generator_test.txt.erb
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をつくっておけば、あら簡単。
どこかでバグが見つかっても、作り直すことも簡単です。

時間を無駄に浪費して残業してしまうなんてことがなくなりますように。

## まとめ

エンジニアとは自らの幸せを自ら掴み取る人間である