lib/rubype.rb in rubype-0.2.2 vs lib/rubype.rb in rubype-0.2.3
- old
+ new
@@ -4,75 +4,106 @@
TrueClass.send(:include, Boolean)
FalseClass.send(:include, Boolean)
class Module
private
- def __rubype__
- prepend (@__rubype__ = Module.new) unless @__rubype__
- @__rubype__
- end
+ # @return [Module]
+ def __rubype__
+ prepend (@__rubype__ = Module.new) unless @__rubype__
+ @__rubype__
+ end
- # @param hash [Hash] {method_name: [ArgClass1, ArgClass2, ... ArgClassn => RtnClass]}
- def typesig(hash)
- meth = hash.keys.first
- *arg_types, type_pair = hash.values.first
+ # @param meth [Symbol]
+ # @param type_info_hash [Hash] { [ArgInfo_1, ArgInfo_2, ... ArgInfo_n] => RtnInfo }
+ # @return self
+ def typesig(meth, type_info_hash)
+ ::Rubype.send(:define_typed_method, self, meth, type_info_hash, __rubype__)
+ self
+ end
+end
- __rubype__.send(:define_method, meth) do |*args, &block|
- ::Rubype.send(:assert_arg_type, self, meth, args, arg_types << type_pair.keys.first)
- rtn = super(*args, &block)
- ::Rubype.send(:assert_trn_type, self, meth, rtn, type_pair.values.first)
- rtn
+class Method
+ def type_info
+ if methods_hash = Rubype.typed_method_info[owner]
+ methods_hash[name]
end
- self
end
end
module Rubype
class ArgumentTypeError < ::TypeError; end
class ReturnTypeError < ::TypeError; end
+ @@typed_method_info = Hash.new({})
class << self
+ def typed_method_info
+ @@typed_method_info
+ end
+
private
+ # @param caller [Object]
+ # @param type_info_hash [Hash] { [ArgInfo_1, ArgInfo_2, ... ArgInfo_n] => RtnInfo }
+ # @param module [Module]
+ def define_typed_method(meth_caller, meth, type_info_hash, __rubype__)
+ arg_types, rtn_type = *strip_type_info(type_info_hash)
+ @@typed_method_info[meth_caller][meth] = {
+ arg_types => rtn_type
+ }
+ __rubype__.send(:define_method, meth) do |*args, &block|
+ ::Rubype.send(:assert_arg_type, meth_caller, meth, args, arg_types)
+ rtn = super(*args, &block)
+ ::Rubype.send(:assert_trn_type, meth_caller, meth, rtn, rtn_type)
+ rtn
+ end
+ end
- # @param caller [Module]
- # @param meth [Symbol]
- # @param args [Array<Object>]
- # @param type_infos [Array<Class, Symbol>]
- def assert_arg_type(caller, meth, args, type_infos)
- args.each_with_index do |arg, i|
- case type_check(arg, type_infos[i])
+ # @param type_info_hash [Hash] { [ArgInfo_1, ArgInfo_2, ... ArgInfo_n] => RtnInfo }
+ # @return arg_types [Array<Class, Symbol>], rtn_type [Class, Symbol]
+ def strip_type_info(type_info_hash)
+ arg_types, rtn_type = type_info_hash.first
+ [arg_types, rtn_type]
+ end
+
+ # @param caller [Module]
+ # @param meth [Symbol]
+ # @param args [Array<Object>]
+ # @param type_infos [Array<Class, Symbol>]
+ def assert_arg_type(caller, meth, args, type_infos)
+ args.zip(type_infos).each.with_index(1) do |(arg, type_info), i|
+ case type_check(arg, type_info)
+ when :need_correct_class
+ raise ArgumentTypeError,
+ "Expected #{caller.class}##{meth}'s #{i}th argument to be #{type_info} but got #{arg.inspect} instead"
+ when :need_correct_method
+ raise ArgumentTypeError,
+ "Expected #{caller.class}##{meth}'s #{i}th argument to have method ##{type_info} but got #{arg.inspect} instead"
+ end
+ end
+ end
+
+ # @param caller [Module]
+ # @param rtn [Object]
+ # @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 ArgumentTypeError,
- "Expected #{caller.class}##{meth}'s #{i+1}th argument to be #{type_infos[i]} but got #{arg.inspect} instead"
+ raise ReturnTypeError,
+ "Expected #{caller.class}##{meth} to return #{type_info} but got #{rtn.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"
+ raise ReturnTypeError,
+ "Expected #{caller.class}##{meth} to return object which has method ##{type_info} but got #{rtn.inspect} instead"
end
end
- end
- # @param caller [Module]
- # @param rtn [Object]
- # @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"
+ # @param obj [Object]
+ # @param type_info [Class, Symbol]
+ # @return [Symbol]
+ def type_check(obj, type_info)
+ case type_info
+ when Module
+ :need_correct_class unless (obj.is_a?(type_info) || type_info == Any)
+ when Symbol
+ :need_correct_method unless (obj.respond_to?(type_info))
+ end
end
- end
-
- # @param obj [Object]
- # @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