module Rtype

Public Class Methods

and(*args) click to toggle source
# File lib/rtype/behavior/and.rb, line 21
def self.and(*args)
        Behavior::And[*args]
end

Public Instance Methods

arg_message(idx) click to toggle source

@return [String]

# File lib/rtype/legacy.rb, line 142
def arg_message(idx)
        "for #{ordinalize_number(idx+1)} argument:"
end
arg_type_error_message(idx, expected, value) click to toggle source

@param [Integer] idx @param expected A type behavior @param value @return [String] A error message

@raise [ArgumentError] If expected is invalid

# File lib/rtype/legacy.rb, line 137
def arg_type_error_message(idx, expected, value)
        "#{arg_message(idx)}\n" + type_error_message(expected, value)
end
assert_arguments_type(expected_args, args) click to toggle source

Validates arguments

@param [Array] expected_args A type signature for non-keyword arguments @param [Array] args @return [void]

@raise [TypeSignatureError] If expected_args is invalid @raise [ArgumentTypeError] If args is invalid

# File lib/rtype/legacy.rb, line 326
def assert_arguments_type(expected_args, args)
        e_len = expected_args.length
        # `length.times` is faster than `each_with_index`
        args.length.times do |i|
                break if i >= e_len
                expected = expected_args[i]
                value = args[i]
                unless valid?(expected, value)
                        raise ArgumentTypeError, "#{arg_message(i)}\n" + type_error_message(expected, value)
                end
        end
        nil
end
assert_return_type(expected, result) click to toggle source
# File lib/rtype/legacy.rb, line 350
def assert_return_type(expected, result)
        unless valid?(expected, result)
                raise ReturnTypeError, "for return:\n" + type_error_message(expected, result)
        end
        nil
end
assert_valid_argument_type_sig_element(sig) click to toggle source

Checks the type behavior is valid

@param sig A type behavior @raise [TypeSignatureError] If sig is invalid

# File lib/rtype/legacy.rb, line 248
def assert_valid_argument_type_sig_element(sig)
        case sig
        when Rtype::Behavior::Base
        when Module
        when Symbol
        when Regexp
        when Range
        when Array
                sig.each do |e|
                        assert_valid_argument_type_sig_element(e)
                end
        when Hash
                sig.each_value do |e|
                        assert_valid_argument_type_sig_element(e)
                end
        when Proc
        when true
        when false
        when nil
        else
                raise TypeSignatureError, "Invalid type signature: Unknown type behavior #{sig}"
        end
end
assert_valid_arguments_type_sig(sig) click to toggle source

Checks the arguments type signature is valid

e.g. ‘[Integer]`, `{key: “value”}` are valid (the second is keyword argument signature and ignored in rtype-legacy). `Integer` is invalid.

@param sig A arguments type signature @raise [TypeSignatureError] If sig is invalid

# File lib/rtype/legacy.rb, line 223
def assert_valid_arguments_type_sig(sig)
        if sig.is_a?(Array)
                sig = sig.dup
                if sig.last.is_a?(Hash)
                        kwargs = sig.pop
                else
                        kwargs = {}
                end
                sig.each { |e| assert_valid_argument_type_sig_element(e) }
                unless kwargs.empty?
                        raise TypeSignatureError, "Invalid type signature: keyword arguments must be empty"
                end
        elsif sig.is_a?(Hash)
                unless kwargs.empty?
                        raise TypeSignatureError, "Invalid type signature: keyword arguments must be empty"
                end
        else
                raise TypeSignatureError, "Invalid type signature: arguments type signature is neither array nor hash"
        end
end
assert_valid_return_type_sig(sig) click to toggle source

@see assert_valid_argument_type_sig_element

# File lib/rtype/legacy.rb, line 273
def assert_valid_return_type_sig(sig)
        assert_valid_argument_type_sig_element(sig)
end
assert_valid_type_sig(sig) click to toggle source

Checks the type signature is valid

e.g. ‘[Integer] => Any` is valid. `[Integer]` or `Any` are invalid

@param sig A type signature @raise [TypeSignatureError] If sig is invalid

# File lib/rtype/legacy.rb, line 204
def assert_valid_type_sig(sig)
        unless sig.is_a?(Hash)
                raise TypeSignatureError, "Invalid type signature: type signature is not hash"
        end
        if sig.empty?
                raise TypeSignatureError, "Invalid type signature: type signature is empty hash"
        end
        assert_valid_arguments_type_sig(sig.first[0])
        assert_valid_return_type_sig(sig.first[1])
end
define_typed_accessor(owner, name, type_behavior, singleton) click to toggle source

