irbでオートハイライトやオートインデントがされないときに見直す設定

Ruby 2.7 で大幅に強化された irb でオートハイライトやオートインデント、マルチライン編集ができていない場合、~/.irbrc に以下のような設定が残っている可能性があります。

IRB.conf[:USE_READLINE] = true

IRB.conf[:USE_READLINE]true が設定されている場合、この設定自体を消すか false に設定すると Reline が使われて、Ruby 2.7 以降の強力な機能群が使えるようになります。

たぶん Readline まわりのビルドに苦しんだ頃の名残りが ~/.irbrc に残っていたんじゃないかなと思っています。

余談ですが、つい先日に Nokogiri 1.11.0 がリリースされてプリコンパイル済みのパッケージ配布になったので、Readline と Nokogiri のビルドという Ruby アプリケーション開発でのインストールの鬼門が減っていっているのは、いい話ですね。

RuboCop の Ruby 3.0 対応

構文解析まわりは Ruby 3.0 リリース以前に概ね対応されていると思うので、うまく解析できなかったらバグの可能性があります。その場合の初手としては Parser gem を 3.0.0.0 以上にすると解決するかもしれないので、bundle update parser をしても再現するか見てみてください。

ここでは Ruby 3.0 リリース前後のクリスマスあたりから年末年始にかけて実装していた既存 Cop への対応と、新たな Cop について書いておきます。RuboCop 1.7 に入っているものもあれば、今後のリリースに含まれていくものも併せて記しておきます。

Frozen Regexp, Range リテラル対応

Ruby 3.0 では Regexp リテラルならびに Range リテラルについて、デフォルトで frozen になりました。それにともない定数代入に対する Cop である Style/RedundantFreeze cop と Style/MutableConstant cop について、Ruby 3.0 でのそれらリテラルの定数代入で freeze が不要なことを検知できるようにしました。

github.com

これは早めに入れておきたかったことから最優先で対応していたもので、RuboCop 1.7 に含まれています。

Hash#except 対応

Hash#except ならびに ENV#except に置換可能なケースを検出する Style/HashExcept cop を追加しました。Ruby 3.0 以上のみ有効な Cop ですが、Hash#except は Active Support からインポートされたメソッドなので、Active Support を使っている Ruby 3.0 の Rails プロジェクトなんかで、より効果を発揮するかもしれません。

github.com

Ruby 3.0 構文解析を正式サポート

Ruby 3.0 に正式対応した Parser 3.0.0.0 以上を要求するようにしました。

github.com

以下のような警告が出るひとは Parser のバージョンを上げてみてください。

% ruby -v
ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
% rubocop
warning: parser/current is loading parser/ruby30, which recognizes
warning: 3.0.0-dev-compliant syntax, but you are running 3.0.0.
warning: please see
https://github.com/whitequark/parser#compatibility-with-ruby-mri.

Endless Method Definition のスタイル cop

本エントリ中でこの Cop だけは自分の実装ではないもの (ざっとレビューはしている) 。これはコントリビューターのダニエルが提案している Cop で、Endless Method Definition に対するスタイルをチェックする Cop です。Ruby 3.0 リリースイベントでも Endless Method Definition でメソッド本体を複数行で書いていた ko1 さんに、mame さんが1行で書くことを想定していたというやりとりがありましたが、この Cop はデフォルトで1行定義であれば許可するといった振る舞いになる方向です。

github.com

Dir.glob の結果がソート済みになる対応

Ruby 3.0 から Dir.glob の結果がファイルシステムに依存せずソート済みになることに対応しました。Ruby 3.0 だと Dir.glob のあとに sort を加える警告をしません。将来 RuboCop が Ruby 3.0 以上のみのサポートになったら、この Lint/NonDeterministicRequireOrder cop は非推奨警告して削除する予定です。

github.com

上記と対になる新規 Cop で、Dir.globに続いて sort がされている場合に冗長な sort を消します 。

github.com

元々 Lint/NonDeterministicRequireOrder cop の提案がインターネットの海の向こうから来たときに、Dir.glob の結果がソートされないことで困るユースケースがあることを、amatsuda さんにパッチ会で相談したのを覚えていたので、本家がデフォルトでソート済みになったのを受けて対応しようと思っていたのを行った流れです。

lambda の引数にブロックリテラルを使わず Proc 引数を渡す警告

Ruby 3.0 で lambda(&proc { do_something }) のように、lambda の引数にブロックリテラルを使わず Proc 引数を渡している場合の警告をエミューレーションする Cop を追加しています。オートコレクトについて少し悩んだのですが、既存の振る舞いを維持する形にしました。

github.com

余談ですが、このパッチが 2021 年の書き初めです。

NIL, TRUE, FALSE, Ramdom::DEFAULT定数の削除や非推奨への対応

