lib/rubype.rb in rubype-0.2.6 vs lib/rubype.rb in rubype-0.3.0

- old
+ new

@@ -1,104 +1,48 @@ -require 'rubype/ordinal' -# === Rubype core === # -class Module - private - def __rubype__ - prepend (@__rubype__ = Module.new) unless @__rubype__ - @__rubype__ - end - # typesig :__rubype__, [] => Rubype +require_relative 'rubype/version' +require_relative 'rubype/contract' - def typesig(meth, type_info_hash) - ::Rubype.define_typed_method(self, meth, type_info_hash, __rubype__) - self - end - # typesig :typesig, [Symbol, Hash] => Module -end - module Rubype - @@typed_method_info = Hash.new({}) - class ArgumentTypeError < ::TypeError; end - class ReturnTypeError < ::TypeError; end + module TypeInfo; end + Module.send(:include, TypeInfo) + Symbol.send(:include, TypeInfo) + @@typed_methods = Hash.new({}) + class << self def define_typed_method(owner, meth, type_info_hash, __rubype__) + raise InvalidTypesigError unless valid_type_info_hash?(type_info_hash) arg_types, rtn_type = *type_info_hash.first - @@typed_method_info[owner][meth] = { arg_types => rtn_type } - + contract = Contract.new(arg_types, rtn_type, owner, meth) + @@typed_methods[owner][meth] = contract + method_visibility = get_method_visibility(owner, meth) __rubype__.send(:define_method, meth) do |*args, &block| - ::Rubype.assert_arg_type(self, meth, args, arg_types, caller) - super(*args, &block).tap do |rtn| - ::Rubype.assert_rtn_type(self, meth, rtn, rtn_type, caller) - end + contract.assert_type(args, super(*args, &block)) end - end - def assert_arg_type(meth_caller, meth, args, type_infos, caller_trace) - args.zip(type_infos).each.with_index(1) do |(arg, type_info), i| - unless match_type?(arg, type_info) - raise ArgumentTypeError, - error_mes("#{meth_caller.class}##{meth}'s #{i}#{ordinal(i)} argument", type_info, arg, caller_trace) - end - end + __rubype__.send(method_visibility, meth) end - def assert_rtn_type(meth_caller, meth, rtn, type_info, caller_trace) - unless match_type?(rtn, type_info) - raise ReturnTypeError, - error_mes("#{meth_caller.class}##{meth}'s return", type_info, rtn, caller_trace) + def get_method_visibility(owner, meth) + case + when owner.private_method_defined?(meth) + :private + when owner.protected_method_defined?(meth) + :protected + else + :public end end - def typed_method_info - @@typed_method_info + def typed_methods + @@typed_methods end private - def match_type?(obj, type_info) - case type_info - when Module; (obj.is_a?(type_info) || type_info == Any) - when Symbol; (obj.respond_to?(type_info)) - end + def valid_type_info_hash?(type_info_hash) + return false unless type_info_hash.is_a?(Hash) + type_info_hash.first[0].is_a?(Array) end - - def error_mes(target, expected, actual, caller_trace) - expected_mes = case expected - when Module; expected - when Symbol; "respond to :#{expected}" - end - <<-ERROR_MES -for #{target} -Expected: #{expected_mes}, -Actual: #{actual.inspect} - -#{caller_trace.join("\n")} - ERROR_MES - end end end -# === end (only 79 lines :D)=== # -# Builtin Contracts -class Any; end -module Boolean; end -TrueClass.send(:include, Boolean) -FalseClass.send(:include, Boolean) - -class Method - def type_info - if methods_hash = Rubype.typed_method_info[owner] - methods_hash[name] - end - end - typesig :type_info, [] => Hash - - def arg_types - type_info.first.first if type_info - end - typesig :arg_types, [] => Array - - def return_type - type_info.first.last if type_info - end - typesig :arg_types, [] => Any -end +require_relative 'rubype/core_ext'