0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rubyの型付けの変遷とRBS入門:今から型安全なRubyコードを書くために

Last updated at Posted at 2025-10-31

※ 自分用にLLMでまとめた記事になります。

==

Rubyの型付けの変遷とRBS入門:今から型安全なRubyコードを書くために

はじめに

Rubyは動的型付け言語として知られていますが、近年、型安全性を高めるための取り組みが活発になっています。本記事では、Rubyの型付けの歴史的な変遷を振り返り、特に**RBS(Ruby Signature)**に焦点を当てて、実践的な導入方法まで解説します。

Rubyの型付けの変遷

1. 初期のRuby(1995年〜)

Rubyは1995年にまつもとゆきひろ氏によって開発され、動的型付け言語として設計されました。この時期の特徴:

  • 実行時型チェック:型の不一致は実行時にのみ検出される
  • ダックタイピング:オブジェクトの型よりもメソッドの存在を重視
  • メタプログラミング:実行時にクラスやメソッドを動的に変更可能

柔軟性と開発速度を重視する思想のもと、型注釈は不要でした。

2. 型チェッカーの登場(2010年代後半〜)

大規模プロジェクトでの型安全性のニーズから、コミュニティによる型チェックツールが登場しました。

Sorbet(Stripe開発)

2019年にStripe社が公開した型チェッカーです:

  • **独自の型定義言語RBI(Ruby Interface)**を使用
  • インライン型アノテーション(# typed: strictなど)を使用
  • 段階的な型付けが可能(# typed: false# typed: true# typed: strict
  • 実行時型チェックもサポート

Sorbetは独自のアプローチを採用し、コード内に直接型情報を記述します。

Steep(ソウタロ氏開発)

  • RBSベースの型チェッカー
  • Sorbetとは異なり、型情報を外部ファイル(.rbs)に記述
  • Rubyの思想により近いアプローチ
  • TypeScriptにインスパイアされた設計

3. RBS(Ruby Signature)の標準化(2020年〜)

**Ruby 3.0(2020年12月リリース)**でRBSが標準ライブラリとして導入されました:

  • 言語標準:Ruby本体に含まれるため、長期的なサポートが期待できる
  • 非侵入的:ソースコードを変更せず、別ファイル(.rbs)に型情報を記述
  • 段階的導入:既存コードを壊さずに導入可能

RBSの導入により、Rubyにおける型付けが公式にサポートされるようになりました。

RBSとは

RBS(Ruby Signature)は、Rubyの型情報を記述するための言語です。.rbs拡張子のファイルに型定義を記述します。

RBSの基本構文

以下は、RBS公式リポジトリのREADME.mdから引用したチャットアプリの例です:

module ChatApp
  VERSION: String

  class User
    attr_reader login: String
    attr_reader email: String

    def initialize: (login: String, email: String) -> void
  end

  class Bot
    attr_reader name: String
    attr_reader email: String
    attr_reader owner: User

    def initialize: (name: String, owner: User) -> void
  end

  class Message
    attr_reader id: String
    attr_reader string: String
    attr_reader from: User | Bot                     # `|` means union types: `#from` can be `User` or `Bot`
    attr_reader reply_to: Message?                   # `?` means optional type: `#reply_to` can be `nil`

    def initialize: (from: User | Bot, string: String) -> void

    def reply: (from: User | Bot, string: String) -> Message
  end

  class Channel
    attr_reader name: String
    attr_reader messages: Array[Message]
    attr_reader users: Array[User]
    attr_reader bots: Array[Bot]

    def initialize: (name: String) -> void

    def each_member: () { (User | Bot) -> void } -> void  # `{` and `}` means block.
                   | () -> Enumerator[User | Bot, void]   # Method can be overloaded.
  end
end

出典:ruby/rbs README.md

RBSファイルの配置

プロジェクト構造の例:

my_project/
├── lib/
│   ├── user.rb
│   └── product.rb
└── sig/
    ├── user.rbs
    └── product.rbs

sig/ディレクトリに配置するのが一般的です。

RBSの主要機能(公式ドキュメントより)

以下は、RBS By Exampleから引用した標準ライブラリの例です。

1. 引数なしメソッド

class String
  def empty?: () -> bool
end

2. 単一引数メソッド

class String
  def include?: (String) -> bool
end

3. 可変長引数メソッド

class String
  def end_with?: (*String) -> bool
end

4. オプショナル引数

class String
  def ljust: (Integer, ?String) -> String
end

5. オーバーロード

class Array[Elem]
  def *: (String) -> String
       | (Integer) -> Array[Elem]
end

6. ユニオン型

class String
  def <<: (String | Integer) -> String
end

7. オプショナル型(nilable)

class Enumerable[Elem]
  def first: () -> Elem?
           | (Integer) -> Array[Elem]
end

8. キーワード引数

class String
  def lines: (?String, ?chomp: bool) -> Array[String]
end

9. クラスメソッド

class Time
  def self.now: () -> Time
end

10. ブロック引数

class Array[Elem]
  def filter: () { (Elem) -> boolish } -> ::Array[Elem]
            | () -> ::Enumerator[Elem, ::Array[Elem]]
end

11. 型変数

class Hash[K, V]
  def keys: () -> Array[K]
end

出典:ruby/rbs docs/rbs_by_example.md

RBSを取り込むための実践ガイド

Step 1: 環境の準備

Rubyのバージョン確認

RBSはRuby 3.0以降で標準ライブラリとして含まれています:

ruby -v  # Ruby 3.0以上が必要(推奨:3.1以上)

RBSとSteepのインストール

# Gemfile
gem 'rbs'        # Ruby 3.0以降は標準ライブラリだが、開発用に追加することもある
gem 'steep'      # 型チェックツール
bundle install

Step 2: プロジェクトの初期化

RBSの初期化

bundle exec rbs init

これにより、sig/ディレクトリが作成され、基本的な型定義ファイルが生成されます。

Steepプロジェクトの初期化

Steep公式リポジトリのREADME.mdに従って、steep initを実行します:

bundle exec steep init

これにより、Steepfileが作成されます。以下は公式の例です:

# Steepfile
target :app do
  check "lib"
  signature "sig"

  library "pathname"
end

出典:soutaro/steep README.md

Step 3: 既存コードへの段階的導入

アプローチ1: 新しいコードから始める

新しく書くコードだけにRBSを適用する方法です。

アプローチ2: 重要なクラスから型付け

エラーの影響が大きいクラスから優先的に型付けします。

Step 4: RBSの自動生成ツール活用

rbs prototype コマンド

RBS公式リポジトリのREADME.mdによると、rbs prototypeコマンドで既存のRubyコードからRBS定義を自動生成できます:

# person.rb
class Person
  attr_reader :name
  attr_reader :contacts

  def initialize(name:)
    @name = name
    @contacts = []
  end

  def speak
    "I'm #{@name} and I love Ruby!"
  end
end
$ rbs prototype rb person.rb

出力例:

class Person
  @name: untyped

  @contacts: untyped

  attr_reader name: untyped

  attr_reader contacts: untyped

  def initialize: (name: untyped) -> void

  def speak: () -> ::String
end

出典:ruby/rbs README.md

生成されたRBSは概形なので、手動で調整が必要です。

rbs prototypeには3つのオプションがあります:

  • rb - 利用可能なRubyコードから生成
  • rbi - Sorbet RBIから生成
  • runtime - ランタイムAPIから生成

TypeProfの活用

TypeProfはRuby 3.3以降でサポートされています:

gem install typeprof

出典:ruby/typeprof README.md

Step 5: 型チェックの実行

Steepによる型チェック

Steep公式リポジトリのREADME.mdに従って、型チェックを実行します:

# 型チェックの実行
bundle exec steep check

# 対話的な型チェック(ファイル変更を監視)
bundle exec steep watch

CI/CDへの組み込み

.github/workflows/type_check.ymlの例:

name: Type Check

on: [push, pull_request]

jobs:
  typecheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: ruby/setup-ruby@v1
        with:
          ruby-version: 3.2
      - run: bundle install
      - run: bundle exec steep check

Step 6: 段階的な厳格化

Steep公式リポジトリの例を参考に、以下のような段階的な型付けが可能です。

初期段階

全てをuntypedで開始してもOK:

class Calculator
  def add: (untyped, untyped) -> untyped
end

徐々に型を絞り込む

# Step 1: 戻り値の型を指定
def add: (untyped, untyped) -> Integer

# Step 2: 引数も型指定
def add: (Integer, Integer) -> Integer

Step 7: IDE統合

VS Code

Steep公式によると、Steep VSCodeプラグインをインストールします:

SteepはLanguage Server Protocolを実装しており、LSPをサポートするエディタで使用可能です。

出典:soutaro/steep README.md

よくある落とし穴とベストプラクティス

1. メタプログラミングとの相性

RBSはメタプログラミングを完全には表現できません。必要に応じてuntypedを使用します。

2. Railsとの統合

RailsプロジェクトでのRBS定義には、rbs-railsなどのツールが利用できます。

3. 外部ライブラリの型定義

標準ライブラリや人気gemの型定義はgem_rbs_collectionで管理されています。

公式READMEに従って、以下のコマンドを実行します:

# rbs_collection.yaml を作成
rbs collection init

# 依存関係を解決し、このリポジトリからRBSファイルをインストール
rbs collection install

rbs_collection.yamlが存在する場合、インストールされたRBSは自動的に読み込まれます。
rbssteepコマンドには追加の設定は不要です。

出典:ruby/gem_rbs_collection README.md

4. テストコードとの統合

型チェックとテストを併用することで、より堅牢なコードが書けます。

SorbetとRBSの違い

項目 Sorbet RBS
開発元 Stripe Ruby公式
型定義の場所 コード内(RBI) 外部ファイル(.rbs)
標準化 コミュニティツール Ruby標準ライブラリ
実行時チェック あり なし(Steepは静的解析のみ)
段階的導入 可能 可能
メタプログラミング 一部サポート 限定的

まとめ

Rubyの型付けは、SorbetやSteepのようなコミュニティツールから始まり、RBSの標準化により新たな段階に入りました。RBSの主な利点は:

  1. 非侵入的:既存コードを変更せずに導入可能
  2. 段階的導入:少しずつ型を付けられる
  3. 標準化:Ruby本体に含まれるため、長期的なサポートが期待できる
  4. IDE統合:開発体験の向上

既存のプロジェクトでも、新しいコードから始めて段階的に導入することで、型安全性を高めながら開発を続けることができます。まずはrbs prototypeで現状を把握し、重要な部分から徐々に型を付けていくことをおすすめします。

参考リンク

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?