NIL, TRUE, FALSE, Ramdom::DEFAULT といった定数が削除、非推奨されることに対応しておこうと思っていたのですが、まとめて非推奨定数を検知できる Cop として追加の提案をしておきました。

github.com

Numbered Parameter への代入がエラーになることへの対応

Numbered Parameter への代入は Ruby 2.7 では警告、Ruby 3.0 でエラーになるようになりました。Ruby 2.7 の警告をエミュレーションした Cop を追加しました。ただのエミュレーションではない拡張ポイントとして、Numbered Parameter は _1 から _9 までで、_0_10 以上はただのローカル変数のようでしたが、Naming 部署の Cop として一律警告するようにしました。この拡張があるため Lint ではなく Naming 部署に置いたという流れです。

github.com


RuboCop の Ruby 3.0 サポートについて、引き続き対応していく予定です。

また、OSS 活動を支援してくれるスポンサーを GitHub Sponsors で募っていますので、こちらもどうぞよろしく。

github.com

それではハックを続けましょう。

`&& return` より `and return` を好むべき理由

かつての RuboCop は condition and return というコードに対して、condition && return にするようデフォルトでサジェスチョンしていた。

このサジェスチョンはおかしく見えたので、結構前に構成を変えてデフォルトで condition and return を受け入れるようにしている。

このあたり Ruby での演算子の結合順位をおさらいすると、以下のとおり。

  1. &&
  2. ||
  3. and, or

docs.ruby-lang.org

サジェスチョンされるがまま演算子を変えると、結果が変わるサンプルです。

% ruby -e 'p false || true and return' # p(false || true) and return と等価
true

% ruby -e 'p false || true && return' # p(false || (true && return)) と等価
# noop

このように結合順位の関係から、条件式と制御フローをつなげる時は && より and を一貫して使う方が原則好ましいと思っています。

参考までに上述している RuboCop Rails の PR にも書いていますが、RailsDoubleRenderError が起きた時のメッセージで示されるのは render :action and return です。

github.com

auto-correct されたから常に正しいわけではないので、おかしいと思うケースと遭遇したときは立ち止まってもう一度レビューしてみましょう。

あとこういったおかしいところを地道になおして行っていたりもしているので、RuboCop のバージョンが古い場合はアップデートしてみてください。

Rails 6.1で生成コードをRuboCop適用済みにする

Rails 6.1 がリリースされたので、y-yagi さんによる待望のパッチが使えるようになった。

PR にあるように使い方はシンプルで、Rails 6.1 での config/environments/development.rb に以下の設定を足す。

config.generators.after_generate do |files|
  parsable_files = files.filter { |file| file.end_with?('.rb') }
  unless parsable_files.empty?
    system("bundle exec rubocop -A --fail-level=E #{parsable_files.shelljoin}", exception: true)
  end
end

RuboCop で Style/FrozenStringLiteralComment cop を有効にしているので、--auto-correct-all あるいは -A を指定している (RuboCop 0.87 以上は -ASafeAutoCorrect: false な cop への自動修正もされる) 。

bin/rails g を実行すると、コード生成の流れで rubocop コマンドが実行される。

% bin/rails g migration create_articles
Running via Spring preloader in process 80818
      invoke  active_record
      create    db/migrate/20201214064506_create_articles.rb
Inspecting 1 file
C

Offenses:

db/migrate/20201214064506_create_articles.rb:1:1: C: [Corrected] Style/FrozenStringLiteralComment: Missing frozen string literal comment.
class CreateArticles < ActiveRecord::Migration[6.1]
^
db/migrate/20201214064506_create_articles.rb:2:1: C: [Corrected] Layout/EmptyLineAfterMagicComment: Add an empty line after magic comments.
class CreateArticles < ActiveRecord::Migration[6.1]
^
db/migrate/20201214064506_create_articles.rb:4:1: C: [Corrected] Layout/EmptyLinesAroundBlockBody: Extra empty line detected at block body beginning.

1 file inspected, 3 offenses detected, 3 offenses corrected

すると、以下のように自動修正が適用されたコードが生成される。

% cat db/migrate/20201214064506_create_articles.rb
# frozen_string_literal: true

class CreateArticles < ActiveRecord::Migration[6.1]
  def change
    create_table :articles do |t|
      t.timestamps
    end
  end
end

自分はモデルやコントローラなどはコード生成しないが、マイグレーションファイルだけは bin/rails g を使っており、たまに fstring マジックコメントを書き忘れたまま CI に push してしまうので、この機能は待望していたものだった。

余談だけれど、かつて bin/rails g で生成するコードにデフォルトで fstring マジックコメントを足す PR を出して通せなかったことがあったけれど、これはアプリケーションレイヤーで (フックという抽象化によって) 問題解決をコントロールできる柔軟なアプローチで感動しました。

