Ruby のメソッドの引数や戻り値には型指定がないけど、それを指定できるような仕組みをつくってみました。
module Strict def strict(name, &block) @returns = Object @arguments = [] block.call m = instance_method(name) ret_type, arg_type = @returns, @arguments define_method name do |*args| c = caller args.each_with_index do |arg, i| next unless arg_type[i] raise TypeError, "argument #{i+1}: #{arg.inspect} is not kind of #{arg_type[i]}", c unless arg_type[i] === arg end ret = m.bind(self).call(*args) raise TypeError, "return value #{ret.inspect} is not kind of #{ret_type}", c unless ret_type === ret ret end end def returns(type) @returns = type end def argument(type) @arguments.push type end end
Strict モジュールを extend して、メソッドを定義した後、strict でメソッドの戻り値の型と引数の型を指定できます。
class Hoge extend Strict def hoge(a, b) return a end strict :hoge do returns Integer argument Integer argument String end end h = Hoge.new h.hoge 123, "abc" # => 123 h.hoge "123", "abc" # TypeError: argument 1: "123" is not kind of Integer
いまいち不格好ですけど、一応目的は達成できてるかな。
実際に使うかというと使わないような気がしますが、まあこんなこともできるという実験ということで。