
kickflowで主にバックエンドを担当している小本です。今回は、既存のRailsプロジェクトについて、AIを活用してYARDコメントをrbs-inlineに自動変換した事例を紹介します。
- RBS / rbs-inlineとは
- なぜRBS / rbs-inlineを導入したいのか?
- AI使ったYARDからrbs-inlineへの移行
- GitHub ActionsによるRBSファイルの自動生成
- まとめ
- 最後に
RBS / rbs-inlineとは
RBSはRuby 3.0から導入されたRubyのコードに型情報を記述するための言語です。
そしてrbs-inlineはRubyのコメントにRBSの型定義を直接記述できるツールです。ソースコードと型定義を同じファイルで管理できるため、メンテナンスが容易になります。 rbs-inlineのコメントやRDocやYARDに似ていますが互換性はありません。
class Person attr_reader :name #: String # @rbs name: String # @rbs return: void def initialize(name:) @name = name end end
なぜRBS / rbs-inlineを導入したいのか?
kickflowではAIコーディングを積極的に使っており既に本番コードの一部をAIで生成しています。そして静的型付けはAIコーディングと相性が良いと言われています。AIが参照できる情報が増えますし、型検査によってコーディングのミスを(AIが思考中に自動で)検出できるからでしょう。実際、kickflowではTypeScriptも使っていますが、こういった静的型付けのメリットを感じる場面があります。
そこで、RubyにもRBSによる静的型付けを導入すべきであると考えました。すでに、kickflowでは一部のメソッドでYARDによりメソッドの引数・戻り値の型が宣言されていました。ならば、YARDコメントをrbs-inlineに移行することで部分的にでもAIコーディングの精度が上がると考えました。
また、rbs-inlineとYARDは機能が被っているツールなので、「今後メインストリームになる方」に移ったほうが何かと利益があると考えました。
AI使ったYARDからrbs-inlineへの移行
変換作業の概要
rbs-inlineの文法は複雑なため正規表現での一括変換は現実的ではありません。yard_to_rbs_inlineというGemもありましたが、開発途上のようでした。
そこでAIに書き換えさせることにしました。
AIエージェントとしてはRoo Code(モデルはGemini 2.5 Pro)を使いました *1 。「YARDコメントをrbs-inlineに書き換えて」と指示するだけで基本的な変換はできたのですが、上手くいかない部分もあり、以下のような工夫をしました:
- まずルールファイル(後述)を定義しスタイルを指定する
- rbs-inlineの複数の記法があり統一するため
- AIがrbs-inlineには無い文法を捏造するのを防ぐため
- 50ファイル程度の小さな単位で処理させる
- これはAIというより人間による確認・コードレビューをしやすくするため
- YARDの
@paramsを変換させてから、@returnを変換させる- 一度に変換させるとYARDコメントが無いメソッドに勝手に型定義を追加するなど、誤動作が起きたため
ルールファイルは以下のような内容です:
- クラスやPublicなメソッドにはrbs-inlineによるコメントを書くことを推奨します。 - rbs-inlineのコメントはDoc style syntaxで書くことを推奨します。 - マジックコメント `rbs_inline: enabled` は不要です。 ```ruby class Person attr_reader :name #: String attr_reader :addresses #: Array[String] # @rbs name: String # @rbs addresses: Array[String] # @rbs return: void def initialize(name:, addresses:) @name = name @addresses = addresses end end ``` - rbs-inlineによるコメントでは、型定義の後の `--` によるコメントの前後にスペースを加えてください。 NGな例: # @rbs name: String--名前 OKな例: # @rbs name: String -- 名前 - rbs-inlineの型定義の後に誤って `#` でコメントを書いている場合は `--` に書き直してください。ただしrubocop:disableなどのコメントは `#` のままで問題ありません。 - nilを含むユニオン型については `A | nil` ではなく `A?` を優先して使用してください。ただし、`A | B | nil` のように複数の型がある場合は`| nil` を使用してください。
GitHub ActionsによるRBSファイルの自動生成
rbs-inlineコメントからRBSファイルへの変換はbundle exec rbs-inlineコマンドで簡単に実行できます。
しかし、開発効率を考慮しGitHub Actionsで自動化しました*2。
Github Actionsのワークフロー設定ファイルもAIに生成させました。
# .github/workflows/generate-rbs.yml name: Generate RBS Files on: schedule: # 毎日午前13時(JST)に実行(UTC 04:00) - cron: '0 4 * * *' workflow_dispatch: # 手動実行も可能にする jobs: generate-rbs: permissions: contents: write pull-requests: write runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@master with: fetch-depth: 1 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: ruby-version: .ruby-version bundler-cache: true env: BUNDLE_JOBS: 4 BUNDLE_RETRY: 3 BUNDLE_PATH: vendor/bundle - name: Generate RBS files # generate-rbs.shはbundle exec rbs-inline を実行するだけのスクリプト run: | set -euo pipefail ./generate-rbs.sh - name: Check for updated files in sig/ directory id: check-changes run: | # sigディレクトリで変更されたファイルを確認 changed_files=$(git status --porcelain sig/ | awk '{print $2}') if [ -n "$changed_files" ]; then echo "Updated RBS files:" echo "$changed_files" echo "has_changes=true" >> $GITHUB_OUTPUT # 変更されたファイルの内容も表示 echo "Changes detected in the following files:" git status --porcelain sig/ | awk '{print $2}' else echo "No RBS files were updated." echo "has_changes=false" >> $GITHUB_OUTPUT fi - name: Set current datetime as env variable if: steps.check-changes.outputs.has_changes == 'true' env: TZ: 'Asia/Tokyo' run: echo "CURRENT_DATETIME=$(date +'%Y%m%d%H%M%S')" >> $GITHUB_ENV - name: Commit and push changes if: steps.check-changes.outputs.has_changes == 'true' run: | git config --local user.email "github-actions[bot]@users.noreply.github.com" git config --local user.name "github-actions[bot]" # ブランチを作成 git checkout -b ci/generate-rbs_${{ env.CURRENT_DATETIME }} # RBSファイルを追加 git add sig/ git commit -m "chore: RBSファイルを自動生成 - generate-rbs.shスクリプトを実行してRBSファイルを更新 - 型定義ファイルの自動生成により開発効率を向上" git push origin ci/generate-rbs_${{ env.CURRENT_DATETIME }} - name: Create PR if: steps.check-changes.outputs.has_changes == 'true' run: | gh pr create \ -B develop \ --head $(git rev-parse --abbrev-ref HEAD) \ -t "[CI] Generate RBS files" \ -b "" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: No changes to commit if: steps.check-changes.outputs.has_changes == 'false' run: | echo "No RBS files were updated. Skipping commit."
このワークフローは毎日定期的に実行され、変更があればPull Requestを自動作成します。人間によるレビューを経てマージされます。
まとめ
AIを使用することでYARDコメントからrbs-inlineへの移行を効率的に実現できました。
また、Github actionsを使うことで今までの開発サイクルを維持したまま型定義によるメリットを享受できました。
最後に
kickflowでは、私たちと一緒にプロダクト開発を推進してくれる仲間を募集しています。 このような技術的な取り組みや、より良い開発プロセスを追求することに興味がある方は、ぜひ採用サイトをご覧ください。