kind 3.0.1 → 5.1.0
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/.tool-versions +1 -0
- data/.travis.sh +42 -12
- data/.travis.yml +7 -5
- data/CHANGELOG.md +1309 -0
- data/Gemfile +22 -7
- data/README.md +990 -490
- data/kind.gemspec +1 -1
- data/lib/kind.rb +29 -292
- data/lib/kind/active_model/validation.rb +3 -4
- data/lib/kind/core.rb +15 -0
- data/lib/kind/core/dig.rb +40 -0
- data/lib/kind/core/empty.rb +13 -0
- data/lib/kind/core/empty/constant.rb +7 -0
- data/lib/kind/{error.rb → core/error.rb} +2 -6
- data/lib/kind/core/maybe.rb +42 -0
- data/lib/kind/core/maybe/none.rb +57 -0
- data/lib/kind/core/maybe/result.rb +51 -0
- data/lib/kind/core/maybe/some.rb +90 -0
- data/lib/kind/core/maybe/typed.rb +29 -0
- data/lib/kind/core/maybe/wrappable.rb +33 -0
- data/lib/kind/core/presence.rb +33 -0
- data/lib/kind/core/try.rb +34 -0
- data/lib/kind/core/type_checker.rb +87 -0
- data/lib/kind/core/type_checkers.rb +30 -0
- data/lib/kind/core/type_checkers/custom/boolean.rb +19 -0
- data/lib/kind/core/type_checkers/custom/callable.rb +19 -0
- data/lib/kind/core/type_checkers/custom/lambda.rb +19 -0
- data/lib/kind/core/type_checkers/ruby/array.rb +17 -0
- data/lib/kind/core/type_checkers/ruby/class.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/comparable.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/enumerable.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/enumerator.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/file.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/float.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/hash.rb +17 -0
- data/lib/kind/core/type_checkers/ruby/integer.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/io.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/method.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/module.rb +17 -0
- data/lib/kind/core/type_checkers/ruby/numeric.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/proc.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/queue.rb +14 -0
- data/lib/kind/core/type_checkers/ruby/range.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/regexp.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/string.rb +17 -0
- data/lib/kind/core/type_checkers/ruby/struct.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/symbol.rb +13 -0
- data/lib/kind/core/type_checkers/ruby/time.rb +13 -0
- data/lib/kind/core/type_checkers/stdlib/open_struct.rb +13 -0
- data/lib/kind/core/type_checkers/stdlib/set.rb +17 -0
- data/lib/kind/{undefined.rb → core/undefined.rb} +4 -2
- data/lib/kind/core/utils/kind.rb +61 -0
- data/lib/kind/core/utils/undefined.rb +7 -0
- data/lib/kind/validator.rb +108 -1
- data/lib/kind/version.rb +1 -1
- data/test.sh +4 -4
- metadata +50 -15
- data/lib/kind/active_model/kind_validator.rb +0 -96
- data/lib/kind/checker.rb +0 -15
- data/lib/kind/checker/factory.rb +0 -35
- data/lib/kind/checker/protocol.rb +0 -73
- data/lib/kind/empty.rb +0 -21
- data/lib/kind/is.rb +0 -19
- data/lib/kind/maybe.rb +0 -183
- data/lib/kind/of.rb +0 -11
- data/lib/kind/types.rb +0 -115
data/kind.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.description = %q{A simple type system (at runtime) for Ruby - free of dependencies.}
|
11
11
|
spec.homepage = 'https://github.com/serradura/kind'
|
12
12
|
spec.license = 'MIT'
|
13
|
-
spec.required_ruby_version = Gem::Requirement.new('>= 2.
|
13
|
+
spec.required_ruby_version = Gem::Requirement.new('>= 2.1.0')
|
14
14
|
|
15
15
|
spec.metadata['homepage_uri'] = spec.homepage
|
16
16
|
spec.metadata['source_code_uri'] = 'https://github.com/serradura/kind'
|
data/lib/kind.rb
CHANGED
@@ -1,314 +1,51 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
|
5
|
-
require 'kind/empty'
|
6
|
-
require 'kind/undefined'
|
7
|
-
require 'kind/checker'
|
8
|
-
require 'kind/maybe'
|
9
|
-
|
10
|
-
require 'kind/error'
|
11
|
-
require 'kind/of'
|
12
|
-
require 'kind/is'
|
13
|
-
require 'kind/types'
|
3
|
+
require 'set'
|
4
|
+
require 'ostruct'
|
14
5
|
|
15
6
|
module Kind
|
16
|
-
|
17
|
-
|
18
|
-
private_constant :WRONG_NUMBER_OF_ARGUMENTS
|
7
|
+
require 'kind/version'
|
8
|
+
require 'kind/core'
|
19
9
|
|
20
|
-
|
21
|
-
return Is if Undefined == expected && Undefined == object
|
10
|
+
extend self
|
22
11
|
|
23
|
-
|
24
|
-
|
25
|
-
raise ArgumentError, WRONG_NUMBER_OF_ARGUMENTS
|
12
|
+
def is?(kind, arg)
|
13
|
+
KIND.is?(kind, arg)
|
26
14
|
end
|
27
15
|
|
28
|
-
|
29
|
-
return Of if Undefined == kind && Undefined == object
|
30
|
-
|
31
|
-
return Kind::Of.(kind, object) if Undefined != object
|
16
|
+
alias is is?
|
32
17
|
|
33
|
-
|
18
|
+
def of?(kind, *args)
|
19
|
+
KIND.of?(kind, args)
|
34
20
|
end
|
35
21
|
|
36
|
-
def
|
37
|
-
|
22
|
+
def of_class?(value)
|
23
|
+
KIND.of_class?(value)
|
38
24
|
end
|
39
25
|
|
40
|
-
|
41
|
-
|
42
|
-
# --------------------- #
|
43
|
-
|
44
|
-
module Is
|
45
|
-
def self.Class(value)
|
46
|
-
value.kind_of?(::Class)
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.Module(value)
|
50
|
-
::Module == value || (value.is_a?(::Module) && !self.Class(value))
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.Boolean(value)
|
54
|
-
Kind.of.Class(value) <= TrueClass || value <= FalseClass
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.Callable(value)
|
58
|
-
value.respond_to?(:call)
|
59
|
-
end
|
26
|
+
def of_module?(value)
|
27
|
+
KIND.of_module?(value)
|
60
28
|
end
|
61
29
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
def self.Class(object = Undefined)
|
66
|
-
return Class if Undefined == object
|
67
|
-
|
68
|
-
self.call(::Class, object)
|
69
|
-
end
|
70
|
-
|
71
|
-
const_set(:Class, ::Module.new do
|
72
|
-
extend Checker::Protocol
|
73
|
-
|
74
|
-
def self.__kind; ::Class; end
|
75
|
-
|
76
|
-
def self.class?(value); Kind::Is.Class(value); end
|
77
|
-
|
78
|
-
def self.__is_instance__(value); class?(value); end
|
79
|
-
end)
|
80
|
-
|
81
|
-
def self.Class?(*args)
|
82
|
-
Kind::Of::Class.instance?(*args)
|
83
|
-
end
|
84
|
-
|
85
|
-
# -- Module
|
86
|
-
|
87
|
-
def self.Module(object = Undefined)
|
88
|
-
return Module if Undefined == object
|
89
|
-
|
90
|
-
self.call(::Module, object)
|
91
|
-
end
|
92
|
-
|
93
|
-
const_set(:Module, ::Module.new do
|
94
|
-
extend Checker::Protocol
|
95
|
-
|
96
|
-
def self.__kind_undefined(value)
|
97
|
-
__kind_error(Kind::Undefined) if Kind::Undefined == value
|
98
|
-
|
99
|
-
yield
|
100
|
-
end
|
101
|
-
|
102
|
-
def self.__kind_error(value)
|
103
|
-
raise Kind::Error.new('Module'.freeze, value)
|
104
|
-
end
|
105
|
-
|
106
|
-
def self.__kind_of(value)
|
107
|
-
return value if Kind::Is.Module(value)
|
108
|
-
|
109
|
-
__kind_error(value)
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.__kind; ::Module; end
|
113
|
-
|
114
|
-
def self.class?(value); Kind::Is.Module(value); end
|
115
|
-
|
116
|
-
def self.instance(value, options = Empty::HASH)
|
117
|
-
default = options[:or]
|
118
|
-
|
119
|
-
if ::Kind::Maybe::Value.none?(default)
|
120
|
-
__kind_undefined(value) { __kind_of(value) }
|
121
|
-
else
|
122
|
-
return value if Kind::Undefined != value && instance?(value)
|
123
|
-
|
124
|
-
__kind_undefined(default) { __kind_of(default) }
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
def self.__is_instance__(value); class?(value); end
|
129
|
-
end)
|
130
|
-
|
131
|
-
def self.Module?(*args)
|
132
|
-
Kind::Of::Module.instance?(*args)
|
133
|
-
end
|
134
|
-
|
135
|
-
# -- Boolean
|
136
|
-
|
137
|
-
def self.Boolean(object = Undefined, options = Empty::HASH)
|
138
|
-
default = options[:or]
|
139
|
-
|
140
|
-
return Kind::Of::Boolean if Undefined == object && default.nil?
|
141
|
-
|
142
|
-
bool = object.nil? ? default : object
|
143
|
-
|
144
|
-
return bool if bool.is_a?(::TrueClass) || bool.is_a?(::FalseClass)
|
145
|
-
|
146
|
-
raise Kind::Error.new('Boolean'.freeze, bool)
|
147
|
-
end
|
148
|
-
|
149
|
-
const_set(:Boolean, ::Module.new do
|
150
|
-
extend Checker::Protocol
|
151
|
-
|
152
|
-
def self.__kind; [TrueClass, FalseClass].freeze; end
|
153
|
-
|
154
|
-
def self.class?(value); Kind.is.Boolean(value); end
|
30
|
+
def respond_to(value, *method_names)
|
31
|
+
method_names.each { |method_name| KIND.respond_to!(method_name, value) }
|
155
32
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
if ::Kind::Maybe::Value.none?(default)
|
160
|
-
__kind_undefined(value) { Kind::Of::Boolean(value) }
|
161
|
-
else
|
162
|
-
return value if Kind::Undefined != value && instance?(value)
|
163
|
-
|
164
|
-
__kind_undefined(default) { Kind::Of::Boolean(default) }
|
165
|
-
end
|
166
|
-
end
|
167
|
-
|
168
|
-
def self.__kind_undefined(value)
|
169
|
-
if Kind::Undefined == value
|
170
|
-
raise Kind::Error.new('Boolean'.freeze, Kind::Undefined)
|
171
|
-
else
|
172
|
-
yield
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def self.__is_instance__(value);
|
177
|
-
value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
178
|
-
end
|
179
|
-
|
180
|
-
def self.or_undefined(value)
|
181
|
-
result = or_nil(value)
|
182
|
-
result.nil? ? Kind::Undefined : result
|
183
|
-
end
|
184
|
-
end)
|
185
|
-
|
186
|
-
def self.Boolean?(*args)
|
187
|
-
Kind::Of::Boolean.instance?(*args)
|
188
|
-
end
|
189
|
-
|
190
|
-
# -- Lambda
|
191
|
-
|
192
|
-
def self.Lambda(object = Undefined, options = Empty::HASH)
|
193
|
-
default = options[:or]
|
194
|
-
|
195
|
-
return Kind::Of::Lambda if Undefined == object && default.nil?
|
196
|
-
|
197
|
-
func = object || default
|
198
|
-
|
199
|
-
return func if func.is_a?(::Proc) && func.lambda?
|
200
|
-
|
201
|
-
raise Kind::Error.new('Lambda'.freeze, func)
|
202
|
-
end
|
203
|
-
|
204
|
-
const_set(:Lambda, ::Module.new do
|
205
|
-
extend Checker::Protocol
|
206
|
-
|
207
|
-
def self.__kind; ::Proc; end
|
208
|
-
|
209
|
-
def self.instance(value, options = Empty::HASH)
|
210
|
-
default = options[:or]
|
211
|
-
|
212
|
-
if ::Kind::Maybe::Value.none?(default)
|
213
|
-
__kind_undefined(value) { Kind::Of::Lambda(value) }
|
214
|
-
else
|
215
|
-
return value if Kind::Undefined != value && instance?(value)
|
216
|
-
|
217
|
-
__kind_undefined(default) { Kind::Of::Lambda(default) }
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
def self.__kind_undefined(value)
|
222
|
-
if Kind::Undefined == value
|
223
|
-
raise Kind::Error.new('Lambda'.freeze, Kind::Undefined)
|
224
|
-
else
|
225
|
-
yield
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
|
-
def self.__is_instance__(value)
|
230
|
-
value.is_a?(__kind) && value.lambda?
|
231
|
-
end
|
232
|
-
end)
|
233
|
-
|
234
|
-
def self.Lambda?(*args)
|
235
|
-
Kind::Of::Lambda.instance?(*args)
|
236
|
-
end
|
237
|
-
|
238
|
-
# -- Callable
|
239
|
-
|
240
|
-
def self.Callable(object = Undefined, options = Empty::HASH)
|
241
|
-
default = options[:or]
|
242
|
-
|
243
|
-
return Kind::Of::Callable if Undefined == object && default.nil?
|
244
|
-
|
245
|
-
callable = object || default
|
246
|
-
|
247
|
-
return callable if callable.respond_to?(:call)
|
248
|
-
|
249
|
-
raise Kind::Error.new('Callable'.freeze, callable)
|
250
|
-
end
|
251
|
-
|
252
|
-
const_set(:Callable, ::Module.new do
|
253
|
-
extend Checker::Protocol
|
254
|
-
|
255
|
-
def self.__kind; Object; end
|
256
|
-
|
257
|
-
def self.class?(value)
|
258
|
-
Kind::Is::Callable(value)
|
259
|
-
end
|
260
|
-
|
261
|
-
def self.instance(value, options = Empty::HASH)
|
262
|
-
default = options[:or]
|
263
|
-
|
264
|
-
if ::Kind::Maybe::Value.none?(default)
|
265
|
-
__kind_undefined(value) { Kind::Of::Callable(value) }
|
266
|
-
else
|
267
|
-
return value if Kind::Undefined != value && instance?(value)
|
268
|
-
|
269
|
-
__kind_undefined(default) { Kind::Of::Callable(default) }
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
def self.__kind_undefined(value)
|
274
|
-
if Kind::Undefined == value
|
275
|
-
raise Kind::Error.new('Callable'.freeze, Kind::Undefined)
|
276
|
-
else
|
277
|
-
yield
|
278
|
-
end
|
279
|
-
end
|
280
|
-
|
281
|
-
def self.__is_instance__(value);
|
282
|
-
value.respond_to?(:call)
|
283
|
-
end
|
284
|
-
end)
|
285
|
-
|
286
|
-
def self.Callable?(*args)
|
287
|
-
Kind::Of::Callable.instance?(*args)
|
288
|
-
end
|
289
|
-
|
290
|
-
# ---------------------- #
|
291
|
-
# Built-in type checkers #
|
292
|
-
# ---------------------- #
|
293
|
-
|
294
|
-
# -- Classes
|
295
|
-
[
|
296
|
-
String, Symbol, Numeric, Integer, Float, Regexp, Time,
|
297
|
-
Array, Range, Hash, Struct, Enumerator, Set,
|
298
|
-
Method, Proc,
|
299
|
-
IO, File
|
300
|
-
].each { |klass| Types.add(klass) }
|
33
|
+
value
|
34
|
+
end
|
301
35
|
|
302
|
-
|
36
|
+
def of_module_or_class(value)
|
37
|
+
KIND.of_module_or_class!(value)
|
38
|
+
end
|
303
39
|
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
].each { |klass| Types.add(klass) }
|
40
|
+
def of(kind, object)
|
41
|
+
KIND.of!(kind, object)
|
42
|
+
end
|
308
43
|
|
309
|
-
|
44
|
+
def value(kind, value, default:)
|
45
|
+
KIND.value(kind, value, of(kind, default))
|
46
|
+
end
|
310
47
|
|
311
|
-
|
312
|
-
|
48
|
+
def Of(kind, opt = Empty::HASH)
|
49
|
+
TypeChecker::Object.new(kind, opt)
|
313
50
|
end
|
314
51
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
3
|
+
warn '[DEPRECATION] "kind/active_model/validation" is deprecated; use "kind/validator" instead.' \
|
4
|
+
'It will be removed on next major release.'
|
5
|
+
|
4
6
|
require 'kind/validator'
|
5
|
-
require 'active_model'
|
6
|
-
require 'active_model/validations'
|
7
|
-
require_relative 'kind_validator'
|
data/lib/kind/core.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kind/core/utils/kind'
|
4
|
+
require 'kind/core/utils/undefined'
|
5
|
+
|
6
|
+
require 'kind/core/error'
|
7
|
+
require 'kind/core/empty'
|
8
|
+
require 'kind/core/dig'
|
9
|
+
require 'kind/core/try'
|
10
|
+
require 'kind/core/presence'
|
11
|
+
require 'kind/core/undefined'
|
12
|
+
require 'kind/core/maybe'
|
13
|
+
|
14
|
+
require 'kind/core/type_checker'
|
15
|
+
require 'kind/core/type_checkers'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kind
|
4
|
+
module Dig
|
5
|
+
extend self
|
6
|
+
|
7
|
+
def call(data, keys)
|
8
|
+
return unless keys.kind_of?(::Array)
|
9
|
+
|
10
|
+
keys.reduce(data) do |memo, key|
|
11
|
+
value = get(memo, key)
|
12
|
+
|
13
|
+
break if KIND.null?(value)
|
14
|
+
|
15
|
+
value
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def [](*keys)
|
20
|
+
->(data) { call(data, keys) }
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def get(data, key)
|
26
|
+
return data[key] if ::Hash === data
|
27
|
+
|
28
|
+
case data
|
29
|
+
when ::Array
|
30
|
+
data[key] if key.respond_to?(:to_int)
|
31
|
+
when ::OpenStruct
|
32
|
+
data[key] if key.respond_to?(:to_sym)
|
33
|
+
when ::Struct
|
34
|
+
data[key] rescue nil if key.respond_to?(:to_int) || key.respond_to?(:to_sym)
|
35
|
+
else
|
36
|
+
data.public_send(key) if key.respond_to?(:to_sym) && data.respond_to?(key)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -2,12 +2,8 @@
|
|
2
2
|
|
3
3
|
module Kind
|
4
4
|
class Error < TypeError
|
5
|
-
|
6
|
-
|
7
|
-
private_constant :UNDEFINED_OBJECT
|
8
|
-
|
9
|
-
def initialize(arg, object = UNDEFINED_OBJECT)
|
10
|
-
if UNDEFINED_OBJECT == object
|
5
|
+
def initialize(arg, object = UNDEFINED)
|
6
|
+
if UNDEFINED == object
|
11
7
|
# Will be used when the exception was raised with a message. e.g:
|
12
8
|
# raise Kind::Error, "some message"
|
13
9
|
super(arg)
|