y-yagi さんありがとう!

Offers MagazineにOSS開発に関する記事を寄稿した

少し前に Offers さんより、RuboCop コミッターとしての OSS 開発に関する話というオファーをいただいて Offers Magazine に執筆した。文筆物では12年ぶりの新作。

offers.jp

オファーいただいていた文字数に対して分量割増しで書いてたものの、自分の OSS 開発に関する火付けで重要な松田さんとのエピソードや、OSS 開発者としての人生観的な影響を受けている kamipo さんとのエピソードなど、収まらずに割愛せざるを得なかったものもたくさんあるので、機会があればまたどこかで。

さて、今回は OSS を続けることへのモチベーションの維持や、パッチそのものの質といった部分に焦点をあてた話にした。続けることへのロールモデルとして、分かりやすいであろう GitHub における草というものを持ってきている。書くべきことは本編に書いたので、良ければご一読ください。

また、執筆にあたり編集の峪さんには、執筆のオファーからの打ち合わせ、アウトライン作成、その他もろもろ編集多岐に渡るやりとりでお世話になりました (時代背景から推測できるとおり、すべてオンラインで行っていました) 。ありがとうございました!

RuboCop 1.5で導入された`SuggestExtensions`パラメータ

RuboCop 1.5で導入されたSuggestExtensionsパラメータについて記しておきます。

導入されたパッチは以下です。

github.com

たとえば Bundler を使って RSpec を依存指定している一方で、RuboCop RSpec を使っていない場合は、以下のように RSpec に対応した拡張 RuboCop が存在することを rubocop コマンド実行のメッセージでサジェスチョンします。不必要な場合はメッセージ中に含まれている方法でオプトアウトできます。

% bundle exec rubocop --parallel
(snip)

Tip: Based on detected gems, the following RuboCop extension libraries
might be helpful:
  * rubocop-rspec (http://github.com/rubocop-hq/rubocop-rspec)

You can opt out of this message by adding the following to your
config (see
https://docs.rubocop.org/rubocop/extensions.html#extension-suggestions
for more options):
  AllCops:
    SuggestExtensions: false

現在デフォルトでサジェスチョンするのは、RuboCop HQ で管理されている以下の拡張 RuboCop です。

新たに拡張 RuboCop を足すこともなく、こういったサジェスチョンが不要といった場合は、メッセージにあるように SuggestExtensions: false を .rubocop.yml に指定してください。サジェスチョンメッセージが消えます。

AllCops:
  SuggestExtensions: false

また、先ほど RuboCop 1.5.2 がリリースされました。

rubygems.org

RuboCop 1.5.0, 1.5.1 は、依存している regexp_parser について 2.0 以上を要求するようにしていましたが、Capybara などは現状 1 系のサポートのみとなっていたため、RuboCop 1.5 系にアップグレードできないというフィードバックがありました。

そのため、RuboCop 1.5.2 では regexp_parser 1 系と 2 系をサポートするようにしました。

注意点としては、regexp_parser 1 系を使っている場合は knu さんが直してくれたマルチバイト文字の正規表現に関する既知のバグが残っているので、ご注意ください (regexp_parser 2 系に上がると直ります) 。両系をサポートしたパッチはこちら。

github.com

bundle update で RuboCop 1.5 系へのアップグレードを試みた際に、唐突に 1.4.2 から 1.5.2 に上がった場合はこういった事情になります。

インタラクティブ プレゼンテーション パターンズを再読した

Kaigi on Rails STAY HOME Edition で登壇した動画が公開された。公開作業ありがとうございます。

www.youtube.com

Kaigi on Rails への登壇自体の話は以前書いたエントリに譲り、今回はプレゼンに関する『インタラクティブ プレゼンテーション パターンズ (2004年) 』 (通称イプパタ) という文献を思い出したので、良い機会なので少し書き残しておきます。Web 資料としては以下から辿れます。

objectclub.jp

紹介されているパターンのうち、自分のプレゼンスタイルに取り入れているものもあれば取り入れていないものもあるけれど、全体的にプレゼンへの考え方として結構な影響を受けていたりする。

インタラクティブ プレゼンテーション パターンズ』にある『その場修正』といったパターンに対しては『直前までの作り込み』といった派生系を、イプパタ以降のテックカンファレンスで発見 (ハッチング) している。『その場修正』が JIT 的な最適化だとすれば『直前までの作り込み』は AOT 的な最適化といったところか。今回の Kaigi on Rails でも自分より前にされていたプレゼンを自分の話の流れに取り入れたりしていた。

イプパタについてプレゼンに対するパターンという視点はいま見ても面白いと思うのと、オンラインカンファレンスならではのプレゼンテーションパターンというのはありそうなので、そういった視点で社会を観察してみても面白いかもしれない。