コンテンツにスキップ

はじめに

この章を読み終えると、次のことができるようになります:

  • rigorPATHに乗せる(速いAI支援の方法、または手作業で);
  • rigor checkを実行し、出力される診断を読む;
  • ほとんどのチェッカーとRigorを分かつ「注釈不要」のスタンス——そして推論が及ばないときの抜け道——を理解する。

これは唯一、最初から最後まで読むべき章です。ハンドブックの残りは、あとから拾い読みできるリファレンスです。

この章の内容 Rigorのインストール · rigor checkが見るもの · 最小の動作セッション · 診断の読み方 · 「注釈なし」のスタンス · 推論だけでは足りないとき · 設定ファイル

Rigorはライブラリではなくツールです — リンターやコンパイラと同様に、プロジェクトを解析しますがランタイムの一部にはなりません。アプリケーションのGemfileに追加しないでください。単独でインストールし、プロジェクトを指して実行します。

Rigor自体はRuby 4.0上で動作し、あなたのコードがターゲットとするRubyとは独立しています — target_ruby:設定キーがRigorにあなたのプロジェクトが動作するRubyを伝えます。

速いパス: AIエージェントにセットアップさせる

Section titled “速いパス: AIエージェントにセットアップさせる”

AIコーディングエージェント(Claude Code、またはAgent Skillsをサポートする任意のアシスタント)を使っているなら、このプロンプトを渡してください:

Install Rigor in this project by following the instructions at
https://raw.githubusercontent.com/rigortype/rigor/refs/heads/master/docs/install.md

エージェントは環境を検出し、Rigorをインストールし、そしてrigor-project-initスキルを実行します——これはあなたのGemfileを辿り、フレームワークに合ったプラグインセットを提案し、導入モードを選び、.rigor.dist.ymlを書き出してくれます。手動のYAML編集は不要です。これが推奨パスです;下記の設定ファイルセクションが、スキルが生成するものを示すので、あとから読んで調整できます。

同じプロンプトはRailsクイックスタートで16言語で利用できます。

自分でセットアップを進めたいなら、推奨のランタイムバージョンマネージャーはmiseで、Ruby 4.0とRigorの両方をプロビジョニングします:

Terminal window
mise use ruby@4.0
mise use gem:rigortype

miseがシェルでアクティベートされていると、rigorPATH上に置かれます。gemの名前はrigortypeです(rigorという名前はRubyGemsで取得済みでした);インストールされる実行ファイルはrigorです。すでにRuby 4.0があるなら、gem install rigortypeでも動きます。

シェルアクティベーションとshims、asdf、コンテナ内開発についてはRigorのインストールを、継続的インテグレーションについてはCIでのRigor実行を参照してください。

