0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

rbs-inlineに触れてみた

Last updated at Posted at 2024-08-24

はじめに

この記事は、rbs-inlineを触ってみた際のメモ的な記事です。rbs-inlineのREADMEを参照しながら動かしてみました

検証しているバージョン

  • Ruby 3.3.4
  • rbs-inline 0.6.0
  • steep 1.7.1

導入

RubyやBundlerは導入ずみであるとします。

1. bundle install

bundle initでGemfileを作成し、その中にrbs-inlineを追加します。

# frozen_string_literal: true

source "https://rubygems.org"

gem 'rbs-inline', require: false

追記したら、bundle install

$ bundle install 
Fetching gem metadata from https://rubygems.org/...
Resolving dependencies...
Fetching rbs 3.5.3
Installing rbs 3.5.3 with native extensions
Fetching rbs-inline 0.6.0
Installing rbs-inline 0.6.0
Bundle complete! 1 Gemfile dependency, 5 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.

2. Rubyを書く

README.mdにサンプルが書かれているので、それを参考にコードを書きます。

$ mkdir lib
$ touch lib/person.rb
lib/person.rb
# rbs_inline: enabled

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

  def to_s #: String
    "Person(name = #{name}, addresses = #{addresses.join(", ")})"
  end

  # @rbs &block: (String) -> void
  def each_address(&block) #:: void
    addresses.each(&block)
  end
end

3. RBS fileの生成をCLI上で確認する

bundle exec rbs-inline [ディレクトリ/ファイル名]とすると、CLI上にRBSの生成結果が出力されます。

$ bundle exec rbs-inline lib/person.rb 
# Generated from lib/person.rb with RBS::Inline

class Person
  attr_reader name: String

  attr_reader addresses: Array[String]

  # @rbs name: String
  # @rbs addresses: Array[String]
  # @rbs return: void
  def initialize: (name: String, addresses: Array[String]) -> void

  def to_s: () -> String

  # @rbs &block: (String) -> void
  def each_address: () { (String) -> void } -> untyped
end

🎉 Generated 1 RBS files under

4. 自動生成したRBSをファイルに保存する

bundle exec rbs-inline --output [ディレクトリ/ファイル名]を実行すると、sig/generated配下にrbsファイルが保存されます。

$ bundle exec rbs-inline --output lib/person.rb 
🎉 Generated 1 RBS files under sig/generated

5. steepで型チェック

$ bundle add steepでsteepを導入します。

% bundle add steep
Fetching gem metadata from https://rubygems.org/.............
(省略)
Fetching steep 1.7.1
Installing steep 1.7.1

Steepfileを$ bundle exec steep initで生成します。

$ bundle exec steep init
Writing Steepfile...

$ tree .
.
├── Gemfile
├── Gemfile.lock
├── Steepfile
├── lib
│   └── person.rb
└── sig
    └── generated
        └── person.rbs

4 directories, 5 files

Steepのgetting startedを参考に、Steepfileに以下を追記します

target :app do
  check "lib"
  signature "sig"
end

bundle exec steep checkで型チェックをします。

$ bundle exec steep check
# Type checking files:

.....................................................................................

No type error detected. 🧋

6. わざとエラーが発生することを体験する

5までの手順で、型チェックができるようになりました。しかし、エラーが出る場合を体験していないので、わざとエラーが出るようにしてみます。

6-1. sig/generated/person.rbsを編集する

今回は、rbs-inlineを書かずに手動でRBSファイルを変更します。
以下のように、def age: () -> Stringを追記します。

sig/generated/person.rbs
  (省略)
  def age: () -> String
end

6-2. Person#ageを追加

Personクラスに、Integerを返すageインスタンスメソッドを追記します。

lib/person.rb
# rbs_inline: enabled

class Person
  # 省略
  def age
    20
  end
  # 省略

6-3. 型チェックを実行する

bundle exec steep checkを実行すると、エラーが出力されました。RBSではStringを期待していたのに、Person#ageではIntegerを返していることから、MethodBodyTypeMismatchと判定されているようです。

$ bundle exec steep check
# Type checking files:

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

lib/person.rb:19:6: [error] Cannot allow method body have type `::Integer` because declared as type `::String`
│   ::Integer <: ::String
│     ::Numeric <: ::String
│       ::Object <: ::String
│         ::BasicObject <: ::String
│
│ Diagnostic ID: Ruby::MethodBodyTypeMismatch
│
└   def age
        ~~~

Detected 1 problem from 1 file

6-4. 修正する

rbs-inlineを用いて、RBSを修正してみましょう。

まずは、Person#ageに戻り値の型定義を追加します。

lib/person.rb
  def age #: Integer
    20
  end

つぎに、`bundle exec rbs-inline --output lib/person.rb`でRBSファイルを自動生成します。

$ bundle exec rbs-inline --output lib/person.rb 
🎉 Generated 1 RBS files under sig/generated

6-5. 修正後の型チェックを実行

bundle exec steep checkを再実行すると、今度は問題なく型チェックが通りました。

$ bundle exec steep check                      
# Type checking files:

.....................................................................................

No type error detected. 🍵

さいごに

初めてrbs-inlineに触れてみました。Rubyのコードの中に型も一緒に書ける体験は非常にいいものだと感じました。まだ入門したばかりなので、もっと触れていこうと思います。

0
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?