AWS SDK for Ruby V3に導入されたRBSの検証結果

はじめに

少し前ですが、AWS SDK for Ruby V3に対して型定義情報を提供するRBSが追加されたというアナウンスがありました。

aws.amazon.com

実際にこれを実装したのがksssさんで、そのことをブログ記事にもされています。

ksss9.hatenablog.com

RBSについては検証ができていなかったのですが、よく使うAWS SDK for RubyRBSが含まれることになったので試してみることにしました。

前提条件

今回は、以下のgemのバージョンで試しました。

環境構築

以下の中身を持ったGemfileを作成します。

# frozen_string_literal: true

source "https://rubygems.org"

gem 'aws-sdk-s3', '~> 1.158'
gem 'steep', require: false

bundle installを実行して、Gemfile.lockを生成しておきます。

その後、rbs collection initを実行し、rbs_collection.yamlを生成します。rbs_collection.yamlの中身は特に変更せず、rbs collection installを実行します。これにより、アプリに必要なgemをGemfile.lockから判断し必要であればRBSファイルをダウンロードされ、rbs_collection.lock.yamlファイルが作成されます。今回AWS SDK for RubyにはRBSが含まれることになったので、実際にはダウンロードされないようです。

ちなみに、ここらへんの挙動は以下のブログに詳しく書かれていました。

moneyforward-dev.jp

その後、型チェックをするためにSteepfileを作成します。Steepfileの作成には、bundle exec steep initを実行すると便利です。あらかじめ初期設定がされたSteepfileが生成されますが、今回は以下のように記述しました。

target :lib do
  signature "sig"

  check "lib"
  library "aws-sdk-s3"
end

環境準備は以上で終了です。

型チェック

実際に型チェックを実施してみます。Steepfilecheck "lib"と書いたので、lib以下にあるファイルがチェック対象となるようです。例えばlib/main.rbというファイルを作り、以下の内容としてみます。

require 'aws-sdk-s3'

client = Aws::S3::Client.new
client.create_buckeet(bucket: "aaaaa")

あとは、bundle exec steep checkを実行すると、無事create_buckeetというメソッドはないよというチェックエラーを検出してくれました。

# Type checking files:

.................................................................................................................F..........

lib/main.rb:4:7: [error] Type `::Aws::S3::Client` does not have method `create_buckeet`
│ Diagnostic ID: Ruby::NoMethod
│
└ client.create_buckeet(bucket: "aaaaa")
         ~~~~~~~~~~~~~~

Detected 1 problem from 1 file

型のチェックも実施してくれます。例えば、以下のようなプログラムにおいてチェックをかけてみます。

require 'aws-sdk-s3'

client = Aws::S3::Client.new
client.list_objects_v2(bucket: "aaaaa").contents.each do |obj|
  obj.etag = 123
end

結果は、以下の通り。etagにはStringを指定する必要がありますが、Integerが指定されているというチェック結果が出ました。

# Type checking files:

.......................................................................................................................F....

lib/main.rb:5:13: [error] Cannot pass a value of type `::Integer` as an argument of type `::String`
│   ::Integer <: ::String
│     ::Numeric <: ::String
│       ::Object <: ::String
│         ::BasicObject <: ::String
│
│ Diagnostic ID: Ruby::ArgumentTypeMismatch
│
└   obj.etag = 123
               ~~~

Detected 1 problem from 1 file

Visual Studio Codeとの連携

SteepにはVisual Studio CodeのExtensionが用意されています。

marketplace.visualstudio.com

これをインストールすることで、Visual Studio Codeのエディタ上でチェック結果が表示されます。

考察

AWS SDK for Ruby V3に導入されたRBSについて実際に検証してみました。今回、aws-sdkではなくaws-sdk-s3に絞ったのは意図的で、aws-sdkと書いてしまうと、aws-sdk配下の300以上のgemに対してチェックが行われ、かなり時間がかかります。手元のM2 MacBook Airで数分かかりました。このため、Gemfilerbs_collection.yamlに記述するgemは直接使うものだけを明示したほうが良いかなと感じます。