rtype 0.6.0 → 0.6.3

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.
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