rtype 0.6.0 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 545e8dc3a8ac3c44aa68d87126c6dbf8d57302bb
4
- data.tar.gz: f3d34bb1fb2ecd9cb7f4b0a9315d14fa5a726940
3
+ metadata.gz: 4edbfe36753db1a9d6a413bf31ccbed37c499df5
4
+ data.tar.gz: bfa734ba5689e7fca457b247e0f03dbcde507f8e
5
5
  SHA512:
6
- metadata.gz: e39262cd99fdf372ed953a2e4c09cafcc09b7d236946d66d3d37acd03f432e72a0de4f7aaf3cd7d74e0d8997ef0178846ba35c040e209acc08a4a60b4e43f7b5
7
- data.tar.gz: e31ad200c1d08bb0077ef429cfa4d813bff2732f04f705eafc0ce4166c9dbbf0f82581a9e4655500fdb35ec09721cc22c3d29104fccf40c789fd2cdc7bd3f8b2
6
+ metadata.gz: 60031209128806548c02edc8944e18a103c3f34a2ddca144dd53716050e939d9f7e4baf9ec7d33a3cf70da28ef156b5fcafd8177cddba6f11be6029cf0a4357a
7
+ data.tar.gz: 5f40a360733043804e02478347ec2a8a3c187b3d7ea943e31d470a7b4727fa4d89770ad93d1e08bb349550ea1a733fc4f2908d0776db4df777567dcc6083b8e1
data/README.md CHANGED
@@ -32,9 +32,9 @@ Test::invert(state: 0)
32
32
  ## Requirements
33
33
  - Ruby >= 2.1
34
34
  - MRI
35
- - If C native extension is used, otherwise it is not required
36
- - JRuby
37
- - If Java extension is used, otherwise it is not required
35
+ - If C native extension is used. otherwise it is not required
36
+ - JRuby (JRuby 9000+)
37
+ - If Java extension is used. otherwise it is not required
38
38
 
39
39
  ## Features
40
40
  - Provides type checking for arguments and return
@@ -80,52 +80,58 @@ then, Rtype use it. (Do not `require 'rtype-java'`)
80
80
 
81
81
  ### Supported Type Behaviors
82
82
  - `Module`
83
- - Value must be an instance of the module/class or one of its superclasses
83
+ - A value must be an instance of the module/class or one of its superclasses (`is_a?`)
84
84
  - `Any` : An alias for `BasicObject` (means Any Object)
85
85
  - `Boolean` : `true` or `false`
86
86
  - `Symbol`
87
- - Value must have(respond to) a method with the name
87
+ - A value must have(respond to) a method with the name
88
88
  - `Regexp`
89
- - Value must match the regexp pattern
89
+ - A value must match the regexp pattern
90
90
  - `Range`
91
- - Value must be included in the range
91
+ - A value must be included in the range
92
92
  - `Array`
93
- - Value can be any type in the array
93
+ - A value can be any type in the array
94
94
  - `Hash`
95
- - Value must be an hash
96
- - Each of value’s elements must be valid
97
- - Value's key list must be equal to the hash's key list
95
+ - A value must be a hash
96
+ - Each of the value’s elements must be valid
97
+ - The value's key list must be equal to the hash's key list
98
98
  - **String** key is **different** from **symbol** key
99
- - vs Keyword arguments (e.g.)
100
- - `[{}]` is **not** hash type argument. it is keyword argument because its position is last
101
- - `[{}, {}]` is empty hash type argument (first) and one empty keyword argument (second)
102
- - `[{}, {}, {}]` is two empty hash type argument (first, second) and empty keyword argument (last)
99
+ - vs. Keyword arguments (e.g.)
100
+ - `[{}]` is **not** hash type argument. it is keyword argument, because its position is last
101
+ - `[{}, {}]` is empty hash type argument (first), and one empty keyword argument (second)
102
+ - `[{}, {}, {}]` is two empty hash type argument (first, second), and empty keyword argument (last)
103
103
  - `{}` is keyword argument. non-keyword arguments must be in array.
104
104
  - Of course, nested hash works
