web-dev-qa-db-ja.com

Rubyプログラマーはどのように型チェックを行いますか?

Rubyには型がないので、Rubyプログラマーは関数が正しい引数を受け取ることをどのように確認しますか?今、私はif object.kind_of/instance_ofステートメントを繰り返してチェックしてどこでもランタイムエラーが発生しますが、これは醜いです。これを行うには、より良い方法が必要です。

23
pythoniku

もちろん、Rubyは動的に型付けされます。

したがって、メソッドのドキュメントによってタイプコントラクトが決まります。型情報は、正式な型システムから[非公式の型仕様]メソッドのドキュメントに移動されます。 「配列のように振る舞う」などの一般性と「文字列である」などの詳細を混ぜ合わせます。呼び出し元は、statedタイプでのみ機能することを期待する必要があります。

発信者がこの契約に違反した場合、何かが起こる可能性があります。メソッドは心配する必要はありません:それは間違って使用されました。

上記に照らして、私はavoid特定のタイプをチェックし、avoidそのような動作でオーバーロードを作成しようとしています。

単体テストはhelpコントラクトが期待されるデータに対して機能することを確認できます。

18
user166390

私の個人的な方法は、一般的に推奨される方法かどうかはわかりませんが、エラーが発生したら、タイプチェックとその他の検証を行うことです。タイプチェックルーチンをレスキューブロックに配置しました。このようにして、正しい引数が与えられたときにパフォーマンスの低下を回避できますが、エラーが発生したときに正しいエラーメッセージを返します。

def foo arg1, arg2, arg3
  ...
  main_routine
  ...
rescue
  ## check for type and other validations
  raise "Expecting an array: #{arg1.inspect}" unless arg1.kind_of?(Array)
  raise "The first argument must be of length 2: #{arg1.inspect}" unless arg1.length == 2
  raise "Expecting a string: #{arg2.inspect}" unless arg2.kind_of?(String)
  raise "The second argument must not be empty" if arg2.empty?
  ...
  raise "This is `foo''s bug. Something unexpected happened: #{$!.message}"
end

main_routineで、arg1が配列であると仮定して、arg1でメソッドeachを使用するとします。 eachが定義されていない他の何かであることが判明した場合、裸のエラーメッセージはmethod each not defined on ...のようなものになります。これは、メソッドfooのユーザーの観点からは役に立たない可能性があります。その場合、元のエラーメッセージはメッセージExpecting an array: ...に置き換えられます。これははるかに役立ちます。

21
sawa

メソッドに存在する理由がある場合、そのメソッドが呼び出されます。

妥当なテストが書かれていれば、すべてが呼び出されます。

また、すべてのメソッドが呼び出されると、すべてのメソッドの型がチェックされます。

呼び出し元を不必要に制約する可能性があり、とにかく実行時チェックを複製するだけのタイプチェックを入力する時間を無駄にしないでください。代わりに、その時間をテストの作成に費やしてください。

9
DigitalRoss

メソッドの最初にraiseを使用して、単純で効果的な手動の型チェックを追加することをお勧めします。

def foo(bar)
    raise TypeError, "You called foo without the bar:String needed" unless bar.is_a? String
    bar.upcase
end

パラメータがあまりない場合の最善の方法は、Ruby 2+で利用可能なキーワード引数を使用することです。複数のパラメータがあり、現在/将来の実装の詳細を監視している場合は、次のようになります。状況を改善し、プログラマーに値がゼロかどうかを確認する方法を提供します。

プラス:カスタム例外を使用できます

class NotStringError < TypeError
   def message 
     "be creative, use metaprogramming ;)"
#...
raise NotStringError
1
makevoid

契約による設計 アプローチを使用できます。 契約 Ruby gem。とてもいいと思います。

1
Julien