Rails Guideのコマンドラインのところを見ているとgeneratorを作成できることに気づいた
# こんな感じでファイルをテンプレートから作れるジェネレータを作れる
be rails g my_generator hogehoge
config/defsは作成するのが面倒だと前から感じていた
generatorを作ってみた
defsに定数を追加したいときは大体以下のファイルを生成する必要がある
- config/defs/**.yml
- app/model/defs/**.rb
- frontend/src/Defs/**.jsx
こんな感じでテンプレートを生成したい
be rails g defs hoge_fuga
Running via Spring preloader in process 175
create app/models/defs/hoge_fuga.rb
create config/defs/hoge_fuga.yml
create frontend/src/Defs/HogeFuga.jsx
generatorをgenerateする
generatorをコマンドから作成する
# testも作成されるが削除した
be rails g generator defs
create lib/generators/defs/defs_generator.rb
create lib/generators/defs/USAGE
create lib/generators/defs/templates
各ファイルの説明
- defs_generator.rb
generatorの本体。
- USAGE
helpの中身be rails g defs --help
で中身を表示する
説明は省略する
- templates
template用のerbを置くディレクトリ
generator本体
こいつのパブリックメソッドが定義順に実行される
Thorというgemを使っている
Rails::Generators::NamedBaseを継承するとデフォルトでnameに引数が入る
class DefsGenerator < Rails::Generators::NamedBase
source_root File.expand_path('templates', __dir__)
def create_model_file
template 'model.rb.erb', "app/models/defs/#{name.underscore}.rb"
end
def create_config_file
template 'config.yml.erb', "config/defs/#{name.underscore}.yml"
end
def create_jsx_file
template 'front_defs.jsx.erb', "frontend/src/Defs/#{class_name}.jsx"
end
private
def class_name
name.classify
end
end
templates
普通のerbで書ける
model.rb.erb
class Defs::<%= class_name %> < ActiveYaml::Base
include ActiveHash::Enum
set_root_path Rails.root.join('config/defs')
set_filename '<%= name.underscore %>'
enum_accessor :key
end
config.yml.erb
#
# id <Int>
# key: <String>
# name <String>
#
hoge:
id: 1
key: hoge
name: fuga
front_defs.jsx.erb
import constantizeJSONDef from 'ConstantizeJSONDef';
import Def from 'RailsConfig/defs/<%= name.underscore %>.yml';
export default constantizeJSONDef(Def, {
key: 'key',
name: '<%= class_name %>',
});
Usage
> be rails g defs --help
Usage:
rails generate defs NAME [options]
Options:
[--skip-namespace], [--no-skip-namespace] # Skip namespace (affects only isolated engines)
[--skip-collision-check], [--no-skip-collision-check] # Skip collision check
Runtime options:
-f, [--force] # Overwrite files that already exist
-p, [--pretend], [--no-pretend] # Run but do not make any changes
-q, [--quiet], [--no-quiet] # Suppress status output
-s, [--skip], [--no-skip] # Skip files that already exist
Description:
Defsを生成する
Example:
be rails g defs hoge
This will create:
app/models/defs/hoge.rb
config/defs/hoge.yml
frontend/src/Defs/Hoge.jsx
消したくなったら
be rails destroy defs hoge
Railsのgeneratorをもう少し詳しく
Thor
Railsのgeneratorの内部で使われているgem
コマンドラインツールの作成のためのgem
Rake-likeなシンタックスで書ける
Rails内部で使われているのでrequireすれば使える
引数の扱いがrakeと比べて楽
class HogeGenerator < Rails::Generators::Base
source_root File.expand_path('templates', __dir__)
# documentには :string, :numeric, :array, :hashが使えるとある
# :optionalと:requiredは逆の関係にある
argument :arg1, type: :string, default: 'str', desc: 'essential argment'
argument :arg3, type: :hash, optional: true
argument :arg4, type: :array, required: false
# 何故かバグった
# argument :arg2, type: :numeric
def test_args
puts arg1
# puts arg2
puts arg3
puts arg4
end
class_option :skip_option, type: :boolean, default: false, desc: 'this is description'
class_option :put_option2, type: :boolean, default: false, desc: 'this is description', aliases: [:x, :y, :z]
def test_class_options
say 'not skip option' unless options[:skip_option]
puts 'put option2' if options[:put_option2]
end
end
RailsのgeneratorではThor::GroupとThor::Actionsを拡張する形で使っている
Thor::Groupはpublicメソッドを定義順に呼び出す処理を主に行っている
Actionsはrailsのものと合わせてdocを探しながら実装するのが良さそう
thor_doc:
https://rdoc.info/github/erikhuda/thor/master/Thor/Actions
rails_doc:
https://api.rubyonrails.org/classes/Rails/Generators/Actions.html
module Rails
module Generators
class Error < Thor::Error # :nodoc:
end
class Base < Thor::Group
include Thor::Actions
include Rails::Generators::Actions
# 以下略
end
使えそうなメソッド
Thor::Actions
-
directory(source, *args, &block)
ディレクトリごと再帰的にコピーする -
gsub_file(path, flag, *args, &block)
ファイル内のテキストを置き換える -
inject_into_class(path, klass, *args, &block) ⇒ Object
-
inject_into_module(path, module_name, *args, &block) ⇒ Object
-
insert_into_file(destination, *args, &block) ⇒ Object (also: #inject_into_file)
読んで字の如くコードの内容を挿入できる -
inside(dir = "", config = {}, &block)
ブロック実行中のみ一時的に他ディレクトリをルートにする -
run(command, config = {})
シェルのコマンドが実行できる -
run_ruby_script(command, config = {})
rubyのスクリプトが実行できる -
template(source, *args, &block)
ERBのテンプレートからファイルを生成できる
Rails::Generators::Actions
-
rake(command, options = {})
rakeタスクが実行できる -
git(commands = {})
gitコマンドが実行できる