rtype 0.6.8-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/LICENSE +9 -0
- data/README.md +541 -0
- data/Rakefile +12 -0
- data/benchmark/benchmark.rb +200 -0
- data/lib/rtype/argument_type_error.rb +4 -0
- data/lib/rtype/behavior/and.rb +24 -0
- data/lib/rtype/behavior/base.rb +17 -0
- data/lib/rtype/behavior/core_ext.rb +174 -0
- data/lib/rtype/behavior/float_check.rb +17 -0
- data/lib/rtype/behavior/integer_check.rb +17 -0
- data/lib/rtype/behavior/nilable.rb +21 -0
- data/lib/rtype/behavior/not.rb +24 -0
- data/lib/rtype/behavior/numeric_check.rb +42 -0
- data/lib/rtype/behavior/typed_array.rb +26 -0
- data/lib/rtype/behavior/typed_hash.rb +29 -0
- data/lib/rtype/behavior/typed_set.rb +26 -0
- data/lib/rtype/behavior/xor.rb +25 -0
- data/lib/rtype/behavior.rb +17 -0
- data/lib/rtype/core_ext.rb +274 -0
- data/lib/rtype/method_annotator.rb +31 -0
- data/lib/rtype/return_type_error.rb +4 -0
- data/lib/rtype/rtype_proxy.rb +10 -0
- data/lib/rtype/type_signature.rb +10 -0
- data/lib/rtype/type_signature_error.rb +4 -0
- data/lib/rtype/version.rb +7 -0
- data/lib/rtype.rb +468 -0
- data/spec/rtype_spec.rb +1070 -0
- data/spec/spec_helper.rb +14 -0
- metadata +131 -0
@@ -0,0 +1,200 @@
|
|
1
|
+
require 'benchmark/ips'
|
2
|
+
|
3
|
+
is_mri = RUBY_ENGINE == 'ruby'
|
4
|
+
|
5
|
+
require "rtype"
|
6
|
+
require "rubype" if is_mri
|
7
|
+
require "sig"
|
8
|
+
require "contracts"
|
9
|
+
require "contracts/version"
|
10
|
+
require "typecheck"
|
11
|
+
|
12
|
+
puts "Ruby version: #{RUBY_VERSION}"
|
13
|
+
puts "Ruby engine: #{RUBY_ENGINE}"
|
14
|
+
puts "Ruby description: #{RUBY_DESCRIPTION}"
|
15
|
+
|
16
|
+
puts "Rtype version: #{Rtype::VERSION}"
|
17
|
+
puts "Rubype version: #{Rubype::VERSION}" if is_mri
|
18
|
+
puts "Sig version: #{Sig::VERSION}"
|
19
|
+
puts "Contracts version: #{Contracts::VERSION}"
|
20
|
+
puts "Typecheck version: #{Typecheck::VERSION}"
|
21
|
+
|
22
|
+
if !Rtype::NATIVE_EXT_VERSION.nil?
|
23
|
+
puts "Rtype with native extension"
|
24
|
+
elsif !Rtype::JAVA_EXT_VERSION.nil?
|
25
|
+
puts "Rtype with java extension"
|
26
|
+
else
|
27
|
+
puts "Rtype without native extension"
|
28
|
+
end
|
29
|
+
|
30
|
+
class PureTest
|
31
|
+
def sum(x, y)
|
32
|
+
x + y
|
33
|
+
end
|
34
|
+
|
35
|
+
def mul(x, y)
|
36
|
+
x * y
|
37
|
+
end
|
38
|
+
|
39
|
+
def args(a, b, c, d)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
pure_obj = PureTest.new
|
43
|
+
|
44
|
+
class RtypeTest
|
45
|
+
rtype [Numeric, Numeric] => Numeric
|
46
|
+
def sum(x, y)
|
47
|
+
x + y
|
48
|
+
end
|
49
|
+
|
50
|
+
rtype [:to_i, :to_i] => Numeric
|
51
|
+
def mul(x, y)
|
52
|
+
x * y
|
53
|
+
end
|
54
|
+
|
55
|
+
rtype [Integer, Numeric, String, :to_i] => Any
|
56
|
+
def args(a, b, c, d)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
rtype_obj = RtypeTest.new
|
60
|
+
|
61
|
+
if is_mri
|
62
|
+
class RubypeTest
|
63
|
+
def sum(x, y)
|
64
|
+
x + y
|
65
|
+
end
|
66
|
+
typesig :sum, [Numeric, Numeric] => Numeric
|
67
|
+
|
68
|
+
def mul(x, y)
|
69
|
+
x * y
|
70
|
+
end
|
71
|
+
typesig :mul, [:to_i, :to_i] => Numeric
|
72
|
+
|
73
|
+
def args(a, b, c, d)
|
74
|
+
end
|
75
|
+
typesig :args, [Integer, Numeric, String, :to_i] => Any
|
76
|
+
end
|
77
|
+
rubype_obj = RubypeTest.new
|
78
|
+
end
|
79
|
+
|
80
|
+
class SigTest
|
81
|
+
sig [Numeric, Numeric], Numeric,
|
82
|
+
def sum(x, y)
|
83
|
+
x + y
|
84
|
+
end
|
85
|
+
|
86
|
+
sig [:to_i, :to_i], Numeric,
|
87
|
+
def mul(x, y)
|
88
|
+
x * y
|
89
|
+
end
|
90
|
+
|
91
|
+
# nil means wildcard
|
92
|
+
sig [Integer, Numeric, String, :to_i], nil,
|
93
|
+
def args(a, b, c, d)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
sig_obj = SigTest.new
|
97
|
+
|
98
|
+
class ContractsTest
|
99
|
+
include Contracts
|
100
|
+
|
101
|
+
Contract Num, Num => Num
|
102
|
+
def sum(x, y)
|
103
|
+
x + y
|
104
|
+
end
|
105
|
+
|
106
|
+
Contract RespondTo[:to_i], RespondTo[:to_i] => Num
|
107
|
+
def mul(x, y)
|
108
|
+
x * y
|
109
|
+
end
|
110
|
+
|
111
|
+
Contract Int, Num, String, RespondTo[:to_i] => Any
|
112
|
+
def args(a, b, c, d)
|
113
|
+
end
|
114
|
+
end
|
115
|
+
contracts_obj = ContractsTest.new
|
116
|
+
|
117
|
+
class TypecheckTest
|
118
|
+
extend Typecheck
|
119
|
+
|
120
|
+
typecheck 'Numeric, Numeric -> Numeric',
|
121
|
+
def sum(x, y)
|
122
|
+
x + y
|
123
|
+
end
|
124
|
+
|
125
|
+
typecheck '#to_i, #to_i -> Numeric',
|
126
|
+
def mul(x, y)
|
127
|
+
x * y
|
128
|
+
end
|
129
|
+
|
130
|
+
typecheck 'Integer, Numeric, String, #to_i -> BasicObject',
|
131
|
+
def args(a, b, c, d)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
typecheck_obj = TypecheckTest.new
|
135
|
+
|
136
|
+
Benchmark.ips do |x|
|
137
|
+
x.report("pure") do |times|
|
138
|
+
i = 0
|
139
|
+
while i < times
|
140
|
+
pure_obj.sum(1, 2)
|
141
|
+
pure_obj.mul(1, 2)
|
142
|
+
pure_obj.args(1, 2, "c", 4)
|
143
|
+
i += 1
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
x.report("rtype") do |times|
|
148
|
+
i = 0
|
149
|
+
while i < times
|
150
|
+
rtype_obj.sum(1, 2)
|
151
|
+
rtype_obj.mul(1, 2)
|
152
|
+
rtype_obj.args(1, 2, "c", 4)
|
153
|
+
i += 1
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
if is_mri
|
158
|
+
x.report("rubype") do |times|
|
159
|
+
i = 0
|
160
|
+
while i < times
|
161
|
+
rubype_obj.sum(1, 2)
|
162
|
+
rubype_obj.mul(1, 2)
|
163
|
+
rubype_obj.args(1, 2, "c", 4)
|
164
|
+
i += 1
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
x.report("sig") do |times|
|
170
|
+
i = 0
|
171
|
+
while i < times
|
172
|
+
sig_obj.sum(1, 2)
|
173
|
+
sig_obj.mul(1, 2)
|
174
|
+
sig_obj.args(1, 2, "c", 4)
|
175
|
+
i += 1
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
x.report("contracts") do |times|
|
180
|
+
i = 0
|
181
|
+
while i < times
|
182
|
+
contracts_obj.sum(1, 2)
|
183
|
+
contracts_obj.mul(1, 2)
|
184
|
+
contracts_obj.args(1, 2, "c", 4)
|
185
|
+
i += 1
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
x.report("typecheck") do |times|
|
190
|
+
i = 0
|
191
|
+
while i < times
|
192
|
+
typecheck_obj.sum(1, 2)
|
193
|
+
typecheck_obj.mul(1, 2)
|
194
|
+
typecheck_obj.args(1, 2, "c", 4)
|
195
|
+
i += 1
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
x.compare!
|
200
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
class And < Base
|
4
|
+
def initialize(*types)
|
5
|
+
@types = types
|
6
|
+
end
|
7
|
+
|
8
|
+
def valid?(value)
|
9
|
+
@types.all? do |e|
|
10
|
+
Rtype::valid? e, value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def error_message(value)
|
15
|
+
arr = @types.map { |e| Rtype::type_error_message(e, value) }
|
16
|
+
arr.join "\nAND "
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.and(*args)
|
22
|
+
Behavior::And[*args]
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
class Base
|
4
|
+
def self.[](*vals)
|
5
|
+
new(*vals)
|
6
|
+
end
|
7
|
+
|
8
|
+
def valid?(value)
|
9
|
+
raise NotImplementedError, "Abstract method"
|
10
|
+
end
|
11
|
+
|
12
|
+
def error_message(value)
|
13
|
+
raise NotImplementedError, "Abstract method"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
class Object
|
2
|
+
# @return [Rtype::Behavior::And]
|
3
|
+
def and(*others)
|
4
|
+
::Rtype::and(self, *others)
|
5
|
+
end
|
6
|
+
|
7
|
+
# @return [Rtype::Behavior::Nilable]
|
8
|
+
def nilable
|
9
|
+
::Rtype::nilable(self)
|
10
|
+
end
|
11
|
+
alias_method :or_nil, :nilable
|
12
|
+
|
13
|
+
# @return [Rtype::Behavior::Not]
|
14
|
+
def not
|
15
|
+
::Rtype::not(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [Rtype::Behavior::Xor]
|
19
|
+
def xor(*others)
|
20
|
+
::Rtype::xor(self, *others)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Array
|
25
|
+
# @return [Rtype::Behavior::TypedArray]
|
26
|
+
def self.of(type_sig)
|
27
|
+
::Rtype::Behavior::TypedArray.new(type_sig)
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Rtype::Behavior::And]
|
31
|
+
def comb
|
32
|
+
::Rtype::Behavior::And[*self]
|
33
|
+
end
|
34
|
+
end
|
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
|
+
|
50
|
+
class Num
|
51
|
+
# @param [Numeric] x
|
52
|
+
# @return [Rtype::Behavior::NumericCheck]
|
53
|
+
# @example Value must be a Numeric and > 2
|
54
|
+
# rtype [Num > 2] => Any
|
55
|
+
def self.>(x)
|
56
|
+
::Rtype::Behavior::NumericCheck.new(:>, x)
|
57
|
+
end
|
58
|
+
|
59
|
+
# @param [Numeric] x
|
60
|
+
# @return [Rtype::Behavior::NumericCheck]
|
61
|
+
# @example Value must be a Numeric and > 2
|
62
|
+
# rtype [Num > 2] => Any
|
63
|
+
def self.>=(x)
|
64
|
+
::Rtype::Behavior::NumericCheck.new(:>=, x)
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param [Numeric] x
|
68
|
+
# @return [Rtype::Behavior::NumericCheck]
|
69
|
+
# @example Value must be a Numeric and > 2
|
70
|
+
# rtype [Num > 2] => Any
|
71
|
+
def self.<(x)
|
72
|
+
::Rtype::Behavior::NumericCheck.new(:<, x)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @param [Numeric] x
|
76
|
+
# @return [Rtype::Behavior::NumericCheck]
|
77
|
+
# @example Value must be a Numeric and > 2
|
78
|
+
# rtype [Num > 2] => Any
|
79
|
+
def self.<=(x)
|
80
|
+
::Rtype::Behavior::NumericCheck.new(:<=, x)
|
81
|
+
end
|
82
|
+
|
83
|
+
# @param [Numeric] x
|
84
|
+
# @return [Rtype::Behavior::NumericCheck]
|
85
|
+
# @example Value must be a Numeric and > 2
|
86
|
+
# rtype [Num > 2] => Any
|
87
|
+
def self.==(x)
|
88
|
+
::Rtype::Behavior::NumericCheck.new(:==, x)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class Int
|
93
|
+
# @param [Numeric] x
|
94
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
95
|
+
# @example Value must be a Integer and > 2
|
96
|
+
# rtype [Int > 2] => Any
|
97
|
+
def self.>(x)
|
98
|
+
::Rtype::Behavior::IntegerCheck.new(:>, x)
|
99
|
+
end
|
100
|
+
|
101
|
+
# @param [Numeric] x
|
102
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
103
|
+
# @example Value must be a Integer and > 2
|
104
|
+
# rtype [Int > 2] => Any
|
105
|
+
def self.>=(x)
|
106
|
+
::Rtype::Behavior::IntegerCheck.new(:>=, x)
|
107
|
+
end
|
108
|
+
|
109
|
+
# @param [Numeric] x
|
110
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
111
|
+
# @example Value must be a Integer and > 2
|
112
|
+
# rtype [Int > 2] => Any
|
113
|
+
def self.<(x)
|
114
|
+
::Rtype::Behavior::IntegerCheck.new(:<, x)
|
115
|
+
end
|
116
|
+
|
117
|
+
# @param [Numeric] x
|
118
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
119
|
+
# @example Value must be a Integer and > 2
|
120
|
+
# rtype [Int > 2] => Any
|
121
|
+
def self.<=(x)
|
122
|
+
::Rtype::Behavior::IntegerCheck.new(:<=, x)
|
123
|
+
end
|
124
|
+
|
125
|
+
# @param [Numeric] x
|
126
|
+
# @return [Rtype::Behavior::IntegerCheck]
|
127
|
+
# @example Value must be a Integer and > 2
|
128
|
+
# rtype [Int > 2] => Any
|
129
|
+
def self.==(x)
|
130
|
+
::Rtype::Behavior::IntegerCheck.new(:==, x)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
class Flo
|
135
|
+
# @param [Numeric] x
|
136
|
+
# @return [Rtype::Behavior::FloatCheck]
|
137
|
+
# @example Value must be a Float and > 2
|
138
|
+
# rtype [Flo > 2] => Any
|
139
|
+
def self.>(x)
|
140
|
+
::Rtype::Behavior::FloatCheck.new(:>, x)
|
141
|
+
end
|
142
|
+
|
143
|
+
# @param [Numeric] x
|
144
|
+
# @return [Rtype::Behavior::FloatCheck]
|
145
|
+
# @example Value must be a Float and > 2
|
146
|
+
# rtype [Flo > 2] => Any
|
147
|
+
def self.>=(x)
|
148
|
+
::Rtype::Behavior::FloatCheck.new(:>=, x)
|
149
|
+
end
|
150
|
+
|
151
|
+
# @param [Numeric] x
|
152
|
+
# @return [Rtype::Behavior::FloatCheck]
|
153
|
+
# @example Value must be a Float and > 2
|
154
|
+
# rtype [Flo > 2] => Any
|
155
|
+
def self.<(x)
|
156
|
+
::Rtype::Behavior::FloatCheck.new(:<, x)
|
157
|
+
end
|
158
|
+
|
159
|
+
# @param [Numeric] x
|
160
|
+
# @return [Rtype::Behavior::FloatCheck]
|
161
|
+
# @example Value must be a Float and > 2
|
162
|
+
# rtype [Flo > 2] => Any
|
163
|
+
def self.<=(x)
|
164
|
+
::Rtype::Behavior::FloatCheck.new(:<=, x)
|
165
|
+
end
|
166
|
+
|
167
|
+
# @param [Numeric] x
|
168
|
+
# @return [Rtype::Behavior::FloatCheck]
|
169
|
+
# @example Value must be a Float and > 2
|
170
|
+
# rtype [Flo > 2] => Any
|
171
|
+
def self.==(x)
|
172
|
+
::Rtype::Behavior::FloatCheck.new(:==, x)
|
173
|
+
end
|
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,21 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
class Nilable < Base
|
4
|
+
def initialize(type)
|
5
|
+
@type = type
|
6
|
+
end
|
7
|
+
|
8
|
+
def valid?(value)
|
9
|
+
value.nil? || Rtype::valid?(@type, value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def error_message(value)
|
13
|
+
Rtype::type_error_message(@type, value) + "\nOR " + Rtype::type_error_message(nil, value)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def nilable(*args)
|
19
|
+
Behavior::Nilable[*args]
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
class Not < Base
|
4
|
+
def initialize(*types)
|
5
|
+
@types = types
|
6
|
+
end
|
7
|
+
|
8
|
+
def valid?(value)
|
9
|
+
@types.all? do |e|
|
10
|
+
!Rtype::valid?(e, value)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def error_message(value)
|
15
|
+
arr = @types.map { |e| "NOT " + Rtype::type_error_message(e, value) }
|
16
|
+
arr.join "\nAND "
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def not(*args)
|
22
|
+
Behavior::Not[*args]
|
23
|
+
end
|
24
|
+
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,26 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
# Typed array behavior. empty array allowed
|
4
|
+
class TypedArray < 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?(Array)
|
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 an array with type #{@type.inspect}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
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
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
class Xor < Base
|
4
|
+
def initialize(*types)
|
5
|
+
@types = types
|
6
|
+
end
|
7
|
+
|
8
|
+
def valid?(value)
|
9
|
+
result = @types.map do |e|
|
10
|
+
Rtype::valid? e, value
|
11
|
+
end
|
12
|
+
result.count(true) == 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def error_message(value)
|
16
|
+
arr = @types.map { |e| Rtype::type_error_message(e, value) }
|
17
|
+
arr.join "\nXOR "
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def xor(*args)
|
23
|
+
Behavior::Xor[*args]
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Rtype
|
2
|
+
module Behavior
|
3
|
+
end
|
4
|
+
end
|
5
|
+
|
6
|
+
require_relative 'behavior/base'
|
7
|
+
require_relative 'behavior/and'
|
8
|
+
require_relative 'behavior/xor'
|
9
|
+
require_relative 'behavior/not'
|
10
|
+
require_relative 'behavior/nilable'
|
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'
|
17
|
+
require_relative 'behavior/core_ext'
|