105
105
  - Example: [Hash](#hash)
106
106
  - `Proc`
107
- - Value must return a truthy value for the proc
107
+ - A value must return a truthy value for the proc
108
108
  - `true`
109
- - Value must be **truthy**
109
+ - A value must be **truthy**
110
110
  - `false`
111
- - Value must be **falsy**
111
+ - A value must be **falsy**
112
112
  - `nil`
113
- - Value must be nil
113
+ - A value must be nil
114
+
114
115
  - Special Behaviors
115
- - `Rtype::and(*types)` : Ensure value is valid for all the types
116
+ - `Rtype::TypedArray` : Ensures a value is an array with the type (type signature)
117
+ - `Array::of(type)` (recommended)
118
+ - `Rtype::Behavior::TypedArray[type]`
119
+ - Example: [TypedArray](#typed-array)
120
+
121
+ - `Rtype::and(*types)` : Ensures a value is valid for all the types
116
122
  - `Rtype::and(*types)`, `Rtype::Behavior::And[*types]`, `include Rtype::Behavior; And[...]`
117
123
  - `Array#comb`
118
124
  - `Object#and(*others)`
119
125
 
120
- - `Rtype::xor(*types)` : Ensure value is valid for only one of the types
126
+ - `Rtype::xor(*types)` : Ensures a value is valid for only one of the types
121
127
  - `Rtype::xor(*types)`, `Rtype::Behavior::Xor[*types]`, `include Rtype::Behavior; Xor[...]`
122
128
  - `Object#xor(*others)`
123
129
 
124
- - `Rtype::not(*types)` : Ensure value is not valid for all the types
130
+ - `Rtype::not(*types)` : Ensures a value is not valid for all the types
125
131
  - `Rtype::not(*types)`, `Rtype::Behavior::Not[*types]`, `include Rtype::Behavior; Not[...]`
126
132
  - `Object#not`
127
133
 
128
- - `Rtype::nilable(type)` : Ensure value can be nil
134
+ - `Rtype::nilable(type)` : Ensures a value can be nil
129
135
  - `Rtype::nilable(type)`, `Rtype::Behavior::Nilable[type]`, `include Rtype::Behavior; Nilable[...]`
130
136
  - `Object#nilable`
131
137
  - `Object#or_nil`
@@ -231,29 +237,29 @@ end
231
237
  # last hash is keyword arguments
232
238
  func({}, {})
233
239
  # (Rtype::ArgumentTypeError) for 1st argument:
234
- # Expected {} to be an hash with 1 elements:
240
+ # Expected {} to be a hash with 1 elements:
235
241
  # - msg : Expected nil to be a String
236
242
 
237
243
  func({msg: 123}, {})
238
244
  # (Rtype::ArgumentTypeError) for 1st argument:
239
- # Expected {:msg=>123} to be an hash with 1 elements:
245
+ # Expected {:msg=>123} to be a hash with 1 elements:
240
246
  # - msg : Expected 123 to be a String
241
247
 
242
248
  func({msg: "hello", key: 'value'}, {})
243
249
  # (Rtype::ArgumentTypeError) for 1st argument:
244
- # Expected {:msg=>"hello", :key=>"value"} to be an hash with 1 elements:
250
+ # Expected {:msg=>"hello", :key=>"value"} to be a hash with 1 elements:
245
251
  # - msg : Expected "hello" to be a String
246
252
 
247
253
  func({"msg" => "hello hash"}, {})
248
254
  # (Rtype::ArgumentTypeError) for 1st argument:
249
- # Expected {"msg"=>"hello hash"} to be an hash with 1 elements:
255
+ # Expected {"msg"=>"hello hash"} to be a hash with 1 elements:
250
256
  # - msg : Expected nil to be a String
251
257
 
252
258
  func({msg: "hello hash"}, {}) # hello hash
253
259
  ```
254
260
 
255
261
  #### rtype with attr_accessor
256
- `rtype_accessor` : calls `attr_accessor` if the accessor method(getter/setter) is not defined, and makes it typed method
262
+ `rtype_accessor` : calls `attr_accessor` if the accessor method(getter/setter) is not defined. and makes it typed
257
263
 
258
264
  You can use `rtype_accessor_self` for static accessor.
259
265
 
@@ -277,6 +283,38 @@ Example.new.value
277
283
  # Expected 456 to be a String
278
284
  ```
279
285
 
286
+ #### Typed Array
287
+ ```ruby
288
+ ### TEST 1 ###
289
+ class Test
290
+ rtype [Array.of(Integer)] => Any
291
+ def sum(args)
292
+ num = 0
293
+ args.each { |e| num += e }
294
+ end
295
+ end
296
+
297
+ sum([1, 2, 3]) # => 6
298
+
299
+ sum([1.0, 2, 3])
300
+ # (Rtype::ArgumentTypeError) for 1st argument:
301
+ # Expected [1.0, 2, 3] to be an array with type Integer"
302
+ ```
303
+
304
+ ```ruby
305
+ ### TEST 2 ###
306
+ class Test
307
+ rtype [ Array.of([Integer, Float]) ] => Any
308
+ def sum(args)
309
+ num = 0
310
+ args.each { |e| num += e }
311
+ end
312
+ end
313
+
314
+ sum([1, 2, 3]) # => 6
315
+ sum([1.0, 2, 3]) # => 6.0
316
+ ```
317
+
280
318
  #### Combined type
281
319
  ```ruby
282
320
  ### TEST 1 ###
@@ -342,7 +380,7 @@ Game::Player.new.attacks Game::Slime.new
342
380
  # Player attacks 'Powerful Slime' (level 123)!
343
381
  ```
344
382
 
345
- #### Position of `rtype` && (Specify method name || annotation mode) && (Symbol || String)
383
+ #### Position of `rtype` && (specifying method name || annotation mode) && (symbol || string)
346
384
  ```ruby
347
385
  require 'rtype'
348
386
 
@@ -371,7 +409,7 @@ class Example
371
409
  puts "Hello? #{i} #{str}"
372
410
  end
373
411
 
374
- # Don't works. `rtype` works for next method
412
+ # Doesn't work. `rtype` works for following (next) method
375
413
  def hello_world_four(i, str)
376
414
  puts "Hello? #{i} #{str}"
377
415
  end
@@ -380,7 +418,7 @@ end
380
418
  ```
381
419
 
382
420
  #### Outside of module (root)
383
- Outside of module, annotation mode don't works. You must specify method name.
421
+ In the outside of module, annotation mode don't works. You must specify method name.
384
422
 
385
423
  ```ruby
386
424
  rtype :say, [String] => Any
@@ -394,7 +432,7 @@ rtype [String] => Any
394
432
  # (ArgumentError) Annotation mode not working out of module
395
433
  ```
396
434
 
397
- #### Static(singleton) method
435
+ #### Class method
398
436
  rtype annotation mode works both instance and class method
399
437
 
400
438
  ```ruby
@@ -410,7 +448,7 @@ end
410
448
  Example::say_ya(3) #say ya ya ya
411
449
  ```
412
450
 
413
- however, if you specify method name, you must use `rtype_self` instead of `rtype`
451
+ if you specify method name, however, you must use `rtype_self` instead of `rtype`
414
452
 
415
453
  ```ruby
416
454
  require 'rtype'
@@ -425,7 +463,7 @@ end
425
463
  Example::say_ya(3) #say ya ya ya
426
464
  ```
427
465
 
428
- #### Check type information
466
+ #### Checking type information
429
467
  This is just the 'information'
430
468
 
431
469
  Any change of this doesn't affect type checking
@@ -524,7 +562,7 @@ Comparison:
524
562
  ## Rubype, Sig
525
563
  Rtype is influenced by [Rubype](https://github.com/gogotanaka/Rubype) and [Sig](https://github.com/janlelis/sig).
526
564
 
527
- If you don't like Rtype, You can use other type checking gem such as Contracts, Rubype, Rtc, Typecheck, Sig.
565
+ If you don't like Rtype, You can use other library such as Contracts, Rubype, Rtc, Typecheck, Sig.
528
566
 
529
567
  ## Author
530
568
  Sputnik Gugja (sputnikgugja@gmail.com)
@@ -2,16 +2,16 @@ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "jruby"
2
2
  begin
3
3
  require 'java'
4
4
  require 'rtype/rtype_java'
5
- puts "Rtype with Java extension"
5
+ # puts "Rtype with Java extension"
6
6
  rescue LoadError
7
- puts "Rtype without native extension"
7
+ # puts "Rtype without native extension"
8
8
  end
9
9
  else
10
10
  begin
11
11
  require "rtype/rtype_native"
12
- puts "Rtype with C native extension"
12
+ # puts "Rtype with C native extension"
13
13
  rescue LoadError
14
- puts "Rtype without native extension"
14
+ # puts "Rtype without native extension"
15
15
  end
16
16
  end
17
17
 
@@ -28,10 +28,18 @@ require_relative 'rtype/behavior'
28
28
  module Rtype
29
29
  extend self
30
30
 
31
- # This is just the 'information'
31
+ # This is just 'information'
32
32
  # Any change of this doesn't affect type checking
33
33
  @@type_signatures = Hash.new
34
34
 
35
+ # Makes the method typed
36
+ # @param owner Owner of the method
37
+ # @param [#to_sym] method_name
38
+ # @param [Hash] type_sig_info A type signature. e.g. `[Integer, Float] => Float`
39
+ # @return [void]
40
+ #
41
+ # @raise [ArgumentError] If method_name is nil
42
+ # @raise [TypeSignatureError] If type_sig_info is invalid
35
43
  def define_typed_method(owner, method_name, type_sig_info)
36
44
  method_name = method_name.to_sym
37
45
  raise ArgumentError, "method_name is nil" if method_name.nil?
@@ -64,7 +72,20 @@ module Rtype
64
72
  define_typed_method_to_proxy(owner, method_name, expected_args, expected_kwargs, return_sig)
65
73
  end
66
74
 
75
+ # Calls `attr_accessor` if the accessor method(getter/setter) is not defined.
76
+ # and makes it typed.
77
+ #
78
+ # this method uses `define_typed_method` for getter and setter.
79
+ #
80
+ # @param owner Owner of the accessor
81
+ # @param [#to_sym] accessor_name
82
+ # @param type_behavior A type behavior. e.g. Integer
83
+ # @return [void]
84
+ #
85
+ # @raise [ArgumentError] If accessor_name is nil
86
+ # @raise [TypeSignatureError]
67
87
  def define_typed_accessor(owner, accessor_name, type_behavior)
88
+ raise ArgumentError, "accessor_name is nil" if accessor_name.nil?
68
89
  getter = accessor_name.to_sym
69
90
  setter = :"#{accessor_name}="
70
91
  valid?(type_behavior, nil)
@@ -72,6 +93,11 @@ module Rtype
72
93
  define_typed_method owner, setter, [type_behavior] => Any
73
94
  end
74
95
 
96
+ # This is just 'information'
97
+ # Any change of this doesn't affect type checking
98
+ #
99
+ # @return [Hash]
100
+ # @note type_signatures[owner][method_name]
75
101
  def type_signatures
76
102
  @@type_signatures
77
103
  end
@@ -89,22 +115,44 @@ module Rtype
89
115
  end
90
116
  =end
91
117
 
118
+ # @param [Integer] idx
119
+ # @param expected A type behavior
120
+ # @param value
121
+ # @return [String] A error message
122
+ #
123
+ # @raise [ArgumentError] If expected is invalid
92
124
  def arg_type_error_message(idx, expected, value)
93
125
  "#{arg_message(idx)}\n" + type_error_message(expected, value)
94
126
  end
95
127
 
128
+ # @param [String, Symbol] key
129
+ # @param expected A type behavior
130
+ # @param value
131
+ # @return [String] A error message
132
+ #
133
+ # @raise [ArgumentError] If expected is invalid
96
134
  def kwarg_type_error_message(key, expected, value)
97
135
  "#{kwarg_message(key)}\n" + type_error_message(expected, value)
98
136
  end
99
-
137
+
138
+ # @return [String]
100
139
  def arg_message(idx)
101
140
  "for #{ordinalize_number(idx+1)} argument:"
102
141
  end
103
142
 
143
+ # @return [String]
104
144
  def kwarg_message(key)
105
145
  "for '#{key}' argument:"
106
146
  end
107
147
 
148
+ # Returns a error message for the pair of type behavior and value
149
+ #
150
+ # @param expected A type behavior
151
+ # @param value
152
+ # @return [String] error message
153
+ #
154
+ # @note This method doesn't check the value is valid
155
+ # @raise [TypeSignatureError] If expected is invalid
108
156
  def type_error_message(expected, value)
109
157
  case expected
110
158
  when Rtype::Behavior::Base
@@ -130,9 +178,9 @@ module Rtype
130
178
  arr << "- #{k} : " + type_error_message(v, value[k])
131
179
  end
132
180
  end
133
- "Expected #{value.inspect} to be an hash with #{expected.length} elements:\n" + arr.join("\n")
181
+ "Expected #{value.inspect} to be a hash with #{expected.length} elements:\n" + arr.join("\n")
134
182
  else
135
- "Expected #{value.inspect} to be an hash"
183
+ "Expected #{value.inspect} to be a hash"
136
184
  end
137
185
  when Proc
138
186
  "Expected #{value.inspect} to return a truthy value for proc #{expected}"
@@ -142,9 +190,19 @@ module Rtype
142
190
  "Expected #{value.inspect} to be a falsy value"
143
191
  when nil # for return
144
192
  "Expected #{value.inspect} to be nil"
193
+ else
194
+ raise TypeSignatureError, "Invalid type behavior #{expected}"
145
195
  end
146
196
  end
147
197
 
198
+ # Checks the type signature is valid
199
+ #
200
+ # e.g.
201
+ # `[Integer] => Any` is valid.
202
+ # `[Integer]` or `Any` are invalid
203
+ #
204
+ # @param sig A type signature
205
+ # @raise [TypeSignatureError] If sig is invalid
148
206
  def assert_valid_type_sig(sig)
149
207
  unless sig.is_a?(Hash)
150
208
  raise TypeSignatureError, "Invalid type signature: type signature is not hash"
@@ -156,6 +214,14 @@ module Rtype
156
214
  assert_valid_return_type_sig(sig.first[1])
157
215
  end
158
216
 
217
+ # Checks the arguments type signature is valid
218
+ #
219
+ # e.g.
220
+ # `[Integer]`, `{key: "value"} are valid.
221
+ # `Integer` is invalid
222
+ #
223
+ # @param sig A arguments type signature
224
+ # @raise [TypeSignatureError] If sig is invalid
159
225
  def assert_valid_arguments_type_sig(sig)
160
226
  if sig.is_a?(Array)
161
227
  sig = sig.dup
@@ -179,6 +245,10 @@ module Rtype
179
245
  end
180
246
  end
181
247
 
248
+ # Checks the type behavior is valid
249
+ #
250
+ # @param sig A type behavior
251
+ # @raise [TypeSignatureError] If sig is invalid
182
252
  def assert_valid_argument_type_sig_element(sig)
183
253
  case sig
184
254
  when Rtype::Behavior::Base
@@ -203,42 +273,19 @@ module Rtype
203
273
  end
204
274
  end
205
275
 
276
+ # @see #assert_valid_argument_type_sig_element
206
277
  def assert_valid_return_type_sig(sig)
207
278
  assert_valid_argument_type_sig_element(sig)
208
279
  end
209
-
210
- private
211
- def define_typed_method_to_proxy(owner, method_name, expected_args, expected_kwargs, return_sig)
212
- # `send` is faster than `method(...).call`
213
- owner.send(:_rtype_proxy).send :define_method, method_name do |*args, **kwargs, &block|
214
- if kwargs.empty?
215
- ::Rtype::assert_arguments_type(expected_args, args)
216
- result = super(*args, &block)
217
- else
218
- ::Rtype::assert_arguments_type_with_keywords(expected_args, args, expected_kwargs, kwargs)
219
- result = super(*args, **kwargs, &block)
220
- end
221
- ::Rtype::assert_return_type(return_sig, result)
222
- result
223
- end
224
- nil
225
- end
226
280
 
227
- def ordinalize_number(num)
228
- if (11..13).include?(num % 100)
229
- "#{num}th"
230
- else
231
- case num % 10
232
- when 1; "#{num}st"
233
- when 2; "#{num}nd"
234
- when 3; "#{num}rd"
235
- else "#{num}th"
236
- end
237
- end
238
- end
239
- public
240
281
  unless respond_to?(:valid?)
241
- # validate argument type
282
+ # Checks the value is valid for the type behavior
283
+ #
284
+ # @param expected A type behavior
285
+ # @param value
286
+ # @return [Boolean]
287
+ #
288
+ # @raise [TypeSignatureError] If expected is invalid
242
289
  def valid?(expected, value)
243
290
  case expected
244
291
  when Module
@@ -272,6 +319,14 @@ public
272
319
  end
273
320
 
274
321
  unless respond_to?(:assert_arguments_type)
322
+ # Validates arguments
323
+ #
324
+ # @param [Array] expected_args A type signature for non-keyword arguments
325
+ # @param args
326
+ # @return [void]
327
+ #
328
+ # @raise [TypeSignatureError] If expected_args is invalid
329
+ # @raise [ArgumentTypeError] If args is invalid
275
330
  def assert_arguments_type(expected_args, args)
276
331
  e_len = expected_args.length
277
332
  # `length.times` is faster than `each_with_index`
@@ -283,10 +338,21 @@ public
283
338
  raise ArgumentTypeError, "#{arg_message(i)}\n" + type_error_message(expected, value)
284
339
  end
285
340
  end
341
+ nil
286
342
  end
287
343
  end
288
344
 
289
345
  unless respond_to?(:assert_arguments_type_with_keywords)
346
+ # Validates arguments and keyword arguments
347
+ #
348
+ # @param [Array] expected_args A type signature for non-keyword arguments
349
+ # @param args Arguments
350
+ # @param [Hash] expected_kwargs A type signature for keyword arguments
351
+ # @param kwargs Keword arguments
352
+ # @return [void]
353
+ #
354
+ # @raise [TypeSignatureError] If expected_args or expected_kwargs are invalid
355
+ # @raise [ArgumentTypeError] If args or kwargs are invalid
290
356
  def assert_arguments_type_with_keywords(expected_args, args, expected_kwargs, kwargs)
291
357
  e_len = expected_args.length
292
358
  # `length.times` is faster than `each_with_index`
@@ -307,14 +373,62 @@ public
307
373
  end
308
374
  end
309
375
  end
376
+ nil
310
377
  end
311
378
  end
312
379
 
380
+ # Validates result
381
+ #
382
+ # @param expected A type behavior
383
+ # @param result
384
+ # @return [void]
385
+ #
386
+ # @raise [TypeSignatureError] If expected is invalid
387
+ # @raise [ReturnTypeError] If result is invalid
313
388
  unless respond_to?(:assert_return_type)
314
389
  def assert_return_type(expected, result)
315
390
  unless valid?(expected, result)
316
391
  raise ReturnTypeError, "for return:\n" + type_error_message(expected, result)
317
392
  end
393
+ nil
318
394
  end
319
395
  end
396
+
397
+ private
398
+ # @param owner
399
+ # @param [Symbol] method_name
400
+ # @param expected_args
401
+ # @param expected_kwargs
402
+ # @param return_sig
403
+ # @return [void]
404
+ def define_typed_method_to_proxy(owner, method_name, expected_args, expected_kwargs, return_sig)
405
+ # `send` is faster than `method(...).call`
406
+ owner.send(:_rtype_proxy).send :define_method, method_name do |*args, **kwargs, &block|
407
+ if kwargs.empty?
408
+ ::Rtype::assert_arguments_type(expected_args, args)
409
+ result = super(*args, &block)
410
+ else
411
+ ::Rtype::assert_arguments_type_with_keywords(expected_args, args, expected_kwargs, kwargs)
412
+ result = super(*args, **kwargs, &block)
413
+ end
414
+ ::Rtype::assert_return_type(return_sig, result)
415
+ result
416
+ end
417
+ nil
418
+ end
419
+
420
+ # @param [Integer] num
421
+ # @return [String]
422
+ def ordinalize_number(num)
423
+ if (11..13).include?(num % 100)
424
+ "#{num}th"
425
+ else
426
+ case num % 10
427
+ when 1; "#{num}st"
428
+ when 2; "#{num}nd"
429
+ when 3; "#{num}rd"
430
+ else "#{num}th"
431
+ end
432
+ end
433
+ end
320
434
  end
@@ -8,4 +8,5 @@ require_relative 'behavior/and'
8
8
  require_relative 'behavior/xor'
9
9
  require_relative 'behavior/not'
10
10
  require_relative 'behavior/nilable'
11
+ require_relative 'behavior/typed_array'
11
12
  require_relative 'behavior/core_ext'
@@ -16,3 +16,13 @@ class Object
16
16
  ::Rtype::xor(self, *others)
17
17
  end
18
18
  end
19
+
20
+ class Array
21
+ def self.of(type_sig)
22
+ ::Rtype::Behavior::TypedArray.new(type_sig)
23
+ end
24
+
25
+ def comb
26
+ ::Rtype::Behavior::And[*self]
27
+ end
28
+ end
@@ -0,0 +1,25 @@
1
+ module Rtype
2
+ module Behavior
3
+ class TypedArray < Base
4
+ def initialize(type)
5
+ @type = type
6
+ Rtype.assert_valid_argument_type_sig_element(@type)
7
+ end
8
+
9
+ def valid?(value)
10
+ if value.is_a?(Array)
11
+ any = value.any? do |e|
12
+ !Rtype::valid?(@type, e)
13
+ end
14
+ !any
15
+ else
16
+ false
17
+ end
18
+ end
19
+
20
+ def error_message(value)
21
+ "Expected #{value.inspect} to be an array with type #{@type.inspect}"
22
+ end
23
+ end
24
+ end
25
+ end
@@ -1,6 +1,8 @@
1
+ # true or false
1
2
  module Boolean; end
2
3
  class TrueClass; include Boolean; end
3
4
  class FalseClass; include Boolean; end
5
+
4
6
  Any = BasicObject
5
7
 
6
8
  class Object
@@ -17,74 +19,119 @@ private
17
19
  @_rtype_proxy
18
20
  end
19
21
 
22
+ # Makes the method typed
23
+ #
24
+ # With 'annotation mode', this method works for both instance method and singleton method (class method).
25
+ # Without it (specifying method name), this method only works for instance method.
26
+ #
27
+ # @param [#to_sym, nil] method_name The name of method. If nil, annotation mode works
28
+ # @param [Hash] type_sig_info A type signature. e.g. [Integer] => Any
29
+ # @return [void]
30
+ #
31
+ # @note Annotation mode doesn't work in the outside of module
32
+ # @raise [ArgumentError] If method_name is nil in the outside of module
33
+ # @raise [TypeSignatureError] If type_sig_info is invalid
20
34
  def rtype(method_name=nil, type_sig_info)
21
35
  if is_a?(Module)
22
36
  if method_name.nil?
23
37
  ::Rtype::assert_valid_type_sig(type_sig_info)
24
38
  _rtype_proxy.annotation_mode = true
25
39
  _rtype_proxy.annotation_type_sig = type_sig_info
40
+ nil
26
41
  else
27
42
  ::Rtype::define_typed_method(self, method_name, type_sig_info)
28
43
  end
29
44
  else
30
45
  if method_name.nil?
31
- raise ArgumentError, "Annotation mode not working out of module"
46
+ raise ArgumentError, "Annotation mode doesn't work in the outside of module"
32
47
  else
33
48
  rtype_self(method_name, type_sig_info)
34
49
  end
35
50
  end
36
51
  end
37
52
 
53
+ # Makes the singleton method (class method) typed
54
+ #
55
+ # @param [#to_sym] method_name
56
+ # @param [Hash] type_sig_info A type signature. e.g. [Integer] => Any
57
+ # @return [void]
58
+ #
59
+ # @raise [ArgumentError] If method_name is nil
60
+ # @raise [TypeSignatureError] If type_sig_info is invalid
38
61
  def rtype_self(method_name, type_sig_info)
39
62
  ::Rtype.define_typed_method(singleton_class, method_name, type_sig_info)
40
63
  end
64
+
65
+ # Makes the accessor methods (getter and setter) typed
66
+ #
67
+ # @param [Array<#to_sym>] accessor_names
68
+ # @param type_behavior A type behavior
69
+ # @return [void]
70
+ #
71
+ # @raise [ArgumentError] If accessor_names contains nil
72
+ # @raise [TypeSignatureError] If type_behavior is invalid
73
+ # @see #rtype
74
+ def rtype_accessor(*accessor_names, type_behavior)
75
+ accessor_names.each do |accessor_name|
76
+ accessor_name = accessor_name.to_sym
77
+ if !respond_to?(accessor_name) || !respond_to?(:"#{accessor_name}=")
78
+ attr_accessor accessor_name
79
+ end
41
80
 
42
- def rtype_accessor(accessor_name, type_behavior)
43
- accessor_name = accessor_name.to_sym
44
- if !respond_to?(accessor_name) || !respond_to?(:"#{accessor_name}=")
45
- attr_accessor accessor_name
46
- end
47
-
48
- if is_a?(Module)
49
- ::Rtype::define_typed_accessor(self, accessor_name, type_behavior)
50
- else
51
- rtype_accessor_self(accessor_name, type_behavior)
81
+ if is_a?(Module)
82
+ ::Rtype::define_typed_accessor(self, accessor_name, type_behavior)
83
+ else
84
+ rtype_accessor_self(accessor_name, type_behavior)
85
+ end
52
86
  end
87
+ nil
53
88
  end
54
-
55
- def rtype_accessor_self(accessor_name, type_behavior)
56
- accessor_name = accessor_name.to_sym
57
- if !respond_to?(accessor_name) || !respond_to?(:"#{accessor_name}=")
58
- singleton_class.send(:attr_accessor, accessor_name)
89
+
90
+ # Makes the accessor methods (getter and setter) typed
91
+ #
92
+ # @param [Array<#to_sym>] accessor_names
93
+ # @param type_behavior A type behavior
94
+ # @return [void]
95
+ #
96
+ # @raise [ArgumentError] If accessor_names contains nil
97
+ # @raise [TypeSignatureError] If type_behavior is invalid
98
+ # @see #rtype_self
99
+ def rtype_accessor_self(*accessor_names, type_behavior)
100
+ accessor_names.each do |accessor_name|
101
+ accessor_name = accessor_name.to_sym
102
+ if !respond_to?(accessor_name) || !respond_to?(:"#{accessor_name}=")
103
+ singleton_class.send(:attr_accessor, accessor_name)
104
+ end
105
+ ::Rtype::define_typed_accessor(singleton_class, accessor_name, type_behavior)
59
106
  end
60
- ::Rtype::define_typed_accessor(singleton_class, accessor_name, type_behavior)
107
+ nil
61
108
  end
62
109
  end
63
110
 
64
111
  class Method
112
+ # @return [Boolean] Whether the method is typed with rtype
65
113
  def typed?
66
114
  !!::Rtype.type_signatures[owner][name]
67
115
  end
68
116
 
117
+ # @return [TypeSignature]
69
118
  def type_signature
70
119
  ::Rtype.type_signatures[owner][name]
71
120
  end
72
121
 
122
+ # @return [Hash]
123
+ # @see TypeSignature#info
73
124
  def type_info
74
125
  ::Rtype.type_signatures[owner][name].info
75
126
  end
76
-
127
+
128
+ # @return [Array, Hash]
77
129
  def argument_type
78
130
  ::Rtype.type_signatures[owner][name].argument_type
79
131
  end
80
132
 
133
+ # @return A type behavior
81
134
  def return_type
82
135
  ::Rtype.type_signatures[owner][name].return_type
83
136
  end
84
137
  end
85
-
86
- class Array
87
- def comb
88
- ::Rtype::Behavior::And[*self]
89
- end
90
- end
@@ -1,9 +1,10 @@
1
1
  module Rtype
2
2
  class TypeSignature
3
3
  attr_accessor :argument_type, :return_type
4
-
4
+
5
+ # @return [Hash] A type signature
5
6
  def info
6
7
  {argument_type => return_type}
7
8
  end
8
9
  end
9
- end
10
+ end
@@ -1,5 +1,5 @@
1
1
  module Rtype
2
- VERSION = "0.6.0".freeze
2
+ VERSION = "0.6.3".freeze
3
3
  # rtype java extension version. nil If the extension is not used
4
4
  JAVA_EXT_VERSION = nil unless defined?(JAVA_EXT_VERSION)
5
5
  # rtype c extension version. nil If the extension is not used
@@ -150,24 +150,30 @@ describe Rtype do
150
150
 
151
151
  it 'Kernel#rtype_accessor' do
152
152
  class TestClass
153
- rtype_accessor :value, String
153
+ rtype_accessor :value, :value2, String
154
154
 
155
155
  def initialize
156
156
  @value = 123
157
+ @value2 = 123
157
158
  end
158
159
  end
159
160
  expect {TestClass.new.value = 123}.to raise_error Rtype::ArgumentTypeError
160
161
  expect {TestClass.new.value}.to raise_error Rtype::ReturnTypeError
162
+ expect {TestClass.new.value2 = 123}.to raise_error Rtype::ArgumentTypeError
163
+ expect {TestClass.new.value2}.to raise_error Rtype::ReturnTypeError
161
164
  end
162
165
 
163
166
  it 'Kernel#rtype_accessor_self' do
164
167
  class TestClass
165
- @@val = 123
168
+ @@value = 123
169
+ @@value2 = 123
166
170
 
167
- rtype_accessor_self :value, String
171
+ rtype_accessor_self :value, :value2, String
168
172
  end
169
173
  expect {TestClass::value = 123}.to raise_error Rtype::ArgumentTypeError
170
174
  expect {TestClass::value}.to raise_error Rtype::ReturnTypeError
175
+ expect {TestClass::value2 = 123}.to raise_error Rtype::ArgumentTypeError
176
+ expect {TestClass::value2}.to raise_error Rtype::ReturnTypeError
171
177
  end
172
178
 
173
179
  describe 'Test type behaviors' do
@@ -440,6 +446,34 @@ describe Rtype do
440
446
  expect {instance.return_nil("abc")}.to raise_error Rtype::ArgumentTypeError
441
447
  end
442
448
  end
449
+
450
+ describe 'Rtype::Behavior::TypedArray' do
451
+ it 'class singleton [] method' do
452
+ klass.send :rtype, :return_nil, [ Rtype::Behavior::TypedArray[Integer] ] => nil
453
+ instance.return_nil([123])
454
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
455
+ expect {instance.return_nil([1.0])}.to raise_error Rtype::ArgumentTypeError
456
+ end
457
+
458
+ it 'core extension method (Array::of)' do
459
+ klass.send :rtype, :return_nil, [ Array.of(Integer) ] => nil
460
+ instance.return_nil([123])
461
+ expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
462
+ expect {instance.return_nil([1.0])}.to raise_error Rtype::ArgumentTypeError
463
+ end
464
+
465
+ it 'complicated type sig' do
466
+ klass.send :rtype, :return_nil, [ Array.of(:to_i.and(:chars)) ] => nil
467
+ instance.return_nil(["hello"])
468
+ expect {instance.return_nil("hello")}.to raise_error Rtype::ArgumentTypeError
469
+ expect {instance.return_nil([123])}.to raise_error Rtype::ArgumentTypeError
470
+ end
471
+
472
+ it 'allows empty array' do
473
+ klass.send :rtype, :return_nil, [ Array.of(Integer) ] => nil
474
+ instance.return_nil([])
475
+ end
476
+ end
443
477
  end
444
478
  end
445
479
 
@@ -2,4 +2,12 @@ require 'coveralls'
2
2
  Coveralls.wear!
3
3
 
4
4
  require 'rtype'
5
- require 'rspec'
5
+ require 'rspec'
6
+
7
+ if !Rtype::NATIVE_EXT_VERSION.nil?
8
+ puts "Rtype with native extension"
9
+ elsif !Rtype::JAVA_EXT_VERSION.nil?
10
+ puts "Rtype with java extension"
11
+ else
12
+ puts "Rtype without native extension"
13
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rtype
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.6.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sputnik Gugja
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-05 00:00:00.000000000 Z
11
+ date: 2016-07-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -72,6 +72,7 @@ files:
72
72
  - lib/rtype/behavior/core_ext.rb
73
73
  - lib/rtype/behavior/nilable.rb
74
74
  - lib/rtype/behavior/not.rb
75
+ - lib/rtype/behavior/typed_array.rb
75
76
  - lib/rtype/behavior/xor.rb
76
77
  - lib/rtype/core_ext.rb
77
78
  - lib/rtype/method_annotator.rb