kind 2.2.0 → 4.0.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 +37 -12
- data/.travis.yml +10 -4
- data/CHANGELOG.md +1230 -0
- data/Gemfile +10 -2
- data/README.md +938 -460
- data/lib/kind.rb +52 -298
- data/lib/kind/active_model/kind_validator.rb +7 -7
- data/lib/kind/core.rb +9 -0
- data/lib/kind/core/deprecation.rb +29 -0
- data/lib/kind/core/kind.rb +61 -0
- data/lib/kind/core/undefined.rb +7 -0
- data/lib/kind/deprecations/built_in_type_checkers.rb +23 -0
- data/lib/kind/deprecations/checker.rb +16 -0
- data/lib/kind/deprecations/checker/factory.rb +31 -0
- data/lib/kind/deprecations/checker/protocol.rb +73 -0
- data/lib/kind/deprecations/is.rb +35 -0
- data/lib/kind/deprecations/of.rb +258 -0
- data/lib/kind/{types.rb → deprecations/types.rb} +15 -9
- data/lib/kind/dig.rb +40 -0
- data/lib/kind/empty.rb +5 -11
- data/lib/kind/error.rb +2 -6
- data/lib/kind/maybe.rb +22 -113
- data/lib/kind/maybe/none.rb +57 -0
- data/lib/kind/maybe/result.rb +51 -0
- data/lib/kind/maybe/some.rb +90 -0
- data/lib/kind/maybe/typed.rb +29 -0
- data/lib/kind/maybe/wrappable.rb +35 -0
- data/lib/kind/presence.rb +33 -0
- data/lib/kind/try.rb +36 -0
- data/lib/kind/type_checker.rb +73 -0
- data/lib/kind/type_checkers.rb +30 -0
- data/lib/kind/type_checkers/core/array.rb +17 -0
- data/lib/kind/type_checkers/core/class.rb +13 -0
- data/lib/kind/type_checkers/core/comparable.rb +13 -0
- data/lib/kind/type_checkers/core/enumerable.rb +13 -0
- data/lib/kind/type_checkers/core/enumerator.rb +13 -0
- data/lib/kind/type_checkers/core/file.rb +13 -0
- data/lib/kind/type_checkers/core/float.rb +13 -0
- data/lib/kind/type_checkers/core/hash.rb +17 -0
- data/lib/kind/type_checkers/core/integer.rb +13 -0
- data/lib/kind/type_checkers/core/io.rb +13 -0
- data/lib/kind/type_checkers/core/method.rb +13 -0
- data/lib/kind/type_checkers/core/module.rb +17 -0
- data/lib/kind/type_checkers/core/numeric.rb +13 -0
- data/lib/kind/type_checkers/core/proc.rb +13 -0
- data/lib/kind/type_checkers/core/queue.rb +14 -0
- data/lib/kind/type_checkers/core/range.rb +13 -0
- data/lib/kind/type_checkers/core/regexp.rb +13 -0
- data/lib/kind/type_checkers/core/string.rb +17 -0
- data/lib/kind/type_checkers/core/struct.rb +13 -0
- data/lib/kind/type_checkers/core/symbol.rb +13 -0
- data/lib/kind/type_checkers/core/time.rb +13 -0
- data/lib/kind/type_checkers/custom/boolean.rb +19 -0
- data/lib/kind/type_checkers/custom/callable.rb +19 -0
- data/lib/kind/type_checkers/custom/lambda.rb +19 -0
- data/lib/kind/type_checkers/stdlib/open_struct.rb +13 -0
- data/lib/kind/type_checkers/stdlib/set.rb +17 -0
- data/lib/kind/undefined.rb +4 -2
- data/lib/kind/validator.rb +1 -1
- data/lib/kind/version.rb +1 -1
- data/test.sh +4 -4
- metadata +52 -7
- data/lib/kind/checker.rb +0 -83
- data/lib/kind/is.rb +0 -19
- data/lib/kind/of.rb +0 -11
data/lib/kind.rb
CHANGED
@@ -1,332 +1,86 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'set'
|
4
|
+
require 'ostruct'
|
5
|
+
|
3
6
|
require 'kind/version'
|
7
|
+
require 'kind/core'
|
4
8
|
|
9
|
+
require 'kind/error'
|
5
10
|
require 'kind/empty'
|
11
|
+
require 'kind/dig'
|
12
|
+
require 'kind/try'
|
13
|
+
require 'kind/presence'
|
6
14
|
require 'kind/undefined'
|
15
|
+
require 'kind/type_checker'
|
16
|
+
|
17
|
+
require 'kind/type_checkers'
|
7
18
|
require 'kind/maybe'
|
8
19
|
|
9
|
-
require 'kind/
|
10
|
-
require 'kind/of'
|
11
|
-
require 'kind/is'
|
12
|
-
require 'kind/
|
13
|
-
require 'kind/
|
20
|
+
require 'kind/deprecations/checker'
|
21
|
+
require 'kind/deprecations/of'
|
22
|
+
require 'kind/deprecations/is'
|
23
|
+
require 'kind/deprecations/types'
|
24
|
+
require 'kind/deprecations/built_in_type_checkers'
|
14
25
|
|
15
26
|
module Kind
|
16
|
-
|
17
|
-
|
18
|
-
private_constant :WRONG_NUMBER_OF_ARGUMENTS
|
19
|
-
|
20
|
-
def self.is(expected = Undefined, object = Undefined)
|
21
|
-
return Is if Undefined == expected && Undefined == object
|
22
|
-
|
23
|
-
return Kind::Is.(expected, object) if Undefined != object
|
24
|
-
|
25
|
-
raise ArgumentError, WRONG_NUMBER_OF_ARGUMENTS
|
27
|
+
def self.is?(kind, arg)
|
28
|
+
KIND.is?(kind, arg)
|
26
29
|
end
|
27
30
|
|
28
|
-
|
29
|
-
|
30
|
-
private_constant :MODULE_OR_CLASS
|
31
|
-
|
32
|
-
private_class_method def self.__checkers__
|
33
|
-
@__checkers__ ||= {}
|
31
|
+
def self.of?(kind, *args)
|
32
|
+
KIND.of?(kind, args)
|
34
33
|
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
def self.of(kind = Undefined, object = Undefined)
|
39
|
-
return Of if Undefined == kind && Undefined == object
|
40
|
-
|
41
|
-
return Kind::Of.(kind, object) if Undefined != object
|
42
|
-
|
43
|
-
__checkers__[kind] ||= begin
|
44
|
-
kind_name = kind.name
|
45
|
-
|
46
|
-
if Kind::Of.const_defined?(kind_name, false)
|
47
|
-
Kind::Of.const_get(kind_name)
|
48
|
-
else
|
49
|
-
Checker.new(Kind::Of.(Module, kind, MODULE_OR_CLASS))
|
50
|
-
end
|
51
|
-
end
|
35
|
+
def self.of_class?(value)
|
36
|
+
KIND.of_class?(value)
|
52
37
|
end
|
53
38
|
|
54
|
-
def self.
|
55
|
-
|
39
|
+
def self.of_module?(value)
|
40
|
+
KIND.of_module?(value)
|
56
41
|
end
|
57
42
|
|
58
|
-
|
59
|
-
|
60
|
-
# --------------------- #
|
43
|
+
def self.respond_to(value, *method_names)
|
44
|
+
method_names.each { |method_name| KIND.respond_to!(method_name, value) }
|
61
45
|
|
62
|
-
|
63
|
-
def self.Class(value)
|
64
|
-
value.kind_of?(::Class)
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.Module(value)
|
68
|
-
::Module == value || (value.is_a?(::Module) && !self.Class(value))
|
69
|
-
end
|
70
|
-
|
71
|
-
def self.Boolean(value)
|
72
|
-
Kind.of.Class(value) <= TrueClass || value <= FalseClass
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.Callable(value)
|
76
|
-
value.respond_to?(:call)
|
77
|
-
end
|
46
|
+
value
|
78
47
|
end
|
79
48
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
def self.Class(object = Undefined)
|
84
|
-
return Class if Undefined == object
|
85
|
-
|
86
|
-
self.call(::Class, object)
|
87
|
-
end
|
88
|
-
|
89
|
-
const_set(:Class, ::Module.new do
|
90
|
-
extend Checkable
|
91
|
-
|
92
|
-
def self.__kind; ::Class; end
|
93
|
-
|
94
|
-
def self.class?(value); Kind::Is.Class(value); end
|
95
|
-
|
96
|
-
def self.__is_instance__(value); class?(value); end
|
97
|
-
end)
|
98
|
-
|
99
|
-
def self.Class?(*args)
|
100
|
-
Kind::Of::Class.instance?(*args)
|
101
|
-
end
|
102
|
-
|
103
|
-
# -- Module
|
104
|
-
|
105
|
-
def self.Module(object = Undefined)
|
106
|
-
return Module if Undefined == object
|
107
|
-
|
108
|
-
self.call(::Module, object)
|
109
|
-
end
|
110
|
-
|
111
|
-
const_set(:Module, ::Module.new do
|
112
|
-
extend Checkable
|
113
|
-
|
114
|
-
def self.__kind_undefined(value)
|
115
|
-
__kind_error(Kind::Undefined) if Kind::Undefined == value
|
116
|
-
|
117
|
-
yield
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.__kind_error(value)
|
121
|
-
raise Kind::Error.new('Module'.freeze, value)
|
122
|
-
end
|
123
|
-
|
124
|
-
def self.__kind_of(value)
|
125
|
-
return value if Kind::Is.Module(value)
|
126
|
-
|
127
|
-
__kind_error(value)
|
128
|
-
end
|
129
|
-
|
130
|
-
def self.__kind; ::Module; end
|
131
|
-
|
132
|
-
def self.class?(value); Kind::Is.Module(value); end
|
133
|
-
|
134
|
-
def self.instance(value, options = Empty::HASH)
|
135
|
-
default = options[:or]
|
136
|
-
|
137
|
-
if ::Kind::Maybe::Value.none?(default)
|
138
|
-
__kind_undefined(value) { __kind_of(value) }
|
139
|
-
else
|
140
|
-
return value if Kind::Undefined != value && instance?(value)
|
141
|
-
|
142
|
-
__kind_undefined(default) { __kind_of(default) }
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
def self.__is_instance__(value); class?(value); end
|
147
|
-
end)
|
148
|
-
|
149
|
-
def self.Module?(*args)
|
150
|
-
Kind::Of::Module.instance?(*args)
|
151
|
-
end
|
152
|
-
|
153
|
-
# -- Boolean
|
154
|
-
|
155
|
-
def self.Boolean(object = Undefined, options = Empty::HASH)
|
156
|
-
default = options[:or]
|
157
|
-
|
158
|
-
return Kind::Of::Boolean if Undefined == object && default.nil?
|
159
|
-
|
160
|
-
bool = object.nil? ? default : object
|
161
|
-
|
162
|
-
return bool if bool.is_a?(::TrueClass) || bool.is_a?(::FalseClass)
|
163
|
-
|
164
|
-
raise Kind::Error.new('Boolean'.freeze, bool)
|
165
|
-
end
|
166
|
-
|
167
|
-
const_set(:Boolean, ::Module.new do
|
168
|
-
extend Checkable
|
169
|
-
|
170
|
-
def self.__kind; [TrueClass, FalseClass].freeze; end
|
171
|
-
|
172
|
-
def self.class?(value); Kind.is.Boolean(value); end
|
173
|
-
|
174
|
-
def self.instance(value, options= Empty::HASH)
|
175
|
-
default = options[:or]
|
176
|
-
|
177
|
-
if ::Kind::Maybe::Value.none?(default)
|
178
|
-
__kind_undefined(value) { Kind::Of::Boolean(value) }
|
179
|
-
else
|
180
|
-
return value if Kind::Undefined != value && instance?(value)
|
181
|
-
|
182
|
-
__kind_undefined(default) { Kind::Of::Boolean(default) }
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
def self.__kind_undefined(value)
|
187
|
-
if Kind::Undefined == value
|
188
|
-
raise Kind::Error.new('Boolean'.freeze, Kind::Undefined)
|
189
|
-
else
|
190
|
-
yield
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
def self.__is_instance__(value);
|
195
|
-
value.is_a?(TrueClass) || value.is_a?(FalseClass)
|
196
|
-
end
|
197
|
-
|
198
|
-
def self.or_undefined(value)
|
199
|
-
result = or_nil(value)
|
200
|
-
result.nil? ? Kind::Undefined : result
|
201
|
-
end
|
202
|
-
end)
|
203
|
-
|
204
|
-
def self.Boolean?(*args)
|
205
|
-
Kind::Of::Boolean.instance?(*args)
|
206
|
-
end
|
207
|
-
|
208
|
-
# -- Lambda
|
209
|
-
|
210
|
-
def self.Lambda(object = Undefined, options = Empty::HASH)
|
211
|
-
default = options[:or]
|
212
|
-
|
213
|
-
return Kind::Of::Lambda if Undefined == object && default.nil?
|
214
|
-
|
215
|
-
func = object || default
|
216
|
-
|
217
|
-
return func if func.is_a?(::Proc) && func.lambda?
|
218
|
-
|
219
|
-
raise Kind::Error.new('Lambda'.freeze, func)
|
220
|
-
end
|
221
|
-
|
222
|
-
const_set(:Lambda, ::Module.new do
|
223
|
-
extend Checkable
|
224
|
-
|
225
|
-
def self.__kind; ::Proc; end
|
226
|
-
|
227
|
-
def self.instance(value, options = Empty::HASH)
|
228
|
-
default = options[:or]
|
229
|
-
|
230
|
-
if ::Kind::Maybe::Value.none?(default)
|
231
|
-
__kind_undefined(value) { Kind::Of::Lambda(value) }
|
232
|
-
else
|
233
|
-
return value if Kind::Undefined != value && instance?(value)
|
234
|
-
|
235
|
-
__kind_undefined(default) { Kind::Of::Lambda(default) }
|
236
|
-
end
|
237
|
-
end
|
238
|
-
|
239
|
-
def self.__kind_undefined(value)
|
240
|
-
if Kind::Undefined == value
|
241
|
-
raise Kind::Error.new('Lambda'.freeze, Kind::Undefined)
|
242
|
-
else
|
243
|
-
yield
|
244
|
-
end
|
245
|
-
end
|
246
|
-
|
247
|
-
def self.__is_instance__(value)
|
248
|
-
value.is_a?(__kind) && value.lambda?
|
249
|
-
end
|
250
|
-
end)
|
251
|
-
|
252
|
-
def self.Lambda?(*args)
|
253
|
-
Kind::Of::Lambda.instance?(*args)
|
254
|
-
end
|
255
|
-
|
256
|
-
# -- Callable
|
257
|
-
|
258
|
-
def self.Callable(object = Undefined, options = Empty::HASH)
|
259
|
-
default = options[:or]
|
260
|
-
|
261
|
-
return Kind::Of::Callable if Undefined == object && default.nil?
|
262
|
-
|
263
|
-
callable = object || default
|
49
|
+
def self.of_module_or_class(value)
|
50
|
+
KIND.of_module_or_class!(value)
|
51
|
+
end
|
264
52
|
|
265
|
-
|
53
|
+
def self.is(expected = UNDEFINED, object = UNDEFINED)
|
54
|
+
if UNDEFINED == expected && UNDEFINED == object
|
55
|
+
DEPRECATION.warn('`Kind.is` without args is deprecated. This behavior will be removed in %{version}')
|
266
56
|
|
267
|
-
|
57
|
+
return Is
|
268
58
|
end
|
269
59
|
|
270
|
-
|
271
|
-
extend Checkable
|
272
|
-
|
273
|
-
def self.__kind; Object; end
|
274
|
-
|
275
|
-
def self.class?(value)
|
276
|
-
Kind::Is::Callable(value)
|
277
|
-
end
|
60
|
+
return is?(expected, object) if UNDEFINED != object
|
278
61
|
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
if ::Kind::Maybe::Value.none?(default)
|
283
|
-
__kind_undefined(value) { Kind::Of::Callable(value) }
|
284
|
-
else
|
285
|
-
return value if Kind::Undefined != value && instance?(value)
|
286
|
-
|
287
|
-
__kind_undefined(default) { Kind::Of::Callable(default) }
|
288
|
-
end
|
289
|
-
end
|
62
|
+
raise ArgumentError, 'wrong number of arguments (given 1, expected 2)'
|
63
|
+
end
|
290
64
|
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
else
|
295
|
-
yield
|
296
|
-
end
|
297
|
-
end
|
65
|
+
def self.of(kind = UNDEFINED, object = UNDEFINED)
|
66
|
+
if UNDEFINED == kind && UNDEFINED == object
|
67
|
+
DEPRECATION.warn('`Kind.of` without args is deprecated. This behavior will be removed in %{version}')
|
298
68
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
69
|
+
Of
|
70
|
+
elsif UNDEFINED != object
|
71
|
+
KIND.of!(kind, object)
|
72
|
+
else
|
73
|
+
DEPRECATION.warn_method_replacement('Kind.of(<Kind>)', 'Kind::Of(<Kind>)')
|
303
74
|
|
304
|
-
|
305
|
-
Kind::Of::Callable.instance?(*args)
|
75
|
+
Checker::Factory.create(kind)
|
306
76
|
end
|
77
|
+
end
|
307
78
|
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
# -- Classes
|
313
|
-
[
|
314
|
-
String, Symbol, Numeric, Integer, Float, Regexp, Time,
|
315
|
-
Array, Range, Hash, Struct, Enumerator, Set,
|
316
|
-
Method, Proc,
|
317
|
-
IO, File
|
318
|
-
].each { |klass| Types.add(klass) }
|
319
|
-
|
320
|
-
Types.add(Queue, name: 'Queue'.freeze)
|
321
|
-
|
322
|
-
# -- Modules
|
323
|
-
[
|
324
|
-
Enumerable, Comparable
|
325
|
-
].each { |klass| Types.add(klass) }
|
326
|
-
|
327
|
-
# -- Kind::Of::Maybe
|
79
|
+
def self.value(kind, value, default:)
|
80
|
+
KIND.value(kind, value, of(kind, default))
|
81
|
+
end
|
328
82
|
|
329
|
-
|
330
|
-
|
83
|
+
def self.Of(kind, opt = Empty::HASH)
|
84
|
+
TypeChecker::Object.new(kind, opt)
|
331
85
|
end
|
332
86
|
end
|
@@ -43,7 +43,7 @@ class KindValidator < ActiveModel::EachValidator
|
|
43
43
|
CLASS_OR_MODULE = 'Class/Module'.freeze
|
44
44
|
|
45
45
|
def kind_is(expected, value)
|
46
|
-
return kind_is_not(expected, value) unless expected.kind_of?(Array)
|
46
|
+
return kind_is_not(expected, value) unless expected.kind_of?(::Array)
|
47
47
|
|
48
48
|
result = expected.map { |kind| kind_is_not(kind, value) }.compact
|
49
49
|
|
@@ -52,13 +52,13 @@ class KindValidator < ActiveModel::EachValidator
|
|
52
52
|
|
53
53
|
def kind_is_not(expected, value)
|
54
54
|
case expected
|
55
|
-
when Class
|
56
|
-
return if expected == Kind
|
55
|
+
when ::Class
|
56
|
+
return if expected == Kind::Class[value] || value < expected
|
57
57
|
|
58
58
|
"must be the class or a subclass of `#{expected.name}`"
|
59
|
-
when Module
|
59
|
+
when ::Module
|
60
60
|
return if value.kind_of?(Class) && value <= expected
|
61
|
-
return if expected == Kind.
|
61
|
+
return if expected == Kind.of_module_or_class(value) || value.kind_of?(expected)
|
62
62
|
|
63
63
|
"must include the `#{expected.name}` module"
|
64
64
|
else
|
@@ -81,7 +81,7 @@ class KindValidator < ActiveModel::EachValidator
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def array_with(expected, value)
|
84
|
-
return if value.kind_of?(Array) && !value.empty? && (value - Kind
|
84
|
+
return if value.kind_of?(::Array) && !value.empty? && (value - Kind::Array[expected]).empty?
|
85
85
|
|
86
86
|
"must be an array with: #{expected.join(', ')}"
|
87
87
|
end
|
@@ -89,7 +89,7 @@ class KindValidator < ActiveModel::EachValidator
|
|
89
89
|
def array_of(expected, value)
|
90
90
|
types = Array(expected)
|
91
91
|
|
92
|
-
return if value.kind_of?(Array) && !value.empty? && value.all? { |value| types.any? { |type| value.kind_of?(type) } }
|
92
|
+
return if value.kind_of?(::Array) && !value.empty? && value.all? { |value| types.any? { |type| value.kind_of?(type) } }
|
93
93
|
|
94
94
|
"must be an array of: #{types.map { |klass| klass.name }.join(', ')}"
|
95
95
|
end
|
data/lib/kind/core.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Kind
|
4
|
+
module DEPRECATION # :nodoc: all
|
5
|
+
WARN_IS_DISABLED = String(ENV['DISABLE_KIND_DEPRECATION']).strip == 't'
|
6
|
+
|
7
|
+
module DevNull
|
8
|
+
def self.warn(_)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
OUTPUT = WARN_IS_DISABLED ? DevNull : ::Kernel
|
13
|
+
|
14
|
+
def self.warn(message)
|
15
|
+
OUTPUT.warn("[DEPRECATION] #{message}" % { version: 'version 5.0' })
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.warn_method_replacement(old_method, new_method)
|
19
|
+
self.warn "`#{old_method}` is deprecated, it will be removed in %{version}. " \
|
20
|
+
"Please use `#{new_method}` instead."
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.warn_removal(name)
|
24
|
+
self.warn "`#{name}` is deprecated, it will be removed in %{version}."
|
25
|
+
end
|
26
|
+
|
27
|
+
private_constant :DevNull, :OUTPUT
|
28
|
+
end
|
29
|
+
end
|