rtype 0.6.8-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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