rtype 0.6.8-java

Sign up to get free protection for your applications and to get access to all the features.
data/lib/rtype.rb ADDED
@@ -0,0 +1,468 @@
1
+ if Object.const_defined?(:RUBY_ENGINE)
2
+ case RUBY_ENGINE
3
+ when "jruby"
4
+ begin
5
+ require 'java'
6
+ require 'rtype/rtype_java'
7
+ # puts "Rtype with Java extension"
8
+ rescue LoadError
9
+ # puts "Rtype without native extension"
10
+ end
11
+ when "ruby"
12
+ begin
13
+ require "rtype/rtype_native"
14
+ # puts "Rtype with C native extension"
15
+ rescue LoadError
16
+ # puts "Rtype without native extension"
17
+ end
18
+ end
19
+ end
20
+
21
+ require_relative 'rtype/rtype_proxy'
22
+ require_relative 'rtype/method_annotator'
23
+ require_relative 'rtype/core_ext'
24
+ require_relative 'rtype/version'
25
+ require_relative 'rtype/type_signature_error'
26
+ require_relative 'rtype/argument_type_error'
27
+ require_relative 'rtype/return_type_error'
28
+ require_relative 'rtype/type_signature'
29
+ require_relative 'rtype/behavior'
30
+
31
+ module Rtype
32
+ extend self
33
+
34
+ # This is just 'information'
35
+ # Any change of this doesn't affect type checking
36
+ @@type_signatures = Hash.new
37
+
38
+ # Makes the method typed
39
+ # @param owner Owner of the method
40
+ # @param [#to_sym] method_name
41
+ # @param [Hash] type_sig_info A type signature. e.g. `[Integer, Float] => Float`
42
+ # @return [void]
43
+ #
44
+ # @raise [ArgumentError] If method_name is nil
45
+ # @raise [TypeSignatureError] If type_sig_info is invalid
46
+ def define_typed_method(owner, method_name, type_sig_info)
47
+ method_name = method_name.to_sym
48
+ raise ArgumentError, "method_name is nil" if method_name.nil?
49
+ assert_valid_type_sig(type_sig_info)
50
+
51
+ el = type_sig_info.first
52
+ arg_sig = el[0]
53
+ return_sig = el[1]
54
+
55
+ if arg_sig.is_a?(Array)
56
+ expected_args = arg_sig.dup
57
+ if expected_args.last.is_a?(Hash)
58
+ expected_kwargs = expected_args.pop
59
+ else
60
+ expected_kwargs = {}
61
+ end
62
+ elsif arg_sig.is_a?(Hash)
63
+ expected_args = []
64
+ expected_kwargs = arg_sig
65
+ end
66
+
67
+ sig = TypeSignature.new
68
+ sig.argument_type = arg_sig
69
+ sig.return_type = return_sig
70
+ unless @@type_signatures.key?(owner)
71
+ @@type_signatures[owner] = {}
72
+ end
73
+ @@type_signatures[owner][method_name] = sig
74
+
75
+ define_typed_method_to_proxy(owner, method_name, expected_args, expected_kwargs, return_sig)
76
+ end
77
+
78
+ # @param owner Owner of the accessor
79
+ # @param [#to_sym] name
80
+ # @param type_behavior A type behavior. e.g. Integer
81
+ # @return [void]
82
+ #
83
+ # @raise [ArgumentError] If name is nil
84
+ # @raise [TypeSignatureError]
85
+ def define_typed_accessor(owner, name, type_behavior)
86
+ define_typed_reader(owner, name, type_behavior)
87
+ define_typed_writer(owner, name, type_behavior)
88
+ end
89
+
90
+ # @param owner Owner of the getter
91
+ # @param [#to_sym] name
92
+ # @param type_behavior A type behavior. e.g. Integer
93
+ # @return [void]
94
+ #
95
+ # @raise [ArgumentError] If name is nil
96
+ # @raise [TypeSignatureError]
97
+ def define_typed_reader(owner, name, type_behavior)
98
+ raise ArgumentError, "name is nil" if name.nil?
99
+ valid?(type_behavior, nil)
100
+ define_typed_method owner, name.to_sym, [] => type_behavior
101
+ end
102
+
103
+ # @param owner Owner of the setter
104
+ # @param [#to_sym] name
105
+ # @param type_behavior A type behavior. e.g. Integer
106
+ # @return [void]
107
+ #
108
+ # @raise [ArgumentError] If name is nil
109
+ # @raise [TypeSignatureError]
110
+ def define_typed_writer(owner, name, type_behavior)
111
+ raise ArgumentError, "name is nil" if name.nil?
112
+ valid?(type_behavior, nil)
113
+ define_typed_method owner, :"#{name.to_sym}=", [type_behavior] => Any
114
+ end
115
+
116
+ # This is just 'information'
117
+ # Any change of this doesn't affect type checking
118
+ #
119
+ # @return [Hash]
120
+ # @note type_signatures[owner][method_name]
121
+ def type_signatures
122
+ @@type_signatures
123
+ end
124
+
125
+ =begin
126
+ def assert_keyword_arguments_type(expected_kwargs, kwargs)
127
+ kwargs.each do |key, value|
128
+ expected = expected_kwargs[key]
129
+ unless expected.nil?
130
+ unless valid?(expected, value)
131
+ raise ArgumentTypeError, "for '#{key}' argument:\n" + type_error_message(expected, value)
132
+ end
133
+ end
134
+ end
135
+ end
136
+ =end
137
+
138
+ # @param [Integer] idx
139
+ # @param expected A type behavior
140
+ # @param value
141
+ # @return [String] A error message
142
+ #
143
+ # @raise [ArgumentError] If expected is invalid
144
+ def arg_type_error_message(idx, expected, value)
145
+ "#{arg_message(idx)}\n" + type_error_message(expected, value)
146
+ end
147
+
148
+ # @param [String, Symbol] key
149
+ # @param expected A type behavior
150
+ # @param value
151
+ # @return [String] A error message
152
+ #
153
+ # @raise [ArgumentError] If expected is invalid
154
+ def kwarg_type_error_message(key, expected, value)
155
+ "#{kwarg_message(key)}\n" + type_error_message(expected, value)
156
+ end
157
+
158
+ # @return [String]
159
+ def arg_message(idx)
160
+ "for #{ordinalize_number(idx+1)} argument:"
161
+ end
162
+
163
+ # @return [String]
164
+ def kwarg_message(key)
165
+ "for '#{key}' argument:"
166
+ end
167
+
168
+ # Returns a error message for the pair of type behavior and value
169
+ #
170
+ # @param expected A type behavior
171
+ # @param value
172
+ # @return [String] error message
173
+ #
174
+ # @note This method doesn't check the value is valid
175
+ # @raise [TypeSignatureError] If expected is invalid
176
+ def type_error_message(expected, value)
177
+ case expected
178
+ when Rtype::Behavior::Base
179
+ expected.error_message(value)
180
+ when Module
181
+ "Expected #{value.inspect} to be a #{expected}"
182
+ when Symbol
183
+ "Expected #{value.inspect} to respond to :#{expected}"
184
+ when Regexp
185
+ "Expected stringified #{value.inspect} to match regexp #{expected.inspect}"
186
+ when Range
187
+ "Expected #{value.inspect} to be included in range #{expected.inspect}"
188
+ when Array
189
+ arr = expected.map { |e| type_error_message(e, value) }
190
+ arr.join("\nOR ")
191
+ when Hash
192
+ if value.is_a?(Hash)
193
+ arr = []
194
+ expected.each do |k, v|
195
+ if v.is_a?(Array) || v.is_a?(Hash)
196
+ arr << "- #{k} : {\n" + type_error_message(v, value[k]) + "\n}"
197
+ else
198
+ arr << "- #{k} : " + type_error_message(v, value[k])
199
+ end
200
+ end
201
+ "Expected #{value.inspect} to be a hash with #{expected.length} elements:\n" + arr.join("\n")
202
+ else
203
+ "Expected #{value.inspect} to be a hash"
204
+ end
205
+ when Proc
206
+ "Expected #{value.inspect} to return a truthy value for proc #{expected}"
207
+ when true
208
+ "Expected #{value.inspect} to be a truthy value"
209
+ when false
210
+ "Expected #{value.inspect} to be a falsy value"
211
+ when nil # for return
212
+ "Expected #{value.inspect} to be nil"
213
+ else
214
+ raise TypeSignatureError, "Invalid type behavior #{expected}"
215
+ end
216
+ end
217
+
218
+ # Checks the type signature is valid
219
+ #
220
+ # e.g.
221
+ # `[Integer] => Any` is valid.
222
+ # `[Integer]` or `Any` are invalid
223
+ #
224
+ # @param sig A type signature
225
+ # @raise [TypeSignatureError] If sig is invalid
226
+ def assert_valid_type_sig(sig)
227
+ unless sig.is_a?(Hash)
228
+ raise TypeSignatureError, "Invalid type signature: type signature is not hash"
229
+ end
230
+ if sig.empty?
231
+ raise TypeSignatureError, "Invalid type signature: type signature is empty hash"
232
+ end
233
+ assert_valid_arguments_type_sig(sig.first[0])
234
+ assert_valid_return_type_sig(sig.first[1])
235
+ end
236
+
237
+ # Checks the arguments type signature is valid
238
+ #
239
+ # e.g.
240
+ # `[Integer]`, `{key: "value"}` are valid.
241
+ # `Integer` is invalid
242
+ #
243
+ # @param sig A arguments type signature
244
+ # @raise [TypeSignatureError] If sig is invalid
245
+ def assert_valid_arguments_type_sig(sig)
246
+ if sig.is_a?(Array)
247
+ sig = sig.dup
248
+ if sig.last.is_a?(Hash)
249
+ kwargs = sig.pop
250
+ else
251
+ kwargs = {}
252
+ end
253
+ sig.each { |e| assert_valid_argument_type_sig_element(e) }
254
+ if kwargs.keys.any? { |e| !e.is_a?(Symbol) }
255
+ raise TypeSignatureError, "Invalid type signature: keyword arguments contain non-symbol key"
256
+ end
257
+ kwargs.each_value { |e| assert_valid_argument_type_sig_element(e) }
258
+ elsif sig.is_a?(Hash)
259
+ if sig.keys.any? { |e| !e.is_a?(Symbol) }
260
+ raise TypeSignatureError, "Invalid type signature: keyword arguments contain non-symbol key"
261
+ end
262
+ sig.each_value { |e| assert_valid_argument_type_sig_element(e) }
263
+ else
264
+ raise TypeSignatureError, "Invalid type signature: arguments type signature is neither array nor hash"
265
+ end
266
+ end
267
+
268
+ # Checks the type behavior is valid
269
+ #
270
+ # @param sig A type behavior
271
+ # @raise [TypeSignatureError] If sig is invalid
272
+ def assert_valid_argument_type_sig_element(sig)
273
+ case sig
274
+ when Rtype::Behavior::Base
275
+ when Module
276
+ when Symbol
277
+ when Regexp
278
+ when Range
279
+ when Array
280
+ sig.each do |e|
281
+ assert_valid_argument_type_sig_element(e)
282
+ end
283
+ when Hash
284
+ sig.each_value do |e|
285
+ assert_valid_argument_type_sig_element(e)
286
+ end
287
+ when Proc
288
+ when true
289
+ when false
290
+ when nil
291
+ else
292
+ raise TypeSignatureError, "Invalid type signature: Unknown type behavior #{sig}"
293
+ end
294
+ end
295
+
296
+ # @see #assert_valid_argument_type_sig_element
297
+ def assert_valid_return_type_sig(sig)
298
+ assert_valid_argument_type_sig_element(sig)
299
+ end
300
+
301
+ unless respond_to?(:valid?)
302
+ # Checks the value is valid for the type behavior
303
+ #
304
+ # @param expected A type behavior
305
+ # @param value
306
+ # @return [Boolean]
307
+ #
308
+ # @raise [TypeSignatureError] If expected is invalid
309
+ def valid?(expected, value)
310
+ case expected
311
+ when Module
312
+ value.is_a? expected
313
+ when Symbol
314
+ value.respond_to? expected
315
+ when Regexp
316
+ !!(expected =~ value.to_s)
317
+ when Range
318
+ expected.include?(value)
319
+ when Hash
320
+ return false unless value.is_a?(Hash)
321
+ return false unless expected.keys == value.keys
322
+ expected.all? { |k, v| valid?(v, value[k]) }
323
+ when Array
324
+ expected.any? { |e| valid?(e, value) }
325
+ when Proc
326
+ !!expected.call(value)
327
+ when true
328
+ !!value
329
+ when false
330
+ !value
331
+ when Rtype::Behavior::Base
332
+ expected.valid? value
333
+ when nil
334
+ value.nil?
335
+ else
336
+ raise TypeSignatureError, "Invalid type signature: Unknown type behavior #{expected}"
337
+ end
338
+ end
339
+ end
340
+
341
+ unless respond_to?(:assert_arguments_type)
342
+ # Validates arguments
343
+ #
344
+ # @param [Array] expected_args A type signature for non-keyword arguments
345
+ # @param [Array] args
346
+ # @return [void]
347
+ #
348
+ # @raise [TypeSignatureError] If expected_args is invalid
349
+ # @raise [ArgumentTypeError] If args is invalid
350
+ def assert_arguments_type(expected_args, args)
351
+ e_len = expected_args.length
352
+ # `length.times` is faster than `each_with_index`
353
+ args.length.times do |i|
354
+ break if i >= e_len
355
+ expected = expected_args[i]
356
+ value = args[i]
357
+ unless valid?(expected, value)
358
+ raise ArgumentTypeError, "#{arg_message(i)}\n" + type_error_message(expected, value)
359
+ end
360
+ end
361
+ nil
362
+ end
363
+ end
364
+
365
+ unless respond_to?(:assert_arguments_type_with_keywords)
366
+ # Validates arguments and keyword arguments
367
+ #
368
+ # @param [Array] expected_args A type signature for non-keyword arguments
369
+ # @param [Array] args Arguments
370
+ # @param [Hash] expected_kwargs A type signature for keyword arguments
371
+ # @param [Hash] kwargs Keword arguments
372
+ # @return [void]
373
+ #
374
+ # @raise [TypeSignatureError] If expected_args or expected_kwargs are invalid
375
+ # @raise [ArgumentTypeError] If args or kwargs are invalid
376
+ def assert_arguments_type_with_keywords(expected_args, args, expected_kwargs, kwargs)
377
+ e_len = expected_args.length
378
+ # `length.times` is faster than `each_with_index`
379
+ args.length.times do |i|
380
+ break if i >= e_len
381
+ expected = expected_args[i]
382
+ value = args[i]
383
+ unless valid?(expected, value)
384
+ raise ArgumentTypeError, "#{arg_message(i)}\n" + type_error_message(expected, value)
385
+ end
386
+ end
387
+
388
+ kwargs.each do |key, value|
389
+ if expected_kwargs.key?(key)
390
+ expected = expected_kwargs[key]
391
+ unless valid?(expected, value)
392
+ raise ArgumentTypeError, "#{kwarg_message(key)}\n" + type_error_message(expected, value)
393
+ end
394
+ end
395
+ end
396
+ nil
397
+ end
398
+ end
399
+
400
+ # Validates result
401
+ #
402
+ # @param expected A type behavior
403
+ # @param result
404
+ # @return [void]
405
+ #
406
+ # @raise [TypeSignatureError] If expected is invalid
407
+ # @raise [ReturnTypeError] If result is invalid
408
+ unless respond_to?(:assert_return_type)
409
+ def assert_return_type(expected, result)
410
+ unless valid?(expected, result)
411
+ raise ReturnTypeError, "for return:\n" + type_error_message(expected, result)
412
+ end
413
+ nil
414
+ end
415
+ end
416
+
417
+ private
418
+ # @param owner
419
+ # @param [Symbol] method_name
420
+ # @param [Array] expected_args
421
+ # @param [Hash] expected_kwargs
422
+ # @param return_sig
423
+ # @return [void]
424
+ def define_typed_method_to_proxy(owner, method_name, expected_args, expected_kwargs, return_sig)
425
+ priv = owner.private_method_defined?(method_name)
426
+ prot = owner.protected_method_defined?(method_name)
427
+
428
+ if expected_kwargs.empty?
429
+ # `send` is faster than `method(...).call`
430
+ owner.send(:_rtype_proxy).send :define_method, method_name do |*args, &block|
431
+ ::Rtype::assert_arguments_type(expected_args, args)
432
+ result = super(*args, &block)
433
+ ::Rtype::assert_return_type(return_sig, result)
434
+ result
435
+ end
436
+ else
437
+ # `send` is faster than `method(...).call`
438
+ owner.send(:_rtype_proxy).send :define_method, method_name do |*args, **kwargs, &block|
439
+ ::Rtype::assert_arguments_type_with_keywords(expected_args, args, expected_kwargs, kwargs)
440
+ result = super(*args, **kwargs, &block)
441
+ ::Rtype::assert_return_type(return_sig, result)
442
+ result
443
+ end
444
+ end
445
+
446
+ if priv
447
+ owner.send(:_rtype_proxy).send(:private, method_name)
448
+ elsif prot
449
+ owner.send(:_rtype_proxy).send(:protected, method_name)
450
+ end
451
+ nil
452
+ end
453
+
454
+ # @param [Integer] num
455
+ # @return [String]
456
+ def ordinalize_number(num)
457
+ if (11..13).include?(num % 100)
458
+ "#{num}th"
459
+ else
460
+ case num % 10
461
+ when 1; "#{num}st"
462
+ when 2; "#{num}nd"
463
+ when 3; "#{num}rd"
464
+ else "#{num}th"
465
+ end
466
+ end
467
+ end
468
+ end