【Tips】RSpecとRuboCopの自動設定スクリプト

Rails ジェネレータと Thor を調べた副産物で作ってみた。

Railsチュートリアルの SampleApp で生成できたため、普通の Rails アプリケーションなら使用可能だと思う（実行環境: ruby:2.4.9, rails:5.1.2）。 

### スクリプトファイルの生成
```bash:bash
# プロジェクトのルートディレクトリからの操作を想定
$ touch rubocop_and_rspec_setting_script.rb
```


### ファイルを編集
```ruby:./rubocop_and_rspec_setting_script.rb
require "thor"
class Helper < Thor
  include Thor::Actions
end
helper = Helper.new


# Application settings
# --------------------------
inject_target_line = "class Application < Rails::Application\n"
helper.inject_into_file("config/application.rb", <<-TEXT, after: inject_target_line, verbose: false)
    config.generators do |g|
      g.test_framework :rspec,
                        fixtures: true,
                        routing_specs: false,
                        view_specs: false,
                        helper_specs: false,
                        controller_specs: false,
                        request_specs: true
      g.fixture_replacement :factory_bot, dir: "spec/factories"
    end
TEXT

puts "  Complate application setting"


# Rubocop
# --------------------------
case helper.ask "Choose rubocop template:", limited_to: %w[plain airbnb none]
when "plain"
  # Base gem (https://github.com/rubocop-hq/rubocop)
  target_gem_group = "group :development, :test do\n"
  helper.inject_into_file("Gemfile", "  gem 'rubocop', require: false\n", after: target_gem_group, verbose: false)

  `cat << TEXT > ./.rubocop.yml
AllCops:
#  TargetRubyVersion:
#  TargetRailsVersion:

  Exclude:
    - 'bin/**/*'
    - 'config/**/*'
    - 'db/**/*'
    - 'lib/**/*'
    - 'node_modules/**/*'
    - 'spec/**/*'
    - 'vendor/**/*'
TEXT`
when "airbnb"
  # Airbnb specific analysis for RuboCop (https://github.com/airbnb/ruby/tree/master/rubocop-airbnb)
  target_gem_group = "group :development, :test do\n"
  helper.inject_into_file("Gemfile", "  gem 'rubocop-airbnb', require: false\n", after: target_gem_group, verbose: false)

  `cat << TEXT > ./.rubocop_airbnb.yml
require:
  - rubocop-airbnb
TEXT`

  `cat << TEXT > ./.rubocop.yml
inherit_from:
  - .rubocop_airbnb.yml
AllCops:
#  TargetRubyVersion:
#  TargetRailsVersion:

  Exclude:
    - 'bin/**/*'
    - 'config/**/*'
    - 'db/**/*'
    - 'lib/**/*'
    - 'node_modules/**/*'
    - 'spec/**/*'
    - 'vendor/**/*'
TEXT`
when "none"
  puts "  INFO: No setting rubocop."
end

puts "  Complate rubocop setting"


# RSpec
# --------------------------
target_gem_group = "group :development, :test do\n"
helper.inject_into_file("Gemfile", <<-TEXT, after: target_gem_group, verbose: false)
  gem 'rspec-rails'
  gem 'factory_bot_rails'
  gem 'database_rewinder'
  gem 'spring-commands-rspec'
TEXT

## Setting rspec-rails
`bundle install`
`bundle exec rails generate rspec:install`

`cat << TEXT > ./.rspec
--require spec_helper
--format documentation
TEXT`

## Setting spring-commands-rspec
`bundle exec spring binstub rspec`

## Enable ./spec/support directory
helper.uncomment_lines "spec/rails_helper.rb", /Dir\[Rails\.root\.join/

`mkdir ./spec/support`

## Setting factory_bot_rails
`cat << TEXT > ./spec/support/factory_bot.rb
RSpec.configure do |config|
  config.include FactoryBot::Syntax::Methods
end
TEXT`

## Setting database_rewinder
`cat << TEXT > ./spec/support/database_rewinder.rb
RSpec.configure do |config|
  config.before(:suite) do
    DatabaseRewinder.clean_all
    # or
    # DatabaseRewinder.clean_with :any_arg_that_would_be_actually_ignored_anyway
  end

  config.after(:each) do
    DatabaseRewinder.clean
  end
end
TEXT`

puts "  Complate rspec setting"


puts "  Finish rubocop  & rspec setting!"
```

### スクリプトを実行

```bash:bash
# 以下のコマンドで実行可能に変更
$ chmod 777 rubocop_and_rspec_setting_script.rb

$ ruby rubocop_and_rspec_setting_script.rb
```


### 心残し

- 国産の[onkcop](https://github.com/onk/onkcop)も選択肢に入れたかったけど、すぐに設定できないため削除した。
- Rails::Generators のように action の呼び出しをスマートにするため、`Thor`を main に組み込みたかったけど、力及ばなかった orz