Module: Rtype

Extended by:
Rtype
Included in:
Rtype
Defined in:
lib/rtype.rb,
lib/rtype/version.rb,
lib/rtype/behavior.rb,
lib/rtype/rtype_proxy.rb,
lib/rtype/behavior/and.rb,
lib/rtype/behavior/not.rb,
lib/rtype/behavior/xor.rb,
lib/rtype/behavior/base.rb,
lib/rtype/type_signature.rb,
lib/rtype/behavior/nilable.rb,
lib/rtype/method_annotator.rb,
lib/rtype/return_type_error.rb,
lib/rtype/argument_type_error.rb,
lib/rtype/type_signature_error.rb

Defined Under Namespace

Modules: Behavior, MethodAnnotator Classes: ArgumentTypeError, ReturnTypeError, RtypeProxy, TypeSignature, TypeSignatureError

Constant Summary collapse

VERSION =
"0.6.0".freeze
JAVA_EXT_VERSION =

rtype java extension version. nil If the extension is not used

nil
NATIVE_EXT_VERSION =

rtype c extension version. nil If the extension is not used

nil
@@type_signatures =

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

Hash.new

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.and(*args) ⇒ Object



21
22
23
# File 'lib/rtype/behavior/and.rb', line 21

def self.and(*args)
  Behavior::And[*args]
end

Instance Method Details

#arg_message(idx) ⇒ Object



100
101
102
# File 'lib/rtype.rb', line 100

def arg_message(idx)
  "for #{ordinalize_number(idx+1)} argument:"
end

#arg_type_error_message(idx, expected, value) ⇒ Object

def assert_keyword_arguments_type(expected_kwargs, kwargs) kwargs.each do |key, value| expected = expected_kwargs unless expected.nil? unless valid?(expected, value) raise ArgumentTypeError, “for ‘#key’ argument:n” + type_error_message(expected, value) end end end end



92
93
94
# File 'lib/rtype.rb', line 92

def arg_type_error_message(idx, expected, value)
  "#{arg_message(idx)}\n" + type_error_message(expected, value)
end

#assert_arguments_type(expected_args, args) ⇒ Object



275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/rtype.rb', line 275

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
end

#assert_arguments_type_with_keywords(expected_args, args, expected_kwargs, kwargs) ⇒ Object



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/rtype.rb', line 290

def assert_arguments_type_with_keywords(expected_args, args, expected_kwargs, kwargs)
  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
  
  kwargs.each do |key, value|
    if expected_kwargs.key?(key)
      expected = expected_kwargs[key]
      unless valid?(expected, value)
        raise ArgumentTypeError, "#{kwarg_message(key)}\n" + type_error_message(expected, value)
      end
    end
  end
end

#assert_return_type(expected, result) ⇒ Object



314
315
316
317
318
# File 'lib/rtype.rb', line 314

def assert_return_type(expected, result)
  unless valid?(expected, result)
    raise ReturnTypeError, "for return:\n" + type_error_message(expected, result)
  end
end

#assert_valid_argument_type_sig_element(sig) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/rtype.rb', line 182

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) ⇒ Object



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/rtype.rb', line 159

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) }
    if kwargs.keys.any? { |e| !e.is_a?(Symbol) }
      raise TypeSignatureError, "Invalid type signature: keyword arguments contain non-symbol key"
    end
    kwargs.each_value { |e| assert_valid_argument_type_sig_element(e) }
  elsif sig.is_a?(Hash)
    if sig.keys.any? { |e| !e.is_a?(Symbol) }
      raise TypeSignatureError, "Invalid type signature: keyword arguments contain non-symbol key"
    end
    sig.each_value { |e| assert_valid_argument_type_sig_element(e) }
  else
    raise TypeSignatureError, "Invalid type signature: arguments type signature is neither array nor hash"
  end
end

#assert_valid_return_type_sig(sig) ⇒ Object



206
207
208
# File 'lib/rtype.rb', line 206

def assert_valid_return_type_sig(sig)
  assert_valid_argument_type_sig_element(sig)
end

#assert_valid_type_sig(sig) ⇒ Object



148
149
150
151
152
153
154
155
156
157
# File 'lib/rtype.rb', line 148

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, accessor_name, type_behavior) ⇒ Object



67
68
69
70
71
72
73
# File 'lib/rtype.rb', line 67

def define_typed_accessor(owner, accessor_name, type_behavior)
  getter = accessor_name.to_sym
  setter = :"#{accessor_name}="
  valid?(type_behavior, nil)
  define_typed_method owner, getter, [] => type_behavior
  define_typed_method owner, setter, [type_behavior] => Any
end

#define_typed_method(owner, method_name, type_sig_info) ⇒ Object

Raises:

  • (ArgumentError)


35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/rtype.rb', line 35

def define_typed_method(owner, method_name, type_sig_info)
  method_name = method_name.to_sym
  raise ArgumentError, "method_name is nil" if method_name.nil?
  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)
      expected_kwargs = expected_args.pop
    else
      expected_kwargs = {}
    end
  elsif arg_sig.is_a?(Hash)
    expected_args = []
    expected_kwargs = arg_sig
  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

  define_typed_method_to_proxy(owner, method_name, expected_args, expected_kwargs, return_sig)
end

#kwarg_message(key) ⇒ Object



104
105
106
# File 'lib/rtype.rb', line 104

def kwarg_message(key)
  "for '#{key}' argument:"
end

#kwarg_type_error_message(key, expected, value) ⇒ Object



96
97
98
# File 'lib/rtype.rb', line 96

def kwarg_type_error_message(key, expected, value)
  "#{kwarg_message(key)}\n" + type_error_message(expected, value)
end

#nilable(*args) ⇒ Object



18
19
20
# File 'lib/rtype/behavior/nilable.rb', line 18

def nilable(*args)
  Behavior::Nilable[*args]
end

#not(*args) ⇒ Object



21
22
23
# File 'lib/rtype/behavior/not.rb', line 21

def not(*args)
  Behavior::Not[*args]
end

#type_error_message(expected, value) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/rtype.rb', line 108

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 an hash with #{expected.length} elements:\n" + arr.join("\n")
    else
      "Expected #{value.inspect} to be an 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"
  end
end

#type_signaturesObject



75
76
77
# File 'lib/rtype.rb', line 75

def type_signatures
  @@type_signatures
end

#valid?(expected, value) ⇒ Boolean

validate argument type

Returns:



242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/rtype.rb', line 242

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) ⇒ Object



22
23
24
# File 'lib/rtype/behavior/xor.rb', line 22

def xor(*args)
  Behavior::Xor[*args]
end