読者です 読者をやめる 読者になる 読者になる

There's an echo in my head

日々のメモ。

Railsのジェネレータを自作する

よく忘れるので。細かい話は他の記事にお任せして、テンプレートからファイルを作れるところまで。

0. こんなのを作りたいとかんがえる

  • 抽象クラスFigureのサブクラスをapp/modelsに作るようなジェネレータがほしい。
  • クラス名は引数で指定したい

こんな感じで使うイメージ:

$ rails g figure triangle --color blue

1. ジェネレータをジェネレートする

 $ rails g generator figure

これでlib/generators/figure以下に

  • USAGE : 使い方を記述するテキストファイ
  • figure_generator.rb : 生成処理を実装するファイル
  • templates/ : テンプレートファイルを置くディレクトリ

が作られる。

2. 作り方を記述する

USAGEファイルに0.のようなことを記述する。

3. 生成処理を記述する

lib/generators/figure/figure_generator.rb に次のように記述する。

class FigureGenerator < Rails::Generators::NamedBase                                               
  source_root File.expand_path('../templates', __FILE__)

  # 引数として受け取る順番に記述する
  # ここで宣言した引数名はそのままその値を返すメソッドとしても使える
  # 追記: NamedBaseの場合はデフォルトでnameが宣言されているのでここではなにもしない
  # argument :name, type: :string, desc: "クラス名。underscoreな形でもOK"

  # オプションを記述する
  # ここで宣言したオプションは`options[:color]`のように参照できる
  class_option :color, type: :string, aliases: "-c", desc: ""

  # 以下に宣言されたpublicなメソッドが上から順に実行される

  def create_model_file
    # テンプレートをもとにapp/modelsにファイルを作る
    template "model.rb.erb", "app/models/#{name.underscore}.rb"
  end

  private

  # このクラス上のメソッドはテンプレートからも呼び出せるので
  # 積極的にprivateメソッドで宣言していきたい
  def class_name
    name.classify
  end
end

4. テンプレートファイルを記述する

figure_generator.rb でtemplateメソッドの引数に渡した model.rb.erb にテンプレートを記述する。ファイル名のとおりERBを使う。 *1

class <%= class_name %> < Figure
  def apexes_count
     # 頂点の数を返す
  end
  def color
    "<%= options[:color] %>"
end

5. 使ってみる

$ rails g figure triangle --color yellow

9/17 追記

class_optionによるオプションの宣言方法を追記した。 ちなみにargumentclass_optionThor::Base::ClassMethodsで定義されているもの。

10/3 追記

NamedBaseの場合はすでにnameargumentで宣言されており別途宣言する必要がないので、ここではコメントアウトした。

*1:もしかしたらファイル名を適切に設定すればERB以外も使えるかもしれない

このブログに出てくるコードスニペッツは、引用あるいは断りがない限りMITライセンスです。