@param owner Owner of the accessor @param [#to_sym] name @param type_behavior A type behavior. e.g. Integer @param [Boolean] singleton Whether the method is singleton method @return [void]

@raise [ArgumentError] If name is nil @raise [TypeSignatureError]

# File lib/rtype/legacy.rb, line 89
def define_typed_accessor(owner, name, type_behavior, singleton)
        define_typed_reader(owner, name, type_behavior, singleton)
        define_typed_writer(owner, name, type_behavior, singleton)
end
define_typed_method(owner, method_name, type_sig_info, singleton) click to toggle source

Makes the method typed @param owner Owner of the method @param [#to_sym] method_name @param [Hash] type_sig_info A type signature. e.g. ‘[Integer, Float] => Float` @param [Boolean] singleton Whether the method is singleton method @return [void]

@raise [ArgumentError] If method_name is nil, keyword argument signature is not empty, or singleton is not a boolean @raise [TypeSignatureError] If type_sig_info is invalid

# File lib/rtype/legacy.rb, line 47
def define_typed_method(owner, method_name, type_sig_info, singleton)
        method_name = method_name.to_sym
        raise ArgumentError, "method_name is nil" if method_name.nil?
        raise ArgumentError, "singleton must be a boolean" unless singleton.is_a?(Boolean)
        assert_valid_type_sig(type_sig_info)

        el = type_sig_info.first
        arg_sig = el[0]
        return_sig = el[1]

        if arg_sig.is_a?(Array)
                expected_args = arg_sig.dup
                if expected_args.last.is_a?(Hash)
                        kwargs = expected_args.pop
                        # empty kwargs signature
                else
                        # empty kwargs signature
                end
        elsif arg_sig.is_a?(Hash)
                # empty kwargs signature
                expected_args = []
        end

        sig = TypeSignature.new
        sig.argument_type = arg_sig
        sig.return_type = return_sig
        unless @@type_signatures.key?(owner)
                @@type_signatures[owner] = {}
        end
        @@type_signatures[owner][method_name] = sig

        redefine_method_to_typed(owner, method_name, expected_args, return_sig, singleton)
end
define_typed_reader(owner, name, type_behavior, singleton) click to toggle source

@param owner Owner of the getter @param [#to_sym] name @param type_behavior A type behavior. e.g. Integer @param [Boolean] singleton Whether the method is singleton method @return [void]

@raise [ArgumentError] If name is nil @raise [TypeSignatureError]

# File lib/rtype/legacy.rb, line 102
def define_typed_reader(owner, name, type_behavior, singleton)
        raise ArgumentError, "name is nil" if name.nil?
        valid?(type_behavior, nil)
        define_typed_method owner, name.to_sym, {[] => type_behavior}, singleton
end
define_typed_writer(owner, name, type_behavior, singleton) click to toggle source

@param owner Owner of the setter @param [#to_sym] name @param type_behavior A type behavior. e.g. Integer @param [Boolean] singleton Whether the method is singleton method @return [void]

@raise [ArgumentError] If name is nil @raise [TypeSignatureError]

# File lib/rtype/legacy.rb, line 116
def define_typed_writer(owner, name, type_behavior, singleton)
        raise ArgumentError, "name is nil" if name.nil?
        valid?(type_behavior, nil)
        define_typed_method owner, :"#{name.to_sym}=", {[type_behavior] => Any}, singleton
end
nilable(*args) click to toggle source
# File lib/rtype/behavior/nilable.rb, line 18
def nilable(*args)
        Behavior::Nilable[*args]
end
not(*args) click to toggle source
# File lib/rtype/behavior/not.rb, line 21
def not(*args)
        Behavior::Not[*args]
end
type_error_message(expected, value) click to toggle source

Returns a error message for the pair of type behavior and value

@param expected A type behavior @param value @return [String] error message

@note This method doesn’t check the value is valid @raise [TypeSignatureError] If expected is invalid

# File lib/rtype/legacy.rb, line 154
def type_error_message(expected, value)
        case expected
        when Rtype::Behavior::Base
                expected.error_message(value)
        when Module
                "Expected #{value.inspect} to be a #{expected}"
        when Symbol
                "Expected #{value.inspect} to respond to :#{expected}"
        when Regexp
                "Expected stringified #{value.inspect} to match regexp #{expected.inspect}"
        when Range
                "Expected #{value.inspect} to be included in range #{expected.inspect}"
        when Array
                arr = expected.map { |e| type_error_message(e, value) }
                arr.join("\nOR ")
        when Hash
                if value.is_a?(Hash)
                        arr = []
                        expected.each do |k, v|
                                if v.is_a?(Array) || v.is_a?(Hash)
                                        arr << "- #{k} : {\n" + type_error_message(v, value[k]) + "\n}"
                                else
                                        arr << "- #{k} : " + type_error_message(v, value[k])
                                end
                        end
                        "Expected #{value.inspect} to be a hash with #{expected.length} elements:\n" + arr.join("\n")
                else
                        "Expected #{value.inspect} to be a hash"
                end
        when Proc
                "Expected #{value.inspect} to return a truthy value for proc #{expected}"
        when true
                "Expected #{value.inspect} to be a truthy value"
        when false
                "Expected #{value.inspect} to be a falsy value"
        when nil # for return
                "Expected #{value.inspect} to be nil"
        else
                raise TypeSignatureError, "Invalid type behavior #{expected}"
        end
end
type_signatures() click to toggle source

This is just ‘information’ Any change of this doesn’t affect type checking

@return [Hash] @note type_signatures[method_name]

# File lib/rtype/legacy.rb, line 127
def type_signatures
        @@type_signatures
end
valid?(expected, value) click to toggle source

Checks the value is valid for the type behavior

@param expected A type behavior @param value @return [Boolean]

@raise [TypeSignatureError] If expected is invalid

# File lib/rtype/legacy.rb, line 285
def valid?(expected, value)
        case expected
        when Module
                value.is_a? expected
        when Symbol
                value.respond_to? expected
        when Regexp
                !!(expected =~ value.to_s)
        when Range
                expected.include?(value)
        when Hash
                return false unless value.is_a?(Hash)
                return false unless expected.keys == value.keys
                expected.all? { |k, v| valid?(v, value[k]) }
        when Array
                expected.any? { |e| valid?(e, value) }
        when Proc
                !!expected.call(value)
        when true
                !!value
        when false
                !value
        when Rtype::Behavior::Base
                expected.valid? value
        when nil
                value.nil?
        else
                raise TypeSignatureError, "Invalid type signature: Unknown type behavior #{expected}"
        end
end
xor(*args) click to toggle source
# File lib/rtype/behavior/xor.rb, line 22
def xor(*args)
        Behavior::Xor[*args]
end

Private Instance Methods

ordinalize_number(num) click to toggle source

@param [Integer] num @return [String]

# File lib/rtype/legacy.rb, line 424
def ordinalize_number(num)
    if (11..13).include?(num % 100)
                "#{num}th"
    else
                case num % 10
                when 1; "#{num}st"
                when 2; "#{num}nd"
                when 3; "#{num}rd"
                else "#{num}th"
                end
    end
end
redefine_method_to_typed(owner, method_name, expected_args, return_sig, singleton) click to toggle source

@param owner @param [Symbol] method_name @param [Array] expected_args @param return_sig @param [Boolean] singleton @return [void]

# File lib/rtype/legacy.rb, line 365
        def redefine_method_to_typed(owner, method_name, expected_args, return_sig, singleton)
                compo = owner.send(:_rtype_component)
                
                methods = owner.instance_methods if !singleton
                methods = owner.methods if singleton
                
                if methods.include?(method_name)
=begin
                        unless compo.has_old?(method_name, singleton)
                                old_method = owner.instance_method(method_name) if !singleton
                                old_method = owner.method(method_name) if singleton
                                compo.set_old(method_name, singleton, old_method)
                        end
=end
                        if compo.has_old?(method_name, singleton)
                                old_method = compo.get_old(method_name, singleton)
                        else
                                old_method = owner.instance_method(method_name) if !singleton
                                old_method = owner.method(method_name) if singleton
                                compo.set_old(method_name, singleton, old_method)
                        end
                else # Undefined method
                        compo.add_undef(method_name, expected_args, return_sig, singleton)
                        return
                end
                
                owner = owner.singleton_class if singleton
                priv = owner.private_method_defined?(method_name)
                prot = owner.protected_method_defined?(method_name)
                
                if !singleton
                        # `send` is faster than `method(...).call`
                        owner.send :define_method, method_name do |*args, &block|
                                ::Rtype::assert_arguments_type(expected_args, args)
                                # result = compo.get_old(method_name, singleton).bind(self).call(*args, &block)
                                result = old_method.bind(self).call(*args, &block)
                                ::Rtype::assert_return_type(return_sig, result)
                                result
                        end
                else
                        owner.send :define_method, method_name do |*args, &block|
                                ::Rtype::assert_arguments_type(expected_args, args)
                                # result = compo.get_old(method_name, singleton).call(*args, &block)
                                result = old_method.call(*args, &block)
                                ::Rtype::assert_return_type(return_sig, result)
                                result
                        end
                end
                
                if priv
                        owner.send(:private, method_name)
                elsif prot
                        owner.send(:protected, method_name)
                end
                nil
        end