Rigorはプロジェクトの.rbファイルを読み、各ファイルにフローセンシティブ(flow-sensitive)な型推論エンジンをかけ、利用可能なsig/*.rbs宣言を参照したうえで、限られた種類のバグを報告します:

  • 受信側のクラスが間違っているメソッド呼び出し
  • 引数の数が間違っているメソッド呼び出し
  • 必ず例外を送出する算術(5 / 0
  • リファインされたパラメータ契約(contract)を満たさない引数の型
  • そのほか、すべて第8章 — エラーの読み方に列挙してあります。

重要なのは、RigorはRubyソースに型注釈を書くことを要求しないことです。証明できる範囲だけ推論し、絞り込めない箇所では沈黙します。十分な静的情報があり確信をもって判断できるときだけ、診断を出します。

プロジェクトのルートで次を実行します:

Terminal window
rigor check lib

これでlib/以下のすべての.rbを辿ります。解析器が文句をつけるものを何も見つけなければ、No diagnosticsと表示して0で終了します:

No diagnostics

何かを見つけたときは、各診断が1行になります。次のファイルがあるとして:

lib/demo.rb
"hello".no_such_method # typo'd method name
[1, 2, 3].rotate(1, 2) # too many arguments

rigor check lib/demo.rbは次を出力します:

lib/demo.rb:1:9: error: undefined method `no_such_method' for "hello" [call.undefined-method]
lib/demo.rb:2:11: error: wrong number of arguments to `rotate' on Array (given 2, expected 0..1) [call.wrong-arity]

単一ファイルだけを対象にしたいときは、ディレクトリの代わりにファイルを渡します:

Terminal window
rigor check path/to/file.rb

そして特定の位置でRigorが何を推論したか尋ねるには:

Terminal window
rigor type-of lib/foo.rb:10:5

これはRigorのリッチな型と、保守的なRBS消去(Rigor以外のRBSツールが見るであろう型)の両方を表示します。「この式はRigorからどう見えるか?」を確かめる最速の方法です。

上の実行の最初の行を取り上げます:

lib/demo.rb:1:9: error: undefined method `no_such_method' for "hello" [call.undefined-method]
部分意味
lib/demo.rb:1:9ファイル、1始まりの行、1始まりの列
error深刻度(error / warning / info
undefined method ...人間向けのメッセージ
[call.undefined-method]修飾されたルール識別子

修飾ルール識別子は、ルールを抑制・降格・参照するために使うハンドルです。最も手早いのは、問題のある行へのインソースコメントです:

"hello".no_such_method # rigor:disable call.undefined-method

同じ識別子はdisable:severity_overrides:設定キーも駆動し、ファミリー単位のワイルドカードも使えます(# rigor:disable callはその行のcall.*ルールをすべて抑制します)。ファミリーとルールの全リスト、そしてどの抑制メカニズムをいつ使うべきかは、第8章 — エラーの読み方にあります。

多くの静的チェッカーはユーザーに型を注釈するよう求めます。Rigorは逆方向です — Rubyコードが何をしているかを見て、値そのものから型を証明します。簡単な例を3つ挙げます:

n = 100
m = n + 1
assert_type("Constant<101>", m) # 算術がたたみ込まれる
def kind(x)
case x
when Integer then :int
when String then :str
end
end
assert_type("Constant<:int>", kind(7)) # ナローイングが case をたたみ込む
greeting = "Hello, " # Constant<"Hello, ">
name = ARGV.first # String? (RBS 由来)
hello = "#{greeting}#{name}!" # リテラル文字列キャリア:
# 補間部分がいずれもリテラル文字列互換なので、
# 結果は「ソース由来であることが証明できる」
# 型になる

注釈を1行も書かずに、Rigorは値そのものについて推論しています。

assert_type(...)の行はRigorのイントロスペクションヘルパーであり、ランタイムチェックではありません——その時点で推論された型を固定するので、地の文を解析器の実際の出力と比較できます。完全なスニペット規約についてはこのハンドブックの読み方を参照してください。

推論で型を絞り込めないとき、エンジンはDynamic[Top](漸進的(gradual)キャリア — 「任意のRuby値の可能性がある」)を返し、診断は出しません。Rigorは証明できない診断を勝手に作り出すことはありません。

初読ですか? このセクションは飛ばしてください。デフォルトのままでも、推論に加えてgemがすでに同梱しているRBSがほとんどのコードをカバーし、続く各章がその出力の読み方を教えます。Rigorが「もっと知っていてほしい」と思う何かをDynamic[Top]に解決したときに、ここへ戻ってきてください。ほとんどのプロジェクトでは抜け道(1)と(2)しか登場しません。

5つの抜け道があります。おおよそよく使う順に並べると:

  1. .rbsファイルを追加する。署名をsig/に置けばRigorが自動的に拾います。ローカルのdefから先が見えない理由として最も多いのがこれです — デフォルトでは解析器は外部のgemをすべてDynamic[Top]として扱います。gemがRBSを同梱していないかぎり、または以下の(4)でgemソース推論をオプトインしないかぎり、内部は見えません。
  2. 既存のRBS署名をRBS::Extendedで締める。メソッドのdef ... -> ::Stringの上に%a{rigor:v1:return: non-empty-string}のような注釈を足します。Rigorはリファインメントを認識しますが、通常のRBSツールはコメントとしてしか見ません。
  3. プラグインを書く。プロジェクトに汎用解析器が知り得ないドメインDSL(Lisp.eval100.kilometerstransition_to(:foo)など)があるなら、プラグインでRigorにそれを教えます。
  4. gemソース推論をオプトインする。RBSを持たないgemのメソッドがDynamic[Top]に解決されてしまうとき、そのgemを.rigor.dist.ymldependencies.source_inference:に列挙すれば、Rigorはそのgemのlib/をプロジェクトソースと同じように辿ります。戻り値はDynamic[T]でラップされ、呼び出し元には出所情報が保持されます。トレードオフはADR-10を参照してください(広いデフォルトは予算を圧迫しbundle updateをノイジーにするため、gem単位のオプトイン設計です)。
  5. rigor-sorbetアダプタを使う。プロジェクトがすでにSorbetを使っているなら、Rigorは既存のsig { ... }ブロック、RBIファイル、T.let / T.cast / T.must / T.unsafeアサーションを何も書き直さずに型ソースとして読み取れます。移行パターンと対応表は第10章を参照してください。

第7章と第9章は(1)〜(3)を詳しく扱います;第10章は(5)を扱います。

最小限の有用な実行に設定ファイルは一切不要です — rigor check libはそのままで動きます。設定ファイルは、追加のpaths、別のseverity_profile、プロジェクト全体のルール無効化、プラグインなど、デフォルト以外の挙動のために用意します。

AI支援セットアップを使ったなら、rigor-project-initスキルが既に1つ書いてくれています。手書きでスターターを書くには、rigor init.rigor.dist.ymlを出力します — これはコミット対象のプロジェクトデフォルトです:

target_ruby: "3.4" # あなたのプロジェクトのRuby — Rigor自身の4.0ではない
paths:
- lib
# signature_paths: [sig] # 省略時は自動検出されます
severity_profile: balanced
# severity_overrides:
# call.argument-type-mismatch: warning
# disable: []
# plugins: []

ほとんどのプロジェクトに必要なのはこれだけです。残りのメカニズム——同梱のJSONスキーマによるエディタオートコンプリート、.rigor.yml.rigor.dist.ymlの優先順位ルール、includes:による合成、そしてパスを取るキーが宣言ファイルを基準にどう解決されるか——は設定で扱います。最初に知っておく価値のある唯一のルール: 開発者がローカルの.rigor.ymlを保持しているとき、それはその実行における設定の唯一のソースであり(2つのファイルが自動的にマージされることは決してありません)、共有デフォルトを拡張するにはそれをincludes:に列挙しなければなりません。

第2章は、Rigorが型を表現するために使うキャリア(carrier)を紹介します。これがRigorを通常のRBSから区別するモデルの中核です。続く第3章(ナローイング(narrowing))でキャリアが活きてきます — キャリアは値を記述し、ナローイングは制御フローがif / case / 述語メソッドを通過するときにキャリアがどう変化するかを記述します。

© 2026 TypedDuck. Licensed under CC BY-SA 4.0.