rtype 0.6.6 → 0.6.8
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 +4 -4
- data/README.md +62 -29
- data/Rakefile +1 -1
- data/lib/rtype.rb +30 -13
- data/lib/rtype/behavior.rb +5 -0
- data/lib/rtype/behavior/core_ext.rb +44 -30
- data/lib/rtype/behavior/float_check.rb +17 -0
- data/lib/rtype/behavior/integer_check.rb +17 -0
- data/lib/rtype/behavior/numeric_check.rb +42 -0
- data/lib/rtype/behavior/typed_array.rb +1 -0
- data/lib/rtype/behavior/typed_hash.rb +29 -0
- data/lib/rtype/behavior/typed_set.rb +26 -0
- data/lib/rtype/core_ext.rb +157 -20
- data/lib/rtype/version.rb +1 -1
- data/spec/rtype_spec.rb +190 -11
- data/spec/spec_helper.rb +1 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 76040d28b4eee5b56fe0d5c6ebf51d462cc0200b
|
4
|
+
data.tar.gz: 7f35c3429e6be7f79856fdc43d629deafa4d7187
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5503c276531313629463a523b3589e91d6baf024f3c8bd22e126e4c57c9e0e9be5521c66435edcb6a209bc4f633c60be9a9b3f4705b2cbf57f9b123378823795
|
7
|
+
data.tar.gz: 1645c3bf900ddb43a6ade511583a5dab0c4bcadfb7884c7d5c8b46bf0e6a4b61f0391eea347771ed6acc2984099a916917f892ee9bf005d9c60b4476c1ab1d27
|
data/README.md
CHANGED
@@ -12,17 +12,27 @@ class Test
|
|
12
12
|
a.to_i + b
|
13
13
|
end
|
14
14
|
|
15
|
-
rtype {state: Boolean} => Boolean
|
15
|
+
rtype [{state: Boolean}] => Boolean
|
16
16
|
def self.invert(state:)
|
17
17
|
!state
|
18
18
|
end
|
19
|
+
|
20
|
+
# Hashes of hashes params require () to prevent invalid syntax
|
21
|
+
rtype({state: Boolean} => Boolean)
|
22
|
+
def self.invert2(state:)
|
23
|
+
!state
|
24
|
+
end
|
19
25
|
end
|
20
26
|
|
21
27
|
Test.new.sum(123, "asd")
|
22
28
|
# (Rtype::ArgumentTypeError) for 2nd argument:
|
23
29
|
# Expected "asd" to be a Numeric
|
24
30
|
|
25
|
-
Test
|
31
|
+
Test.invert(state: 0)
|
32
|
+
# (Rtype::ArgumentTypeError) for 'state' argument:
|
33
|
+
# Expected 0 to be a Boolean
|
34
|
+
|
35
|
+
Test.invert2(state: 0)
|
26
36
|
# (Rtype::ArgumentTypeError) for 'state' argument:
|
27
37
|
# Expected 0 to be a Boolean
|
28
38
|
```
|
@@ -40,8 +50,10 @@ Test::invert(state: 0)
|
|
40
50
|
- Provides type checking for [Keyword Argument](#keyword-argument)
|
41
51
|
- [Type checking for hash elements](#hash)
|
42
52
|
- [Duck Typing](#duck-typing)
|
43
|
-
- [Typed Array](#typed-array)
|
53
|
+
- [Typed Array](#typed-array), Typed Set, Typed Hash
|
44
54
|
- [Numeric check](#special-behaviors). e.g. `Int >= 0`
|
55
|
+
- [Type checking for getter and setter](#attr_accessor-with-rtype)
|
56
|
+
- [float_accessor](#float_accessor), [bool_accessor](#bool_accessor)
|
45
57
|
- Custom type behavior
|
46
58
|
- ...
|
47
59
|
|
@@ -67,16 +79,8 @@ gem 'rtype-native'
|
|
67
79
|
```
|
68
80
|
then, Rtype uses it. (**Do not** `require 'rtype-native'`)
|
69
81
|
|
70
|
-
#### Java extension for JRuby
|
71
|
-
|
72
|
-
```ruby
|
73
|
-
gem install rtype-java
|
74
|
-
```
|
75
|
-
or add to your `Gemfile`:
|
76
|
-
```ruby
|
77
|
-
gem 'rtype-java'
|
78
|
-
```
|
79
|
-
then, Rtype uses it. (**Do not** `require 'rtype-java'`)
|
82
|
+
#### Java extension for JRuby is automatic
|
83
|
+
**Do not** `require 'rtype-java'`
|
80
84
|
|
81
85
|
## Usage
|
82
86
|
|
@@ -106,7 +110,7 @@ then, Rtype uses it. (**Do not** `require 'rtype-java'`)
|
|
106
110
|
- Example: [Hash](#hash)
|
107
111
|
|
108
112
|
- [Special Behaviors](#special-behaviors)
|
109
|
-
- `TypedArray`, `Num, Int, Flo`, `And`, `Xor`, `Not`, `Nilable`
|
113
|
+
- `TypedArray, TypedSet, TypedHash`, `Num, Int, Flo`, `And`, `Xor`, `Not`, `Nilable`
|
110
114
|
|
111
115
|
### Examples
|
112
116
|
|
@@ -204,34 +208,35 @@ def func(hash)
|
|
204
208
|
puts hash[:msg]
|
205
209
|
end
|
206
210
|
|
207
|
-
|
208
|
-
func({}, {})
|
211
|
+
func({})
|
209
212
|
# (Rtype::ArgumentTypeError) for 1st argument:
|
210
213
|
# Expected {} to be a hash with 1 elements:
|
211
214
|
# - msg : Expected nil to be a String
|
212
215
|
|
213
|
-
func({msg: 123}
|
216
|
+
func({msg: 123})
|
214
217
|
# (Rtype::ArgumentTypeError) for 1st argument:
|
215
218
|
# Expected {:msg=>123} to be a hash with 1 elements:
|
216
219
|
# - msg : Expected 123 to be a String
|
217
220
|
|
218
|
-
func({msg: "hello", key: 'value'}
|
221
|
+
func({msg: "hello", key: 'value'})
|
219
222
|
# (Rtype::ArgumentTypeError) for 1st argument:
|
220
223
|
# Expected {:msg=>"hello", :key=>"value"} to be a hash with 1 elements:
|
221
224
|
# - msg : Expected "hello" to be a String
|
222
225
|
|
223
|
-
func({"msg" => "hello hash"}
|
226
|
+
func({"msg" => "hello hash"})
|
224
227
|
# (Rtype::ArgumentTypeError) for 1st argument:
|
225
228
|
# Expected {"msg"=>"hello hash"} to be a hash with 1 elements:
|
226
229
|
# - msg : Expected nil to be a String
|
227
230
|
|
228
|
-
func({msg: "hello hash"}
|
231
|
+
func({msg: "hello hash"}) # hello hash
|
229
232
|
```
|
230
233
|
|
231
|
-
####
|
232
|
-
`rtype_accessor` : calls `attr_accessor` if the accessor
|
234
|
+
#### attr_accessor with rtype
|
235
|
+
- `rtype_accessor(*names, type)` : calls `attr_accessor` if the accessor methods(getter/setter) are not defined. and makes it typed
|
236
|
+
- `rtype_reader(*names, type)` : calls `attr_reader` if the getters are not defined. and makes it typed
|
237
|
+
- `rtype_writer(*names, type)` : calls `attr_writer` if the setters are not defined. and makes it typed
|
233
238
|
|
234
|
-
You can use `rtype_accessor_self` for static accessor.
|
239
|
+
You can use `rtype_accessor_self` for static accessor. (`rtype_reader_self`, `rtype_writer_self` also exist)
|
235
240
|
|
236
241
|
```ruby
|
237
242
|
require 'rtype'
|
@@ -285,6 +290,29 @@ sum([1, 2, 3]) # => 6
|
|
285
290
|
sum([1.0, 2, 3]) # => 6.0
|
286
291
|
```
|
287
292
|
|
293
|
+
#### float_accessor
|
294
|
+
```ruby
|
295
|
+
class Point
|
296
|
+
float_accessor :x, :y
|
297
|
+
end
|
298
|
+
|
299
|
+
v = Point.new
|
300
|
+
v.x = 1
|
301
|
+
v.x # => 1.0 (always Float)
|
302
|
+
```
|
303
|
+
|
304
|
+
#### bool_accessor
|
305
|
+
```ruby
|
306
|
+
class Human
|
307
|
+
bool_accessor :hungry
|
308
|
+
end
|
309
|
+
|
310
|
+
a = Human.new
|
311
|
+
a.hungry = true
|
312
|
+
a.hungry? # => true
|
313
|
+
a.hungry # NoMethodError
|
314
|
+
```
|
315
|
+
|
288
316
|
#### `rtype`
|
289
317
|
```ruby
|
290
318
|
require 'rtype'
|
@@ -392,9 +420,14 @@ Example.new.method(:test).return_type
|
|
392
420
|
|
393
421
|
#### Special Behaviors
|
394
422
|
- `TypedArray` : Ensures value is an array with the type (type signature)
|
395
|
-
- `Array
|
396
|
-
- or `Rtype::Behavior::TypedArray[type]`
|
423
|
+
- `Array.of(type)` (recommended)
|
397
424
|
- Example: [TypedArray](#typed-array)
|
425
|
+
|
426
|
+
- `TypedSet` : Ensures value is a set with the type (type signature)
|
427
|
+
- `Set.of(type)` (recommended)
|
428
|
+
|
429
|
+
- `TypedHash` : Ensures value is a hash with the type (type signature)
|
430
|
+
- `Hash.of(key_type, value_type)` (recommended)
|
398
431
|
|
399
432
|
- `Num, Int, Flo` : Numeric check
|
400
433
|
- `Num/Int/Flo >/>=/</<=/== x`
|
@@ -403,19 +436,19 @@ Example.new.method(:test).return_type
|
|
403
436
|
- e.g. `Flo >= 2` means value must be a `Float` and >= 2
|
404
437
|
|
405
438
|
- `And` : Ensures value is valid for all given types
|
406
|
-
- `Rtype
|
439
|
+
- `Rtype.and(*types)`, `Rtype::Behavior::And[*types]`
|
407
440
|
- or `Array#comb`, `Object#and(*others)`
|
408
441
|
|
409
442
|
- `Xor` : Ensures value is valid for only one of given types
|
410
|
-
- `Rtype
|
443
|
+
- `Rtype.xor(*types)`, `Rtype::Behavior::Xor[*types]`
|
411
444
|
- or `Object#xor(*others)`
|
412
445
|
|
413
446
|
- `Not` : Ensures value is not valid for all given types
|
414
|
-
- `Rtype
|
447
|
+
- `Rtype.not(*types)`, `Rtype::Behavior::Not[*types]`
|
415
448
|
- or `Object#not`
|
416
449
|
|
417
450
|
- `Nilable` : Value can be nil
|
418
|
-
- `Rtype
|
451
|
+
- `Rtype.nilable(type)`, `Rtype::Behavior::Nilable[type]`
|
419
452
|
- or `Object#nilable`, `Object#or_nil`
|
420
453
|
|
421
454
|
- You can create custom behaviors by extending `Rtype::Behavior::Base`
|
data/Rakefile
CHANGED
data/lib/rtype.rb
CHANGED
@@ -74,26 +74,43 @@ module Rtype
|
|
74
74
|
|
75
75
|
define_typed_method_to_proxy(owner, method_name, expected_args, expected_kwargs, return_sig)
|
76
76
|
end
|
77
|
-
|
78
|
-
#
|
79
|
-
#
|
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]
|
80
82
|
#
|
81
|
-
#
|
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]
|
82
94
|
#
|
83
|
-
# @
|
84
|
-
# @
|
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
|
85
105
|
# @param type_behavior A type behavior. e.g. Integer
|
86
106
|
# @return [void]
|
87
107
|
#
|
88
|
-
# @raise [ArgumentError] If
|
108
|
+
# @raise [ArgumentError] If name is nil
|
89
109
|
# @raise [TypeSignatureError]
|
90
|
-
def
|
91
|
-
raise ArgumentError, "
|
92
|
-
getter = accessor_name.to_sym
|
93
|
-
setter = :"#{accessor_name}="
|
110
|
+
def define_typed_writer(owner, name, type_behavior)
|
111
|
+
raise ArgumentError, "name is nil" if name.nil?
|
94
112
|
valid?(type_behavior, nil)
|
95
|
-
define_typed_method owner,
|
96
|
-
define_typed_method owner, setter, [type_behavior] => Any
|
113
|
+
define_typed_method owner, :"#{name.to_sym}=", [type_behavior] => Any
|
97
114
|
end
|
98
115
|
|
99
116
|
# This is just 'information'
|
data/lib/rtype/behavior.rb
CHANGED
@@ -9,4 +9,9 @@ require_relative 'behavior/xor'
|
|
9
9
|
require_relative 'behavior/not'
|
10
10
|
require_relative 'behavior/nilable'
|
11
11
|
require_relative 'behavior/typed_array'
|
12
|
+
require_relative 'behavior/typed_set'
|
13
|
+
require_relative 'behavior/typed_hash'
|
14
|
+
require_relative 'behavior/numeric_check'
|
15
|
+
require_relative 'behavior/integer_check'
|
16
|
+
require_relative 'behavior/float_check'
|
12
17
|
require_relative 'behavior/core_ext'
|
@@ -33,128 +33,142 @@ class Array
|
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
|
+
class Set
|
37
|
+
# @return [Rtype::Behavior::TypedSet]
|
38
|
+
def self.of(type_sig)
|
39
|
+
::Rtype::Behavior::TypedSet.new(type_sig)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class Hash
|
44
|
+
# @return [Rtype::Behavior::TypedHash]
|
45
|
+
def self.of(key_type, value_type)
|
46
|
+
::Rtype::Behavior::TypedHash.new(key_type, value_type)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
36
50
|
class Num
|
37
51
|
# @param [Numeric] x
|
38
|
-
# @return [
|
52
|
+
# @return [Rtype::Behavior::NumericCheck]
|
39
53
|
# @example Value must be a Numeric and > 2
|
40
54
|
# rtype [Num > 2] => Any
|
41
55
|
def self.>(x)
|
42
|
-
|
56
|
+
::Rtype::Behavior::NumericCheck.new(:>, x)
|
43
57
|
end
|
44
58
|
|
45
59
|
# @param [Numeric] x
|
46
|
-
# @return [
|
60
|
+
# @return [Rtype::Behavior::NumericCheck]
|
47
61
|
# @example Value must be a Numeric and > 2
|
48
62
|
# rtype [Num > 2] => Any
|
49
63
|
def self.>=(x)
|
50
|
-
|
64
|
+
::Rtype::Behavior::NumericCheck.new(:>=, x)
|
51
65
|
end
|
52
66
|
|
53
67
|
# @param [Numeric] x
|
54
|
-
# @return [
|
68
|
+
# @return [Rtype::Behavior::NumericCheck]
|
55
69
|
# @example Value must be a Numeric and > 2
|
56
70
|
# rtype [Num > 2] => Any
|
57
71
|
def self.<(x)
|
58
|
-
|
72
|
+
::Rtype::Behavior::NumericCheck.new(:<, x)
|
59
73
|
end
|
60
74
|
|
61
75
|
# @param [Numeric] x
|
62
|
-
# @return [
|
76
|
+
# @return [Rtype::Behavior::NumericCheck]
|
63
77
|
# @example Value must be a Numeric and > 2
|
64
78
|
# rtype [Num > 2] => Any
|
65
79
|
def self.<=(x)
|
66
|
-
|
80
|
+
::Rtype::Behavior::NumericCheck.new(:<=, x)
|
67
81
|
end
|
68
82
|
|
69
83
|
# @param [Numeric] x
|
70
|
-
# @return [
|
84
|
+
# @return [Rtype::Behavior::NumericCheck]
|
71
85
|
# @example Value must be a Numeric and > 2
|
72
86
|
# rtype [Num > 2] => Any
|
73
87
|
def self.==(x)
|
74
|
-
|
88
|
+
::Rtype::Behavior::NumericCheck.new(:==, x)
|
75
89
|
end
|
76
90
|
end
|
77
91
|
|
78
92
|
class Int
|
79
93
|
# @param [Numeric] x
|
80
|
-
# @return [
|
94
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
81
95
|
# @example Value must be a Integer and > 2
|
82
96
|
# rtype [Int > 2] => Any
|
83
97
|
def self.>(x)
|
84
|
-
|
98
|
+
::Rtype::Behavior::IntegerCheck.new(:>, x)
|
85
99
|
end
|
86
100
|
|
87
101
|
# @param [Numeric] x
|
88
|
-
# @return [
|
102
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
89
103
|
# @example Value must be a Integer and > 2
|
90
104
|
# rtype [Int > 2] => Any
|
91
105
|
def self.>=(x)
|
92
|
-
|
106
|
+
::Rtype::Behavior::IntegerCheck.new(:>=, x)
|
93
107
|
end
|
94
108
|
|
95
109
|
# @param [Numeric] x
|
96
|
-
# @return [
|
110
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
97
111
|
# @example Value must be a Integer and > 2
|
98
112
|
# rtype [Int > 2] => Any
|
99
113
|
def self.<(x)
|
100
|
-
|
114
|
+
::Rtype::Behavior::IntegerCheck.new(:<, x)
|
101
115
|
end
|
102
116
|
|
103
117
|
# @param [Numeric] x
|
104
|
-
# @return [
|
118
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
105
119
|
# @example Value must be a Integer and > 2
|
106
120
|
# rtype [Int > 2] => Any
|
107
121
|
def self.<=(x)
|
108
|
-
|
122
|
+
::Rtype::Behavior::IntegerCheck.new(:<=, x)
|
109
123
|
end
|
110
124
|
|
111
125
|
# @param [Numeric] x
|
112
|
-
# @return [
|
126
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
113
127
|
# @example Value must be a Integer and > 2
|
114
128
|
# rtype [Int > 2] => Any
|
115
129
|
def self.==(x)
|
116
|
-
|
130
|
+
::Rtype::Behavior::IntegerCheck.new(:==, x)
|
117
131
|
end
|
118
132
|
end
|
119
133
|
|
120
134
|
class Flo
|
121
135
|
# @param [Numeric] x
|
122
|
-
# @return [
|
136
|
+
# @return [Rtype::Behavior::FloatCheck]
|
123
137
|
# @example Value must be a Float and > 2
|
124
138
|
# rtype [Flo > 2] => Any
|
125
139
|
def self.>(x)
|
126
|
-
|
140
|
+
::Rtype::Behavior::FloatCheck.new(:>, x)
|
127
141
|
end
|
128
142
|
|
129
143
|
# @param [Numeric] x
|
130
|
-
# @return [
|
144
|
+
# @return [Rtype::Behavior::FloatCheck]
|
131
145
|
# @example Value must be a Float and > 2
|
132
146
|
# rtype [Flo > 2] => Any
|
133
147
|
def self.>=(x)
|
134
|
-
|
148
|
+
::Rtype::Behavior::FloatCheck.new(:>=, x)
|
135
149
|
end
|
136
150
|
|
137
151
|
# @param [Numeric] x
|
138
|
-
# @return [
|
152
|
+
# @return [Rtype::Behavior::FloatCheck]
|
139
153
|
# @example Value must be a Float and > 2
|
140
154
|
# rtype [Flo > 2] => Any
|
141
155
|
def self.<(x)
|
142
|
-
|
156
|
+
::Rtype::Behavior::FloatCheck.new(:<, x)
|
143
157
|
end
|
144
158
|
|
145
159
|
# @param [Numeric] x
|
146
|
-
# @return [
|
160
|
+
# @return [Rtype::Behavior::FloatCheck]
|
147
161
|
# @example Value must be a Float and > 2
|
148
162
|
# rtype [Flo > 2] => Any
|
149
163
|
def self.<=(x)
|
150
|
-
|
164
|
+
::Rtype::Behavior::FloatCheck.new(:<=, x)
|
151
165
|
end
|
152
166
|
|
153
167
|
# @param [Numeric] x
|
154
|
-
# @return [
|
168
|
+
# @return [Rtype::Behavior::FloatCheck]
|
155
169
|
# @example Value must be a Float and > 2
|
156
170
|
# rtype [Flo > 2] => Any
|
157
171
|
def self.==(x)
|
158
|
-
|
172
|
+
::Rtype::Behavior::FloatCheck.new(:==, x)
|
159
173
|
end
|
160
174
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
class FloatCheck < NumericCheck
|
4
|
+
def valid?(value)
|
5
|
+
if value.is_a?(Float)
|
6
|
+
@lambda.call(value)
|
7
|
+
else
|
8
|
+
false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def error_message(value)
|
13
|
+
"Expected #{value.inspect} to be a float #{@condition} #{@x}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
class IntegerCheck < NumericCheck
|
4
|
+
def valid?(value)
|
5
|
+
if value.is_a?(Integer)
|
6
|
+
@lambda.call(value)
|
7
|
+
else
|
8
|
+
false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def error_message(value)
|
13
|
+
"Expected #{value.inspect} to be an integer #{@condition} #{@x}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
class NumericCheck < Base
|
4
|
+
@@conditions = [
|
5
|
+
:>, :<, :>=, :<=, :==
|
6
|
+
]
|
7
|
+
|
8
|
+
# @param [Symbol] condition
|
9
|
+
# @param [Numeric] x
|
10
|
+
def initialize(condition, x)
|
11
|
+
raise ArgumentError, "Invalid condition '#{condition}'" unless @@conditions.include?(condition)
|
12
|
+
raise ArgumentError, "x is not a Numeric" unless x.is_a?(Numeric)
|
13
|
+
@condition = condition
|
14
|
+
@x = x
|
15
|
+
@lambda = case condition
|
16
|
+
when :>
|
17
|
+
lambda { |obj| obj > @x }
|
18
|
+
when :<
|
19
|
+
lambda { |obj| obj < @x }
|
20
|
+
when :>=
|
21
|
+
lambda { |obj| obj >= @x }
|
22
|
+
when :<=
|
23
|
+
lambda { |obj| obj <= @x }
|
24
|
+
when :==
|
25
|
+
lambda { |obj| obj == @x }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def valid?(value)
|
30
|
+
if value.is_a?(Numeric)
|
31
|
+
@lambda.call(value)
|
32
|
+
else
|
33
|
+
false
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def error_message(value)
|
38
|
+
"Expected #{value.inspect} to be a numeric #{@condition} #{@x}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
# Typed hash behavior. empty hash allowed
|
4
|
+
class TypedHash < Base
|
5
|
+
def initialize(key_type, value_type)
|
6
|
+
@ktype = key_type
|
7
|
+
@vtype = value_type
|
8
|
+
Rtype.assert_valid_argument_type_sig_element(@ktype)
|
9
|
+
Rtype.assert_valid_argument_type_sig_element(@vtype)
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?(value)
|
13
|
+
if value.is_a?(Hash)
|
14
|
+
any = value.any? do |k, v|
|
15
|
+
!Rtype::valid?(@ktype, k) ||
|
16
|
+
!Rtype::valid?(@vtype, v)
|
17
|
+
end
|
18
|
+
!any
|
19
|
+
else
|
20
|
+
false
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def error_message(value)
|
25
|
+
"Expected #{value.inspect} to be a hash with key type #{@ktype.inspect} and value type #{@vtype.inspect}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
# Typed set behavior. empty set allowed
|
4
|
+
class TypedSet < Base
|
5
|
+
def initialize(type)
|
6
|
+
@type = type
|
7
|
+
Rtype.assert_valid_argument_type_sig_element(@type)
|
8
|
+
end
|
9
|
+
|
10
|
+
def valid?(value)
|
11
|
+
if value.is_a?(Set)
|
12
|
+
any = value.any? do |e|
|
13
|
+
!Rtype::valid?(@type, e)
|
14
|
+
end
|
15
|
+
!any
|
16
|
+
else
|
17
|
+
false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def error_message(value)
|
22
|
+
"Expected #{value.inspect} to be a set with type #{@type.inspect}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/rtype/core_ext.rb
CHANGED
@@ -22,7 +22,7 @@ private
|
|
22
22
|
# Makes the method typed
|
23
23
|
#
|
24
24
|
# With 'annotation mode', this method works for both instance method and singleton method (class method).
|
25
|
-
# Without it
|
25
|
+
# Without it, this method only works for instance method.
|
26
26
|
#
|
27
27
|
# @param [#to_sym, nil] method_name The name of method. If nil, annotation mode works
|
28
28
|
# @param [Hash] type_sig_info A type signature. e.g. [Integer] => Any
|
@@ -62,47 +62,184 @@ private
|
|
62
62
|
::Rtype.define_typed_method(singleton_class, method_name, type_sig_info)
|
63
63
|
end
|
64
64
|
|
65
|
-
#
|
65
|
+
# Calls `attr_accessor` if the accessor method(getter/setter) is not defined.
|
66
|
+
# and makes it typed.
|
66
67
|
#
|
67
|
-
# @param [Array<#to_sym>]
|
68
|
+
# @param [Array<#to_sym>] names
|
68
69
|
# @param type_behavior A type behavior
|
69
70
|
# @return [void]
|
70
71
|
#
|
71
|
-
# @raise [ArgumentError] If
|
72
|
+
# @raise [ArgumentError] If names contains nil
|
72
73
|
# @raise [TypeSignatureError] If type_behavior is invalid
|
73
74
|
# @see #rtype
|
74
|
-
def rtype_accessor(*
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
def rtype_accessor(*names, type_behavior)
|
76
|
+
rtype_reader(*names, type_behavior)
|
77
|
+
rtype_writer(*names, type_behavior)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Calls `attr_accessor` if the accessor method(getter/setter) is not defined.
|
81
|
+
# and makes it typed.
|
82
|
+
#
|
83
|
+
# @param [Array<#to_sym>] names
|
84
|
+
# @param type_behavior A type behavior
|
85
|
+
# @return [void]
|
86
|
+
#
|
87
|
+
# @raise [ArgumentError] If names contains nil
|
88
|
+
# @raise [TypeSignatureError] If type_behavior is invalid
|
89
|
+
# @see #rtype_self
|
90
|
+
def rtype_accessor_self(*names, type_behavior)
|
91
|
+
rtype_reader_self(*names, type_behavior)
|
92
|
+
rtype_writer_self(*names, type_behavior)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Calls `attr_reader` if the getter method is not defined.
|
96
|
+
# and makes it typed.
|
97
|
+
#
|
98
|
+
# @param [Array<#to_sym>] names
|
99
|
+
# @param type_behavior A type behavior
|
100
|
+
# @return [void]
|
101
|
+
#
|
102
|
+
# @raise [ArgumentError] If names contains nil
|
103
|
+
# @raise [TypeSignatureError] If type_behavior is invalid
|
104
|
+
# @see #rtype
|
105
|
+
def rtype_reader(*names, type_behavior)
|
106
|
+
names.each do |name|
|
107
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
108
|
+
|
109
|
+
name = name.to_sym
|
110
|
+
if !respond_to?(name)
|
111
|
+
attr_reader name
|
79
112
|
end
|
80
113
|
|
81
114
|
if is_a?(Module)
|
82
|
-
::Rtype::
|
115
|
+
::Rtype::define_typed_reader(self, name, type_behavior)
|
83
116
|
else
|
84
|
-
|
117
|
+
rtype_reader_self(name, type_behavior)
|
85
118
|
end
|
86
119
|
end
|
87
120
|
nil
|
88
121
|
end
|
89
122
|
|
90
|
-
#
|
123
|
+
# Calls `attr_reader` if the getter method is not defined.
|
124
|
+
# and makes it typed.
|
91
125
|
#
|
92
|
-
# @param [Array<#to_sym>]
|
126
|
+
# @param [Array<#to_sym>] names
|
93
127
|
# @param type_behavior A type behavior
|
94
128
|
# @return [void]
|
95
129
|
#
|
96
|
-
# @raise [ArgumentError] If
|
130
|
+
# @raise [ArgumentError] If names contains nil
|
97
131
|
# @raise [TypeSignatureError] If type_behavior is invalid
|
98
132
|
# @see #rtype_self
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
133
|
+
def rtype_reader_self(*names, type_behavior)
|
134
|
+
names.each do |name|
|
135
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
136
|
+
|
137
|
+
name = name.to_sym
|
138
|
+
if !respond_to?(name)
|
139
|
+
singleton_class.send(:attr_reader, name)
|
140
|
+
end
|
141
|
+
::Rtype::define_typed_reader(singleton_class, name, type_behavior)
|
142
|
+
end
|
143
|
+
nil
|
144
|
+
end
|
145
|
+
|
146
|
+
# Calls `attr_writer` if the setter method is not defined.
|
147
|
+
# and makes it typed.
|
148
|
+
#
|
149
|
+
# @param [Array<#to_sym>] names
|
150
|
+
# @param type_behavior A type behavior
|
151
|
+
# @return [void]
|
152
|
+
#
|
153
|
+
# @raise [ArgumentError] If names contains nil
|
154
|
+
# @raise [TypeSignatureError] If type_behavior is invalid
|
155
|
+
# @see #rtype
|
156
|
+
def rtype_writer(*names, type_behavior)
|
157
|
+
names.each do |name|
|
158
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
159
|
+
|
160
|
+
name = name.to_sym
|
161
|
+
if !respond_to?(:"#{name}=")
|
162
|
+
attr_writer name
|
163
|
+
end
|
164
|
+
|
165
|
+
if is_a?(Module)
|
166
|
+
::Rtype::define_typed_writer(self, name, type_behavior)
|
167
|
+
else
|
168
|
+
rtype_reader_self(name, type_behavior)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
nil
|
172
|
+
end
|
173
|
+
|
174
|
+
# Calls `attr_writer` if the setter method is not defined.
|
175
|
+
# and makes it typed.
|
176
|
+
#
|
177
|
+
# @param [Array<#to_sym>] names
|
178
|
+
# @param type_behavior A type behavior
|
179
|
+
# @return [void]
|
180
|
+
#
|
181
|
+
# @raise [ArgumentError] If names contains nil
|
182
|
+
# @raise [TypeSignatureError] If type_behavior is invalid
|
183
|
+
# @see #rtype_self
|
184
|
+
def rtype_writer_self(*names, type_behavior)
|
185
|
+
names.each do |name|
|
186
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
187
|
+
|
188
|
+
name = name.to_sym
|
189
|
+
if !respond_to?(:"#{name}=")
|
190
|
+
singleton_class.send(:attr_writer, name)
|
191
|
+
end
|
192
|
+
::Rtype::define_typed_writer(singleton_class, name, type_behavior)
|
193
|
+
end
|
194
|
+
nil
|
195
|
+
end
|
196
|
+
|
197
|
+
# Creates getter, setter methods.
|
198
|
+
# The getter method is typed with Float
|
199
|
+
# and the setter method is typed with Numeric.
|
200
|
+
#
|
201
|
+
# If the setter is called with a numeric given,
|
202
|
+
# the setter convert the numeric to a float, and store it.
|
203
|
+
#
|
204
|
+
# As a result, setter can accept a Numeric(Integer/Float), and getter always returns a Float
|
205
|
+
#
|
206
|
+
# @param [Array<#to_sym>] names
|
207
|
+
# @return [void]
|
208
|
+
#
|
209
|
+
# @raise [ArgumentError] If names contains nil
|
210
|
+
def float_accessor(*names)
|
211
|
+
names.each do |name|
|
212
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
213
|
+
|
214
|
+
name = name.to_sym
|
215
|
+
rtype_reader name, Float
|
216
|
+
define_method(:"#{name}=") do |val|
|
217
|
+
instance_variable_set(:"@#{name}", val.to_f)
|
218
|
+
end
|
219
|
+
::Rtype::define_typed_writer(self, name, Numeric)
|
220
|
+
end
|
221
|
+
nil
|
222
|
+
end
|
223
|
+
|
224
|
+
# Creates getter, setter methods. And makes it typed with Boolean.
|
225
|
+
# The name of the getter ends with `?`.
|
226
|
+
#
|
227
|
+
# e.g. `bool_accessor :closed` will create `closed=` and `closed?` methods
|
228
|
+
#
|
229
|
+
# @param [Array<#to_sym>] names
|
230
|
+
# @return [void]
|
231
|
+
#
|
232
|
+
# @raise [ArgumentError] If names contains nil
|
233
|
+
def bool_accessor(*names)
|
234
|
+
names.each do |name|
|
235
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
236
|
+
|
237
|
+
name = name.to_sym
|
238
|
+
rtype_writer name, Boolean
|
239
|
+
define_method(:"#{name}?") do
|
240
|
+
instance_variable_get(:"@#{name}")
|
104
241
|
end
|
105
|
-
::Rtype::
|
242
|
+
::Rtype::define_typed_reader(self, :"#{name}?", Boolean)
|
106
243
|
end
|
107
244
|
nil
|
108
245
|
end
|
data/lib/rtype/version.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
module Rtype
|
2
|
-
VERSION = "0.6.
|
2
|
+
VERSION = "0.6.8".freeze
|
3
3
|
# rtype java extension version. nil If the extension is not used
|
4
4
|
JAVA_EXT_VERSION = nil unless const_defined?(:JAVA_EXT_VERSION, false)
|
5
5
|
# rtype c extension version. nil If the extension is not used
|
data/spec/rtype_spec.rb
CHANGED
@@ -46,6 +46,10 @@ describe Rtype do
|
|
46
46
|
|
47
47
|
def args_and_kwargs(a, b, c:, d:)
|
48
48
|
end
|
49
|
+
|
50
|
+
public
|
51
|
+
def public_func
|
52
|
+
end
|
49
53
|
|
50
54
|
protected
|
51
55
|
def protected_func
|
@@ -149,7 +153,7 @@ describe Rtype do
|
|
149
153
|
end
|
150
154
|
|
151
155
|
it 'Kernel#rtype_accessor' do
|
152
|
-
class
|
156
|
+
class AccessorTestClass
|
153
157
|
rtype_accessor :value, :value2, String
|
154
158
|
|
155
159
|
def initialize
|
@@ -157,23 +161,109 @@ describe Rtype do
|
|
157
161
|
@value2 = 123
|
158
162
|
end
|
159
163
|
end
|
160
|
-
expect {
|
161
|
-
expect {
|
162
|
-
expect {
|
163
|
-
expect {
|
164
|
+
expect {AccessorTestClass.new.value = 123}.to raise_error Rtype::ArgumentTypeError
|
165
|
+
expect {AccessorTestClass.new.value}.to raise_error Rtype::ReturnTypeError
|
166
|
+
expect {AccessorTestClass.new.value2 = 123}.to raise_error Rtype::ArgumentTypeError
|
167
|
+
expect {AccessorTestClass.new.value2}.to raise_error Rtype::ReturnTypeError
|
164
168
|
end
|
165
169
|
|
166
170
|
it 'Kernel#rtype_accessor_self' do
|
167
|
-
class
|
171
|
+
class AccessorTestClass
|
168
172
|
@@value = 123
|
169
173
|
@@value2 = 123
|
170
|
-
|
171
174
|
rtype_accessor_self :value, :value2, String
|
172
175
|
end
|
173
|
-
expect {
|
174
|
-
expect {
|
175
|
-
expect {
|
176
|
-
expect {
|
176
|
+
expect {AccessorTestClass::value = 123}.to raise_error Rtype::ArgumentTypeError
|
177
|
+
expect {AccessorTestClass::value}.to raise_error Rtype::ReturnTypeError
|
178
|
+
expect {AccessorTestClass::value2 = 123}.to raise_error Rtype::ArgumentTypeError
|
179
|
+
expect {AccessorTestClass::value2}.to raise_error Rtype::ReturnTypeError
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'Kernel#rtype_reader' do
|
183
|
+
class ReaderTestClass
|
184
|
+
rtype_reader :value, :value2, String
|
185
|
+
|
186
|
+
def initialize
|
187
|
+
@value = 123
|
188
|
+
@value2 = 123
|
189
|
+
end
|
190
|
+
end
|
191
|
+
expect {ReaderTestClass.new.value}.to raise_error Rtype::ReturnTypeError
|
192
|
+
expect {ReaderTestClass.new.value2}.to raise_error Rtype::ReturnTypeError
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'Kernel#rtype_reader_self' do
|
196
|
+
class ReaderTestClass
|
197
|
+
@@value = 123
|
198
|
+
@@value2 = 123
|
199
|
+
rtype_reader_self :value, :value2, String
|
200
|
+
end
|
201
|
+
expect {ReaderTestClass::value}.to raise_error Rtype::ReturnTypeError
|
202
|
+
expect {ReaderTestClass::value2}.to raise_error Rtype::ReturnTypeError
|
203
|
+
end
|
204
|
+
|
205
|
+
it 'Kernel#rtype_writer' do
|
206
|
+
class WriterTestClass
|
207
|
+
rtype_writer :value, :value2, String
|
208
|
+
|
209
|
+
def initialize
|
210
|
+
@value = 123
|
211
|
+
@value2 = 123
|
212
|
+
end
|
213
|
+
end
|
214
|
+
expect {WriterTestClass.new.value = 123}.to raise_error Rtype::ArgumentTypeError
|
215
|
+
expect {WriterTestClass.new.value2 = 123}.to raise_error Rtype::ArgumentTypeError
|
216
|
+
end
|
217
|
+
|
218
|
+
it 'Kernel#rtype_writer_self' do
|
219
|
+
class WriterTestClass
|
220
|
+
@@value = 123
|
221
|
+
@@value2 = 123
|
222
|
+
rtype_writer_self :value, :value2, String
|
223
|
+
end
|
224
|
+
expect {WriterTestClass::value = 123}.to raise_error Rtype::ArgumentTypeError
|
225
|
+
expect {WriterTestClass::value2 = 123}.to raise_error Rtype::ArgumentTypeError
|
226
|
+
end
|
227
|
+
|
228
|
+
it 'Kernel#float_accessor' do
|
229
|
+
class FloatAccessorTestClass
|
230
|
+
float_accessor :float, :int
|
231
|
+
|
232
|
+
def initialize
|
233
|
+
@float = 10.0
|
234
|
+
@int = 10
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
float_accessor_test = FloatAccessorTestClass.new
|
239
|
+
|
240
|
+
float_accessor_test.float
|
241
|
+
expect {float_accessor_test.int}.to raise_error Rtype::ReturnTypeError
|
242
|
+
float_accessor_test.float = 5.0
|
243
|
+
float_accessor_test.float = 5
|
244
|
+
expect(float_accessor_test.float).to eql(5.0) # be(expected) => passes if actual.eql?(expected)
|
245
|
+
expect(float_accessor_test.float).not_to eql(5)
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'Kernel#bool_accessor' do
|
249
|
+
class BoolAccessorTestClass
|
250
|
+
bool_accessor :state, :invalid_var
|
251
|
+
|
252
|
+
def initialize
|
253
|
+
@state = false
|
254
|
+
@invalid_var = 123
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
bool_accessor_test = BoolAccessorTestClass.new
|
259
|
+
|
260
|
+
bool_accessor_test.state?
|
261
|
+
expect {bool_accessor_test.state}.to raise_error NoMethodError
|
262
|
+
expect(bool_accessor_test.state?).to eql(false)
|
263
|
+
bool_accessor_test.state = true
|
264
|
+
expect(bool_accessor_test.state?).to eql(true)
|
265
|
+
expect {bool_accessor_test.state = 123}.to raise_error Rtype::ArgumentTypeError
|
266
|
+
expect {bool_accessor_test.invalid_var?}.to raise_error Rtype::ReturnTypeError
|
177
267
|
end
|
178
268
|
|
179
269
|
describe 'Test type behaviors' do
|
@@ -475,6 +565,65 @@ describe Rtype do
|
|
475
565
|
end
|
476
566
|
end
|
477
567
|
|
568
|
+
describe 'Rtype::Behavior::TypedSet' do
|
569
|
+
it 'class singleton [] method' do
|
570
|
+
klass.send :rtype, :return_nil, [ Rtype::Behavior::TypedSet[Integer] ] => nil
|
571
|
+
instance.return_nil( Set.new([123]) )
|
572
|
+
expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
|
573
|
+
expect { instance.return_nil(Set.new([1.0])) }.to raise_error Rtype::ArgumentTypeError
|
574
|
+
end
|
575
|
+
|
576
|
+
it 'core extension method (Set::of)' do
|
577
|
+
klass.send :rtype, :return_nil, [ Set.of(Integer) ] => nil
|
578
|
+
instance.return_nil( Set.new([123]) )
|
579
|
+
expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
|
580
|
+
expect { instance.return_nil(Set.new([1.0])) }.to raise_error Rtype::ArgumentTypeError
|
581
|
+
end
|
582
|
+
|
583
|
+
it 'complicated type sig' do
|
584
|
+
klass.send :rtype, :return_nil, [ Set.of(:to_i.and(:chars)) ] => nil
|
585
|
+
instance.return_nil( Set.new(["hello"]) )
|
586
|
+
expect {instance.return_nil("hello")}.to raise_error Rtype::ArgumentTypeError
|
587
|
+
expect { instance.return_nil(Set.new([123])) }.to raise_error Rtype::ArgumentTypeError
|
588
|
+
end
|
589
|
+
|
590
|
+
it 'allows empty set' do
|
591
|
+
klass.send :rtype, :return_nil, [ Set.of(Integer) ] => nil
|
592
|
+
instance.return_nil(Set.new)
|
593
|
+
end
|
594
|
+
end
|
595
|
+
|
596
|
+
describe 'Rtype::Behavior::TypedHash' do
|
597
|
+
it 'class singleton [] method' do
|
598
|
+
klass.send :rtype, :return_nil, [ Rtype::Behavior::TypedHash[Symbol, Integer] ] => nil
|
599
|
+
instance.return_nil( {key: 123} )
|
600
|
+
expect {instance.return_nil(:key)}.to raise_error Rtype::ArgumentTypeError
|
601
|
+
expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
|
602
|
+
expect {instance.return_nil( {"key" => 123} )}.to raise_error Rtype::ArgumentTypeError
|
603
|
+
end
|
604
|
+
|
605
|
+
it 'core extension method (Hash::of)' do
|
606
|
+
klass.send :rtype, :return_nil, [ Hash.of(Symbol, Integer) ] => nil
|
607
|
+
instance.return_nil( {key: 123} )
|
608
|
+
expect {instance.return_nil(:key)}.to raise_error Rtype::ArgumentTypeError
|
609
|
+
expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
|
610
|
+
expect {instance.return_nil( {"key" => 123} )}.to raise_error Rtype::ArgumentTypeError
|
611
|
+
end
|
612
|
+
|
613
|
+
it 'complicated type sig' do
|
614
|
+
klass.send :rtype, :return_nil, [ Hash.of(:to_i.and(:chars), :to_i.and(:chars)) ] => nil
|
615
|
+
instance.return_nil( {"key" => "val"} )
|
616
|
+
expect {instance.return_nil("hello")}.to raise_error Rtype::ArgumentTypeError
|
617
|
+
expect {instance.return_nil( {key: "val"} )}.to raise_error Rtype::ArgumentTypeError
|
618
|
+
expect {instance.return_nil( {"key" => :val} )}.to raise_error Rtype::ArgumentTypeError
|
619
|
+
end
|
620
|
+
|
621
|
+
it 'allows empty hash' do
|
622
|
+
klass.send :rtype, :return_nil, [ Hash.of(Symbol, Integer) ] => nil
|
623
|
+
instance.return_nil({})
|
624
|
+
end
|
625
|
+
end
|
626
|
+
|
478
627
|
describe 'Numeric check' do
|
479
628
|
it 'Num (Numeric)' do
|
480
629
|
klass.send :rtype, :return_nil, [Num >= 0] => Any
|
@@ -751,6 +900,10 @@ describe Rtype do
|
|
751
900
|
klass.send :rtype, :private_func, [] => Any
|
752
901
|
expect {instance.private_func}.to raise_error NoMethodError
|
753
902
|
end
|
903
|
+
it 'public' do
|
904
|
+
klass.send :rtype, :public_func, [] => Any
|
905
|
+
instance.public_func
|
906
|
+
end
|
754
907
|
end
|
755
908
|
|
756
909
|
context 'with empty argument signature' do
|
@@ -816,6 +969,32 @@ describe Rtype do
|
|
816
969
|
AnnotationTest2.new.inst_one(123)
|
817
970
|
AnnotationTest2::static_two(123)
|
818
971
|
end
|
972
|
+
|
973
|
+
context 'when rtype signature duplicated' do
|
974
|
+
it 'the latest have priority' do
|
975
|
+
class PriorityTest1
|
976
|
+
rtype :test_priority, [String] => Any
|
977
|
+
def test_priority(arg)
|
978
|
+
end
|
979
|
+
rtype :test_priority, [Integer] => Any
|
980
|
+
end
|
981
|
+
|
982
|
+
PriorityTest1.new.test_priority(1)
|
983
|
+
expect { PriorityTest1.new.test_priority("str") }.to raise_error Rtype::ArgumentTypeError
|
984
|
+
end
|
985
|
+
|
986
|
+
it 'annotation mode have priority in contemporaneous signatures' do
|
987
|
+
class PriorityTest2
|
988
|
+
rtype :test_priority, [String] => Any
|
989
|
+
rtype [Integer] => Any
|
990
|
+
def test_priority(arg)
|
991
|
+
end
|
992
|
+
end
|
993
|
+
|
994
|
+
PriorityTest2.new.test_priority(1)
|
995
|
+
expect { PriorityTest2.new.test_priority("str") }.to raise_error Rtype::ArgumentTypeError
|
996
|
+
end
|
997
|
+
end
|
819
998
|
end
|
820
999
|
|
821
1000
|
describe "Call Rtype`s static method directly" do
|
data/spec/spec_helper.rb
CHANGED
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.
|
4
|
+
version: 0.6.8
|
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-08-
|
11
|
+
date: 2016-08-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -70,9 +70,14 @@ files:
|
|
70
70
|
- lib/rtype/behavior/and.rb
|
71
71
|
- lib/rtype/behavior/base.rb
|
72
72
|
- lib/rtype/behavior/core_ext.rb
|
73
|
+
- lib/rtype/behavior/float_check.rb
|
74
|
+
- lib/rtype/behavior/integer_check.rb
|
73
75
|
- lib/rtype/behavior/nilable.rb
|
74
76
|
- lib/rtype/behavior/not.rb
|
77
|
+
- lib/rtype/behavior/numeric_check.rb
|
75
78
|
- lib/rtype/behavior/typed_array.rb
|
79
|
+
- lib/rtype/behavior/typed_hash.rb
|
80
|
+
- lib/rtype/behavior/typed_set.rb
|
76
81
|
- lib/rtype/behavior/xor.rb
|
77
82
|
- lib/rtype/core_ext.rb
|
78
83
|
- lib/rtype/method_annotator.rb
|