lib/rubype.rb in rubype-0.2.1 vs lib/rubype.rb in rubype-0.2.2
- old
+ new
@@ -15,46 +15,64 @@
def typesig(hash)
meth = hash.keys.first
*arg_types, type_pair = hash.values.first
__rubype__.send(:define_method, meth) do |*args, &block|
- ::Rubype.send(:assert_arg_type, meth, args, arg_types << type_pair.keys.first)
+ ::Rubype.send(:assert_arg_type, self, meth, args, arg_types << type_pair.keys.first)
rtn = super(*args, &block)
- ::Rubype.send(:assert_trn_type, meth, rtn, type_pair.values.first)
+ ::Rubype.send(:assert_trn_type, self, meth, rtn, type_pair.values.first)
rtn
end
self
end
end
module Rubype
+ class ArgumentTypeError < ::TypeError; end
+ class ReturnTypeError < ::TypeError; end
+
class << self
private
+ # @param caller [Module]
# @param meth [Symbol]
# @param args [Array<Object>]
- # @param klasses [Array<Class>]
- def assert_arg_type(meth, args, klasses)
+ # @param type_infos [Array<Class, Symbol>]
+ def assert_arg_type(caller, meth, args, type_infos)
args.each_with_index do |arg, i|
- if wrong_type?(arg, klasses[i])
- raise ArgumentError, "Wrong type of argument, type of #{arg.inspect} should be #{klasses[i]}"
+ case type_check(arg, type_infos[i])
+ when :need_correct_class
+ raise ArgumentTypeError,
+ "Expected #{caller.class}##{meth}'s #{i+1}th argument to be #{type_infos[i]} but got #{arg.inspect} instead"
+ when :need_correct_method
+ raise ArgumentTypeError,
+ "Expected #{caller.class}##{meth}'s #{i+1}th argument to have method ##{type_infos[i]} but got #{arg.inspect} instead"
end
end
end
- # @param meth [Symbol]
+ # @param caller [Module]
# @param rtn [Object]
- # @param klass [Class]
- def assert_trn_type(meth, rtn, klass)
- if wrong_type?(rtn, klass)
- raise TypeError, "Expected #{meth} to return #{klass} but got #{rtn.inspect} instead"
+ # @param type_info [Class, Symbol]
+ def assert_trn_type(caller, meth, rtn, type_info)
+ case type_check(rtn, type_info)
+ when :need_correct_class
+ raise ReturnTypeError,
+ "Expected #{caller.class}##{meth} to return #{type_info} but got #{rtn.inspect} instead"
+ when :need_correct_method
+ raise ReturnTypeError,
+ "Expected #{caller.class}##{meth} to have method ##{type_info} but got #{rtn.inspect} instead"
end
end
# @param obj [Object]
- # @param klass [Class]
- # @return [Boolean]
- def wrong_type?(obj, klass)
- !(obj.is_a?(klass) || klass == Any)
+ # @param type_info [Class, Symbol]
+ # @return [Symbol]
+ def type_check(obj, type_info)
+ if type_info.is_a?(Module) && !(obj.is_a?(type_info) || type_info == Any)
+ :need_correct_class
+ elsif type_info.is_a?(Symbol) && !(obj.respond_to?(type_info))
+ :need_correct_method
+ end
end
end
end