rtype-legacy 0.0.2 → 0.0.4
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 +50 -24
- data/Rakefile +1 -1
- 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 +149 -20
- data/lib/rtype/legacy.rb +32 -13
- data/lib/rtype/legacy/version.rb +1 -1
- data/spec/rtype_legacy_spec.rb +146 -0
- 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: 1cfd6d899191a80db171d581dcf6c4cf324e0fe3
|
4
|
+
data.tar.gz: 4fec96dfa193388fef8478984625d5cc30d02f9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 602834cd3859a45248ead08fdda5ea34dd7a633c764319fdb8c5e6ce8427c438226293784ca2dc5de335514bfd22f01ee170d4a6c18d2a4bf75dae30d7e7ba42
|
7
|
+
data.tar.gz: 5891fbb28f6a11bc849d9487fe034f4581125ba14c383cf85b6b530495ca7d30d1ef354cb2520e7e9d9cea696af307c5c3a4ba66d66fcb65fdf170c422b61664
|
data/README.md
CHANGED
@@ -12,7 +12,9 @@ class Test
|
|
12
12
|
a.to_i + b
|
13
13
|
end
|
14
14
|
|
15
|
-
|
15
|
+
# Second hash is keyword argument signature
|
16
|
+
# (syntax compatibility with 'rtype' gem)
|
17
|
+
rtype [{state: Boolean}, {}] => Boolean
|
16
18
|
def self.invert(opts)
|
17
19
|
!opts[:state]
|
18
20
|
end
|
@@ -22,7 +24,7 @@ Test.new.sum(123, "asd")
|
|
22
24
|
# (Rtype::ArgumentTypeError) for 2nd argument:
|
23
25
|
# Expected "asd" to be a Numeric
|
24
26
|
|
25
|
-
Test
|
27
|
+
Test.invert(state: 0)
|
26
28
|
# (Rtype::ArgumentTypeError) for 1st argument:
|
27
29
|
# Expected {:state=>0} to be a hash with 1 elements:
|
28
30
|
# - state : Expected 0 to be a Boolean
|
@@ -47,8 +49,10 @@ Test::invert(state: 0)
|
|
47
49
|
- Provides type checking for arguments and return
|
48
50
|
- [Type checking for hash elements](#hash)
|
49
51
|
- [Duck Typing](#duck-typing)
|
50
|
-
- [Typed Array](#typed-array)
|
52
|
+
- [Typed Array](#typed-array), Typed Set, Typed Hash
|
51
53
|
- [Numeric check](#special-behaviors). e.g. `Int >= 0`
|
54
|
+
- [Type checking for getter and setter](#attr_accessor-with-rtype)
|
55
|
+
- [float_accessor](#float_accessor), [bool_accessor](#bool_accessor)
|
52
56
|
- Custom type behavior
|
53
57
|
- ...
|
54
58
|
|
@@ -74,16 +78,8 @@ gem 'rtype-legacy-native'
|
|
74
78
|
```
|
75
79
|
then, Rtype Legacy uses it. (**Do not** `require 'rtype-legacy-native'`)
|
76
80
|
|
77
|
-
#### Java extension for JRuby
|
78
|
-
|
79
|
-
```ruby
|
80
|
-
gem install rtype-legacy-java
|
81
|
-
```
|
82
|
-
or add to your `Gemfile`:
|
83
|
-
```ruby
|
84
|
-
gem 'rtype-legacy-java'
|
85
|
-
```
|
86
|
-
then, Rtype Legacy uses it. (**Do not** `require 'rtype-legacy-java'`)
|
81
|
+
#### Java extension for JRuby is automatic
|
82
|
+
**Do not** `require 'rtype-java'`
|
87
83
|
|
88
84
|
## Usage
|
89
85
|
|
@@ -113,7 +109,7 @@ then, Rtype Legacy uses it. (**Do not** `require 'rtype-legacy-java'`)
|
|
113
109
|
- Example: [Hash](#hash)
|
114
110
|
|
115
111
|
- [Special Behaviors](#special-behaviors)
|
116
|
-
- `TypedArray`, `Num, Int, Flo`, `And`, `Xor`, `Not`, `Nilable`
|
112
|
+
- `TypedArray, TypedSet, TypedHash`, `Num, Int, Flo`, `And`, `Xor`, `Not`, `Nilable`
|
117
113
|
|
118
114
|
### Examples
|
119
115
|
|
@@ -209,10 +205,12 @@ func({"msg" => "hello hash"})
|
|
209
205
|
func({msg: "hello hash"}) # hello hash
|
210
206
|
```
|
211
207
|
|
212
|
-
####
|
213
|
-
`rtype_accessor` : calls `attr_accessor` if the accessor
|
208
|
+
#### attr_accessor with rtype
|
209
|
+
- `rtype_accessor(*names, type)` : calls `attr_accessor` if the accessor methods(getter/setter) are not defined. and makes it typed
|
210
|
+
- `rtype_reader(*names, type)` : calls `attr_reader` if the getters are not defined. and makes it typed
|
211
|
+
- `rtype_writer(*names, type)` : calls `attr_writer` if the setters are not defined. and makes it typed
|
214
212
|
|
215
|
-
You can use `rtype_accessor_self` for static accessor.
|
213
|
+
You can use `rtype_accessor_self` for static accessor. (`rtype_reader_self`, `rtype_writer_self` also exist)
|
216
214
|
|
217
215
|
```ruby
|
218
216
|
require 'rtype'
|
@@ -266,6 +264,29 @@ sum([1, 2, 3]) # => 6
|
|
266
264
|
sum([1.0, 2, 3]) # => 6.0
|
267
265
|
```
|
268
266
|
|
267
|
+
#### float_accessor
|
268
|
+
```ruby
|
269
|
+
class Point
|
270
|
+
float_accessor :x, :y
|
271
|
+
end
|
272
|
+
|
273
|
+
v = Point.new
|
274
|
+
v.x = 1
|
275
|
+
v.x # => 1.0 (always Float)
|
276
|
+
```
|
277
|
+
|
278
|
+
#### bool_accessor
|
279
|
+
```ruby
|
280
|
+
class Human
|
281
|
+
bool_accessor :hungry
|
282
|
+
end
|
283
|
+
|
284
|
+
a = Human.new
|
285
|
+
a.hungry = true
|
286
|
+
a.hungry? # => true
|
287
|
+
a.hungry # NoMethodError
|
288
|
+
```
|
289
|
+
|
269
290
|
#### `rtype`
|
270
291
|
```ruby
|
271
292
|
require 'rtype'
|
@@ -358,9 +379,14 @@ Example.new.method(:test).return_type
|
|
358
379
|
|
359
380
|
#### Special Behaviors
|
360
381
|
- `TypedArray` : Ensures value is an array with the type (type signature)
|
361
|
-
- `Array
|
362
|
-
- or `Rtype::Behavior::TypedArray[type]`
|
382
|
+
- `Array.of(type)` (recommended)
|
363
383
|
- Example: [TypedArray](#typed-array)
|
384
|
+
|
385
|
+
- `TypedSet` : Ensures value is a set with the type (type signature)
|
386
|
+
- `Set.of(type)` (recommended)
|
387
|
+
|
388
|
+
- `TypedHash` : Ensures value is a hash with the type (type signature)
|
389
|
+
- `Hash.of(key_type, value_type)` (recommended)
|
364
390
|
|
365
391
|
- `Num, Int, Flo` : Numeric check
|
366
392
|
- `Num/Int/Flo >/>=/</<=/== x`
|
@@ -369,19 +395,19 @@ Example.new.method(:test).return_type
|
|
369
395
|
- e.g. `Flo >= 2` means value must be a `Float` and >= 2
|
370
396
|
|
371
397
|
- `And` : Ensures value is valid for all given types
|
372
|
-
- `Rtype
|
398
|
+
- `Rtype.and(*types)`, `Rtype::Behavior::And[*types]`
|
373
399
|
- or `Array#comb`, `Object#and(*others)`
|
374
400
|
|
375
401
|
- `Xor` : Ensures value is valid for only one of given types
|
376
|
-
- `Rtype
|
402
|
+
- `Rtype.xor(*types)`, `Rtype::Behavior::Xor[*types]`
|
377
403
|
- or `Object#xor(*others)`
|
378
404
|
|
379
405
|
- `Not` : Ensures value is not valid for all given types
|
380
|
-
- `Rtype
|
406
|
+
- `Rtype.not(*types)`, `Rtype::Behavior::Not[*types]`
|
381
407
|
- or `Object#not`
|
382
408
|
|
383
409
|
- `Nilable` : Value can be nil
|
384
|
-
- `Rtype
|
410
|
+
- `Rtype.nilable(type)`, `Rtype::Behavior::Nilable[type]`
|
385
411
|
- or `Object#nilable`, `Object#or_nil`
|
386
412
|
|
387
413
|
- You can create custom behaviors by extending `Rtype::Behavior::Base`
|
@@ -392,7 +418,7 @@ Example.new.method(:test).return_type
|
|
392
418
|
## Benchmarks
|
393
419
|
Result of `rake benchmark` ([source](https://github.com/sputnikgugja/rtype-legacy/tree/master/benchmark/benchmark.rb))
|
394
420
|
|
395
|
-
Rubype and Sig don't support 1.9 ruby. Typecheck
|
421
|
+
Rubype and Sig don't support 1.9 ruby. Typecheck raises an error in my environment
|
396
422
|
|
397
423
|
### MRI
|
398
424
|
```
|
data/Rakefile
CHANGED
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
@@ -59,50 +59,179 @@ private
|
|
59
59
|
|
60
60
|
# Makes the accessor methods (getter and setter) typed
|
61
61
|
#
|
62
|
-
# @param [Array<#to_sym>]
|
62
|
+
# @param [Array<#to_sym>] names
|
63
63
|
# @param type_behavior A type behavior
|
64
64
|
# @return [void]
|
65
65
|
#
|
66
|
-
# @raise [ArgumentError] If
|
66
|
+
# @raise [ArgumentError] If names contains nil
|
67
67
|
# @raise [TypeSignatureError] If type_behavior is invalid
|
68
68
|
# @raise [RuntimeError] If called outside of module
|
69
69
|
# @see #rtype
|
70
|
-
def rtype_accessor(*
|
71
|
-
|
72
|
-
|
70
|
+
def rtype_accessor(*names, type_behavior)
|
71
|
+
rtype_reader(*names, type_behavior)
|
72
|
+
rtype_writer(*names, type_behavior)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Makes the accessor methods (getter and setter) typed
|
76
|
+
#
|
77
|
+
# @param [Array<#to_sym>] names
|
78
|
+
# @param type_behavior A type behavior
|
79
|
+
# @return [void]
|
80
|
+
#
|
81
|
+
# @raise [ArgumentError] If names contains nil
|
82
|
+
# @raise [TypeSignatureError] If type_behavior is invalid
|
83
|
+
# @see #rtype_self
|
84
|
+
def rtype_accessor_self(*names, type_behavior)
|
85
|
+
rtype_reader_self(*names, type_behavior)
|
86
|
+
rtype_writer_self(*names, type_behavior)
|
87
|
+
end
|
88
|
+
|
89
|
+
# Makes the getter methods typed
|
90
|
+
#
|
91
|
+
# @param [Array<#to_sym>] names
|
92
|
+
# @param type_behavior A type behavior
|
93
|
+
# @return [void]
|
94
|
+
#
|
95
|
+
# @raise [ArgumentError] If names contains nil
|
96
|
+
# @raise [TypeSignatureError] If type_behavior is invalid
|
97
|
+
# @raise [RuntimeError] If called outside of module
|
98
|
+
# @see #rtype
|
99
|
+
def rtype_reader(*names, type_behavior)
|
100
|
+
names.each do |name|
|
101
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
73
102
|
|
74
|
-
|
75
|
-
if !respond_to?(
|
76
|
-
|
103
|
+
name = name.to_sym
|
104
|
+
if !respond_to?(name)
|
105
|
+
attr_reader name
|
77
106
|
end
|
78
107
|
|
79
108
|
if is_a?(Module)
|
80
|
-
::Rtype::
|
109
|
+
::Rtype::define_typed_reader(self, name, type_behavior, false)
|
81
110
|
else
|
82
|
-
raise "
|
111
|
+
raise "rtype_reader doesn't work in the outside of module"
|
83
112
|
end
|
84
113
|
end
|
85
114
|
nil
|
86
115
|
end
|
87
116
|
|
88
|
-
# Makes the
|
117
|
+
# Makes the getter methods typed
|
89
118
|
#
|
90
|
-
# @param [Array<#to_sym>]
|
119
|
+
# @param [Array<#to_sym>] names
|
91
120
|
# @param type_behavior A type behavior
|
92
121
|
# @return [void]
|
93
122
|
#
|
94
|
-
# @raise [ArgumentError] If
|
123
|
+
# @raise [ArgumentError] If names contains nil
|
95
124
|
# @raise [TypeSignatureError] If type_behavior is invalid
|
96
125
|
# @see #rtype_self
|
97
|
-
def
|
98
|
-
|
99
|
-
raise ArgumentError, "
|
126
|
+
def rtype_reader_self(*names, type_behavior)
|
127
|
+
names.each do |name|
|
128
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
129
|
+
|
130
|
+
name = name.to_sym
|
131
|
+
if !respond_to?(name)
|
132
|
+
singleton_class.send(:attr_reader, name)
|
133
|
+
end
|
134
|
+
::Rtype::define_typed_reader(self, name, type_behavior, true)
|
135
|
+
end
|
136
|
+
nil
|
137
|
+
end
|
138
|
+
|
139
|
+
# Makes the setter methods typed
|
140
|
+
#
|
141
|
+
# @param [Array<#to_sym>] names
|
142
|
+
# @param type_behavior A type behavior
|
143
|
+
# @return [void]
|
144
|
+
#
|
145
|
+
# @raise [ArgumentError] If names contains nil
|
146
|
+
# @raise [TypeSignatureError] If type_behavior is invalid
|
147
|
+
# @raise [RuntimeError] If called outside of module
|
148
|
+
# @see #rtype
|
149
|
+
def rtype_writer(*names, type_behavior)
|
150
|
+
names.each do |name|
|
151
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
152
|
+
|
153
|
+
name = name.to_sym
|
154
|
+
if !respond_to?(:"#{name}=")
|
155
|
+
attr_writer name
|
156
|
+
end
|
157
|
+
|
158
|
+
if is_a?(Module)
|
159
|
+
::Rtype::define_typed_writer(self, name, type_behavior, false)
|
160
|
+
else
|
161
|
+
raise "rtype_writer doesn't work in the outside of module"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
nil
|
165
|
+
end
|
166
|
+
|
167
|
+
# Makes the setter methods typed
|
168
|
+
#
|
169
|
+
# @param [Array<#to_sym>] names
|
170
|
+
# @param type_behavior A type behavior
|
171
|
+
# @return [void]
|
172
|
+
#
|
173
|
+
# @raise [ArgumentError] If names contains nil
|
174
|
+
# @raise [TypeSignatureError] If type_behavior is invalid
|
175
|
+
# @see #rtype_self
|
176
|
+
def rtype_writer_self(*names, type_behavior)
|
177
|
+
names.each do |name|
|
178
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
179
|
+
|
180
|
+
name = name.to_sym
|
181
|
+
if !respond_to?(:"#{name}=")
|
182
|
+
singleton_class.send(:attr_writer, name)
|
183
|
+
end
|
184
|
+
::Rtype::define_typed_writer(self, name, type_behavior, true)
|
185
|
+
end
|
186
|
+
nil
|
187
|
+
end
|
188
|
+
|
189
|
+
# Creates getter, setter methods.
|
190
|
+
# The getter method is typed with Float
|
191
|
+
# and the setter method is typed with Numeric.
|
192
|
+
#
|
193
|
+
# If the setter is called with a numeric given,
|
194
|
+
# the setter convert the numeric to a float, and store it.
|
195
|
+
#
|
196
|
+
# As a result, setter can accept a Numeric(Integer/Float), and getter always returns a Float
|
197
|
+
#
|
198
|
+
# @param [Array<#to_sym>] names
|
199
|
+
# @return [void]
|
200
|
+
#
|
201
|
+
# @raise [ArgumentError] If names contains nil
|
202
|
+
def float_accessor(*names)
|
203
|
+
names.each do |name|
|
204
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
205
|
+
|
206
|
+
name = name.to_sym
|
207
|
+
rtype_reader name, Float
|
208
|
+
define_method(:"#{name}=") do |val|
|
209
|
+
instance_variable_set(:"@#{name}", val.to_f)
|
210
|
+
end
|
211
|
+
::Rtype::define_typed_writer(self, name, Numeric, false)
|
212
|
+
end
|
213
|
+
nil
|
214
|
+
end
|
215
|
+
|
216
|
+
# Creates getter, setter methods. And makes it typed with Boolean.
|
217
|
+
# The name of the getter ends with `?`.
|
218
|
+
#
|
219
|
+
# e.g. `bool_accessor :closed` will create `closed=` and `closed?` methods
|
220
|
+
#
|
221
|
+
# @param [Array<#to_sym>] names
|
222
|
+
# @return [void]
|
223
|
+
#
|
224
|
+
# @raise [ArgumentError] If names contains nil
|
225
|
+
def bool_accessor(*names)
|
226
|
+
names.each do |name|
|
227
|
+
raise ArgumentError, "names contains nil" if name.nil?
|
100
228
|
|
101
|
-
|
102
|
-
|
103
|
-
|
229
|
+
name = name.to_sym
|
230
|
+
rtype_writer name, Boolean
|
231
|
+
define_method(:"#{name}?") do
|
232
|
+
instance_variable_get(:"@#{name}")
|
104
233
|
end
|
105
|
-
::Rtype::
|
234
|
+
::Rtype::define_typed_reader(self, :"#{name}?", Boolean, false)
|
106
235
|
end
|
107
236
|
nil
|
108
237
|
end
|
data/lib/rtype/legacy.rb
CHANGED
@@ -77,27 +77,46 @@ module Rtype
|
|
77
77
|
|
78
78
|
redefine_method_to_typed(owner, method_name, expected_args, return_sig, singleton)
|
79
79
|
end
|
80
|
-
|
81
|
-
#
|
82
|
-
#
|
80
|
+
|
81
|
+
# @param owner Owner of the accessor
|
82
|
+
# @param [#to_sym] name
|
83
|
+
# @param type_behavior A type behavior. e.g. Integer
|
84
|
+
# @param [Boolean] singleton Whether the method is singleton method
|
85
|
+
# @return [void]
|
83
86
|
#
|
84
|
-
#
|
87
|
+
# @raise [ArgumentError] If name is nil
|
88
|
+
# @raise [TypeSignatureError]
|
89
|
+
def define_typed_accessor(owner, name, type_behavior, singleton)
|
90
|
+
define_typed_reader(owner, name, type_behavior, singleton)
|
91
|
+
define_typed_writer(owner, name, type_behavior, singleton)
|
92
|
+
end
|
93
|
+
|
94
|
+
# @param owner Owner of the getter
|
95
|
+
# @param [#to_sym] name
|
96
|
+
# @param type_behavior A type behavior. e.g. Integer
|
97
|
+
# @param [Boolean] singleton Whether the method is singleton method
|
98
|
+
# @return [void]
|
85
99
|
#
|
86
|
-
# @
|
87
|
-
# @
|
100
|
+
# @raise [ArgumentError] If name is nil
|
101
|
+
# @raise [TypeSignatureError]
|
102
|
+
def define_typed_reader(owner, name, type_behavior, singleton)
|
103
|
+
raise ArgumentError, "name is nil" if name.nil?
|
104
|
+
valid?(type_behavior, nil)
|
105
|
+
define_typed_method owner, name.to_sym, {[] => type_behavior}, singleton
|
106
|
+
end
|
107
|
+
|
108
|
+
# @param owner Owner of the setter
|
109
|
+
# @param [#to_sym] name
|
88
110
|
# @param type_behavior A type behavior. e.g. Integer
|
89
111
|
# @param [Boolean] singleton Whether the method is singleton method
|
90
112
|
# @return [void]
|
91
113
|
#
|
92
|
-
# @raise [ArgumentError] If
|
114
|
+
# @raise [ArgumentError] If name is nil
|
93
115
|
# @raise [TypeSignatureError]
|
94
|
-
def
|
95
|
-
raise ArgumentError, "
|
96
|
-
getter = accessor_name.to_sym
|
97
|
-
setter = :"#{accessor_name}="
|
116
|
+
def define_typed_writer(owner, name, type_behavior, singleton)
|
117
|
+
raise ArgumentError, "name is nil" if name.nil?
|
98
118
|
valid?(type_behavior, nil)
|
99
|
-
define_typed_method owner,
|
100
|
-
define_typed_method owner, setter, {[type_behavior] => Any}, singleton
|
119
|
+
define_typed_method owner, :"#{name.to_sym}=", {[type_behavior] => Any}, singleton
|
101
120
|
end
|
102
121
|
|
103
122
|
# This is just 'information'
|
data/lib/rtype/legacy/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Rtype
|
2
2
|
module Legacy
|
3
|
-
VERSION = "0.0.
|
3
|
+
VERSION = "0.0.4".freeze
|
4
4
|
# rtype java extension version. nil If the extension is not used
|
5
5
|
JAVA_EXT_VERSION = nil unless const_defined?(:JAVA_EXT_VERSION, false)
|
6
6
|
# rtype c extension version. nil If the extension is not used
|
data/spec/rtype_legacy_spec.rb
CHANGED
@@ -152,6 +152,93 @@ describe Rtype::Legacy do
|
|
152
152
|
expect {TestClass::value2}.to raise_error Rtype::ReturnTypeError
|
153
153
|
end
|
154
154
|
|
155
|
+
it 'Kernel#rtype_reader' do
|
156
|
+
class ReaderTestClass
|
157
|
+
rtype_reader :value, :value2, String
|
158
|
+
|
159
|
+
def initialize
|
160
|
+
@value = 123
|
161
|
+
@value2 = 123
|
162
|
+
end
|
163
|
+
end
|
164
|
+
expect {ReaderTestClass.new.value}.to raise_error Rtype::ReturnTypeError
|
165
|
+
expect {ReaderTestClass.new.value2}.to raise_error Rtype::ReturnTypeError
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'Kernel#rtype_reader_self' do
|
169
|
+
class ReaderTestClass
|
170
|
+
@@value = 123
|
171
|
+
@@value2 = 123
|
172
|
+
rtype_reader_self :value, :value2, String
|
173
|
+
end
|
174
|
+
expect {ReaderTestClass::value}.to raise_error Rtype::ReturnTypeError
|
175
|
+
expect {ReaderTestClass::value2}.to raise_error Rtype::ReturnTypeError
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'Kernel#rtype_writer' do
|
179
|
+
class WriterTestClass
|
180
|
+
rtype_writer :value, :value2, String
|
181
|
+
|
182
|
+
def initialize
|
183
|
+
@value = 123
|
184
|
+
@value2 = 123
|
185
|
+
end
|
186
|
+
end
|
187
|
+
expect {WriterTestClass.new.value = 123}.to raise_error Rtype::ArgumentTypeError
|
188
|
+
expect {WriterTestClass.new.value2 = 123}.to raise_error Rtype::ArgumentTypeError
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'Kernel#rtype_writer_self' do
|
192
|
+
class WriterTestClass
|
193
|
+
@@value = 123
|
194
|
+
@@value2 = 123
|
195
|
+
rtype_writer_self :value, :value2, String
|
196
|
+
end
|
197
|
+
expect {WriterTestClass::value = 123}.to raise_error Rtype::ArgumentTypeError
|
198
|
+
expect {WriterTestClass::value2 = 123}.to raise_error Rtype::ArgumentTypeError
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'Kernel#float_accessor' do
|
202
|
+
class FloatAccessorTestClass
|
203
|
+
float_accessor :float, :int
|
204
|
+
|
205
|
+
def initialize
|
206
|
+
@float = 10.0
|
207
|
+
@int = 10
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
float_accessor_test = FloatAccessorTestClass.new
|
212
|
+
|
213
|
+
float_accessor_test.float
|
214
|
+
expect {float_accessor_test.int}.to raise_error Rtype::ReturnTypeError
|
215
|
+
float_accessor_test.float = 5.0
|
216
|
+
float_accessor_test.float = 5
|
217
|
+
expect(float_accessor_test.float).to eql(5.0) # be(expected) => passes if actual.eql?(expected)
|
218
|
+
expect(float_accessor_test.float).not_to eql(5)
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'Kernel#bool_accessor' do
|
222
|
+
class BoolAccessorTestClass
|
223
|
+
bool_accessor :state, :invalid_var
|
224
|
+
|
225
|
+
def initialize
|
226
|
+
@state = false
|
227
|
+
@invalid_var = 123
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
bool_accessor_test = BoolAccessorTestClass.new
|
232
|
+
|
233
|
+
bool_accessor_test.state?
|
234
|
+
expect {bool_accessor_test.state}.to raise_error NoMethodError
|
235
|
+
expect(bool_accessor_test.state?).to eql(false)
|
236
|
+
bool_accessor_test.state = true
|
237
|
+
expect(bool_accessor_test.state?).to eql(true)
|
238
|
+
expect {bool_accessor_test.state = 123}.to raise_error Rtype::ArgumentTypeError
|
239
|
+
expect {bool_accessor_test.invalid_var?}.to raise_error Rtype::ReturnTypeError
|
240
|
+
end
|
241
|
+
|
155
242
|
describe 'Test type behaviors' do
|
156
243
|
describe 'Module' do
|
157
244
|
it "is right" do
|
@@ -451,6 +538,65 @@ describe Rtype::Legacy do
|
|
451
538
|
end
|
452
539
|
end
|
453
540
|
|
541
|
+
describe 'Rtype::Behavior::TypedSet' do
|
542
|
+
it 'class singleton [] method' do
|
543
|
+
klass.send :rtype, :return_nil, [ Rtype::Behavior::TypedSet[Integer] ] => nil
|
544
|
+
instance.return_nil( Set.new([123]) )
|
545
|
+
expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
|
546
|
+
expect { instance.return_nil(Set.new([1.0])) }.to raise_error Rtype::ArgumentTypeError
|
547
|
+
end
|
548
|
+
|
549
|
+
it 'core extension method (Set::of)' do
|
550
|
+
klass.send :rtype, :return_nil, [ Set.of(Integer) ] => nil
|
551
|
+
instance.return_nil( Set.new([123]) )
|
552
|
+
expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
|
553
|
+
expect { instance.return_nil(Set.new([1.0])) }.to raise_error Rtype::ArgumentTypeError
|
554
|
+
end
|
555
|
+
|
556
|
+
it 'complicated type sig' do
|
557
|
+
klass.send :rtype, :return_nil, [ Set.of(:to_i.and(:chars)) ] => nil
|
558
|
+
instance.return_nil( Set.new(["hello"]) )
|
559
|
+
expect {instance.return_nil("hello")}.to raise_error Rtype::ArgumentTypeError
|
560
|
+
expect { instance.return_nil(Set.new([123])) }.to raise_error Rtype::ArgumentTypeError
|
561
|
+
end
|
562
|
+
|
563
|
+
it 'allows empty set' do
|
564
|
+
klass.send :rtype, :return_nil, [ Set.of(Integer) ] => nil
|
565
|
+
instance.return_nil(Set.new)
|
566
|
+
end
|
567
|
+
end
|
568
|
+
|
569
|
+
describe 'Rtype::Behavior::TypedHash' do
|
570
|
+
it 'class singleton [] method' do
|
571
|
+
klass.send :rtype, :return_nil, [ Rtype::Behavior::TypedHash[Symbol, Integer] ] => nil
|
572
|
+
instance.return_nil( {key: 123} )
|
573
|
+
expect {instance.return_nil(:key)}.to raise_error Rtype::ArgumentTypeError
|
574
|
+
expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
|
575
|
+
expect {instance.return_nil( {"key" => 123} )}.to raise_error Rtype::ArgumentTypeError
|
576
|
+
end
|
577
|
+
|
578
|
+
it 'core extension method (Hash::of)' do
|
579
|
+
klass.send :rtype, :return_nil, [ Hash.of(Symbol, Integer) ] => nil
|
580
|
+
instance.return_nil( {key: 123} )
|
581
|
+
expect {instance.return_nil(:key)}.to raise_error Rtype::ArgumentTypeError
|
582
|
+
expect {instance.return_nil(123)}.to raise_error Rtype::ArgumentTypeError
|
583
|
+
expect {instance.return_nil( {"key" => 123} )}.to raise_error Rtype::ArgumentTypeError
|
584
|
+
end
|
585
|
+
|
586
|
+
it 'complicated type sig' do
|
587
|
+
klass.send :rtype, :return_nil, [ Hash.of(:to_i.and(:chars), :to_i.and(:chars)) ] => nil
|
588
|
+
instance.return_nil( {"key" => "val"} )
|
589
|
+
expect {instance.return_nil("hello")}.to raise_error Rtype::ArgumentTypeError
|
590
|
+
expect {instance.return_nil( {key: "val"} )}.to raise_error Rtype::ArgumentTypeError
|
591
|
+
expect {instance.return_nil( {"key" => :val} )}.to raise_error Rtype::ArgumentTypeError
|
592
|
+
end
|
593
|
+
|
594
|
+
it 'allows empty hash' do
|
595
|
+
klass.send :rtype, :return_nil, [ Hash.of(Symbol, Integer) ] => nil
|
596
|
+
instance.return_nil({})
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
454
600
|
describe 'Numeric check' do
|
455
601
|
it 'Num (Numeric)' do
|
456
602
|
klass.send :rtype, :return_nil, [Num >= 0] => Any
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rtype-legacy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
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
|
@@ -68,9 +68,14 @@ files:
|
|
68
68
|
- lib/rtype/behavior/and.rb
|
69
69
|
- lib/rtype/behavior/base.rb
|
70
70
|
- lib/rtype/behavior/core_ext.rb
|
71
|
+
- lib/rtype/behavior/float_check.rb
|
72
|
+
- lib/rtype/behavior/integer_check.rb
|
71
73
|
- lib/rtype/behavior/nilable.rb
|
72
74
|
- lib/rtype/behavior/not.rb
|
75
|
+
- lib/rtype/behavior/numeric_check.rb
|
73
76
|
- lib/rtype/behavior/typed_array.rb
|
77
|
+
- lib/rtype/behavior/typed_hash.rb
|
78
|
+
- lib/rtype/behavior/typed_set.rb
|
74
79
|
- lib/rtype/behavior/xor.rb
|
75
80
|
- lib/rtype/core_ext.rb
|
76
81
|
- lib/rtype/legacy.rb
|