はじめに
タイトルのとおり。RBSによる型注釈が提供されているメソッドをmonkey patchして、その型注釈をpatch.rbsに書きたい時がある。Rubyのノリで書くと、重複定義エラーになる。
ディレクトリ構成
以降の文章は、次のようなディレクトリ構成で、
|- lib | `- hoge.rb |- sig | |- patch.rbs | `- hoge.rbs |- Gemfile `- Steepfile
bundle exec steep check
が動くような感じで、ファイルを用意している。
# Gemfile source 'https://rubygems.org' gem 'rbs', '~> 1.2' gem 'steep', '~> 0.44'
# Steepfile target :lib do signature "sig" check "lib" end
たとえば
Javascriptみたいに実数と文字列の足し算をRubyでもしたいとする(本当はしたくない)。
> 3.1 + '4' "3.14"
そのために、Floatクラスをmonkey patchする。
# lib/hoge.rb class Float < Numeric alias_method :_org_add, :+ def + (b) return self.to_s + b if b.is_a?(String) _org_add b end private :_org_add end
これで実数と文字列の足し算ができる。
$ irb irb(main):001:0> require_relative 'lib/hoge.rb' => true irb(main):002:0> 3.1 + '4' => "3.14" irb(main):003:0> 3.1 + 4 => 7.1
型注釈を書く
以上のmonkey patchに対してRBSを書くとすると、まず、以下のようなものが思いつく。
# sig/patch.rbs class Float < Numeric alias _org_add + def +: (Complex) -> Complex | (Numeric) -> Float | (String) -> String end
これで bundle exec steep check
すると、重複定義エラーになる。
Floatがcore/float.rbs(https://github.com/ruby/rbs/blob/master/core/float.rbs)で定義されているためである。
(前後省略) gems/rbs-1.2.1/core/float.rbs:40:2: [error] Non-overloading method definition of `+` in `::Float` cannot be duplicated │ Diagnostic ID: RBS::DuplicatedMethodDefinition │ └ def +: (Complex) -> Complex
解決策
# sig/patch.rbs class Float < Numeric alias _org_add + def +: (Complex) -> Complex | (Numeric) -> Float | (String) -> String | ... # オーバーロードであると示す end
これで重複定義エラーがでなくなる。
$ bundle exec steep check # Type checking files: .......................................................... No type error detected. 🫖
おわりに
Rubyはmonkey patchが容易なので、よく出くわすエラーだと思う。公式の文法ドキュメントを見て考えたが、実はガイドの方に書いてありました: rbs/sigs.md at master · ruby/rbs · GitHub