kind 2.3.0 → 4.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 +37 -12
- data/.travis.yml +6 -3
- data/CHANGELOG.md +1267 -0
- data/Gemfile +10 -2
- data/README.md +1005 -489
- data/lib/kind.rb +53 -281
- data/lib/kind/active_model/kind_validator.rb +20 -13
- data/lib/kind/core.rb +10 -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/core/wrong_number_of_args.rb +9 -0
- data/lib/kind/deprecations/built_in_type_checkers.rb +23 -0
- data/lib/kind/{checker.rb → deprecations/checker.rb} +3 -2
- data/lib/kind/{checker → deprecations/checker}/factory.rb +1 -5
- data/lib/kind/{checker → deprecations/checker}/protocol.rb +3 -3
- data/lib/kind/deprecations/is.rb +35 -0
- data/lib/kind/deprecations/of.rb +258 -0
- data/lib/kind/{types.rb → deprecations/types.rb} +14 -8
- 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 +14 -130
- 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 +33 -0
- data/lib/kind/presence.rb +33 -0
- data/lib/kind/try.rb +34 -0
- data/lib/kind/type_checker.rb +87 -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 +53 -9
- data/lib/kind/is.rb +0 -19
- data/lib/kind/of.rb +0 -11
data/lib/kind.rb
CHANGED
@@ -1,314 +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'
|
7
|
-
require 'kind/checker'
|
8
15
|
require 'kind/maybe'
|
9
16
|
|
10
|
-
require 'kind/
|
11
|
-
require 'kind/
|
12
|
-
require 'kind/is'
|
13
|
-
require 'kind/types'
|
14
|
-
|
15
|
-
module Kind
|
16
|
-
WRONG_NUMBER_OF_ARGUMENTS = 'wrong number of arguments (given 1, expected 2)'.freeze
|
17
|
-
|
18
|
-
private_constant :WRONG_NUMBER_OF_ARGUMENTS
|
17
|
+
require 'kind/type_checker'
|
18
|
+
require 'kind/type_checkers'
|
19
19
|
|
20
|
-
|
21
|
-
|
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'
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.of(kind = Undefined, object = Undefined)
|
29
|
-
return Of if Undefined == kind && Undefined == object
|
30
|
-
|
31
|
-
return Kind::Of.(kind, object) if Undefined != object
|
32
|
-
|
33
|
-
Kind::Checker::Factory.create(kind)
|
26
|
+
module Kind
|
27
|
+
def self.is?(kind, arg)
|
28
|
+
KIND.is?(kind, arg)
|
34
29
|
end
|
35
30
|
|
36
31
|
def self.of?(kind, *args)
|
37
|
-
|
32
|
+
KIND.of?(kind, args)
|
38
33
|
end
|
39
34
|
|
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
|
35
|
+
def self.of_class?(value)
|
36
|
+
KIND.of_class?(value)
|
60
37
|
end
|
61
38
|
|
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
|
155
|
-
|
156
|
-
def self.instance(value, options= Empty::HASH)
|
157
|
-
default = options[:or]
|
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
|
39
|
+
def self.of_module?(value)
|
40
|
+
KIND.of_module?(value)
|
41
|
+
end
|
239
42
|
|
240
|
-
|
241
|
-
|
43
|
+
def self.respond_to(value, *method_names)
|
44
|
+
method_names.each { |method_name| KIND.respond_to!(method_name, value) }
|
242
45
|
|
243
|
-
|
46
|
+
value
|
47
|
+
end
|
244
48
|
|
245
|
-
|
49
|
+
def self.of_module_or_class(value)
|
50
|
+
KIND.of_module_or_class!(value)
|
51
|
+
end
|
246
52
|
|
247
|
-
|
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}')
|
248
56
|
|
249
|
-
|
57
|
+
return Is
|
250
58
|
end
|
251
59
|
|
252
|
-
|
253
|
-
extend Checker::Protocol
|
254
|
-
|
255
|
-
def self.__kind; Object; end
|
256
|
-
|
257
|
-
def self.class?(value)
|
258
|
-
Kind::Is::Callable(value)
|
259
|
-
end
|
60
|
+
return is?(expected, object) if UNDEFINED != object
|
260
61
|
|
261
|
-
|
262
|
-
|
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
|
62
|
+
WRONG_NUMBER_OF_ARGS.error!(given: 1, expected: 2)
|
63
|
+
end
|
272
64
|
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
else
|
277
|
-
yield
|
278
|
-
end
|
279
|
-
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}')
|
280
68
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
69
|
+
Of
|
70
|
+
elsif UNDEFINED != object
|
71
|
+
KIND.of!(kind, object)
|
72
|
+
else
|
73
|
+
DEPRECATION.warn_method_replacement('Kind.of(<Kind>)', 'Kind::Of(<Kind>)')
|
285
74
|
|
286
|
-
|
287
|
-
Kind::Of::Callable.instance?(*args)
|
75
|
+
Checker::Factory.create(kind)
|
288
76
|
end
|
77
|
+
end
|
289
78
|
|
290
|
-
|
291
|
-
|
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) }
|
301
|
-
|
302
|
-
Types.add(Queue, name: 'Queue'.freeze)
|
303
|
-
|
304
|
-
# -- Modules
|
305
|
-
[
|
306
|
-
Enumerable, Comparable
|
307
|
-
].each { |klass| Types.add(klass) }
|
308
|
-
|
309
|
-
# -- Kind::Of::Maybe
|
79
|
+
def self.value(kind, value, default:)
|
80
|
+
KIND.value(kind, value, of(kind, default))
|
81
|
+
end
|
310
82
|
|
311
|
-
|
312
|
-
|
83
|
+
def self.Of(kind, opt = Empty::HASH)
|
84
|
+
TypeChecker::Object.new(kind, opt)
|
313
85
|
end
|
314
86
|
end
|
@@ -35,30 +35,30 @@ class KindValidator < ActiveModel::EachValidator
|
|
35
35
|
def kind_of(expected, value)
|
36
36
|
types = Array(expected)
|
37
37
|
|
38
|
-
return if types.any? { |type|
|
38
|
+
return if types.any? { |type| type === value }
|
39
39
|
|
40
|
-
"must be a kind of: #{types.map { |
|
40
|
+
"must be a kind of: #{types.map { |type| type.name }.join(', ')}"
|
41
41
|
end
|
42
42
|
|
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
|
-
result = expected.map { |kind| kind_is_not(kind, value) }.compact
|
48
|
+
result = expected.map { |kind| kind_is_not(kind, value) }.tap(&:compact!)
|
49
49
|
|
50
50
|
result.empty? || result.size < expected.size ? nil : result.join(', ')
|
51
51
|
end
|
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
|
@@ -66,10 +66,17 @@ class KindValidator < ActiveModel::EachValidator
|
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
def respond_to(
|
70
|
-
|
69
|
+
def respond_to(expected, value)
|
70
|
+
method_names = Array(expected)
|
71
71
|
|
72
|
-
|
72
|
+
expected_methods = method_names.select { |method_name| !value.respond_to?(method_name) }
|
73
|
+
expected_methods.map! { |method_name| "`#{method_name}`" }
|
74
|
+
|
75
|
+
return if expected_methods.empty?
|
76
|
+
|
77
|
+
methods = expected_methods.size == 1 ? 'method' : 'methods'
|
78
|
+
|
79
|
+
"must respond to the #{methods}: #{expected_methods.join(', ')}"
|
73
80
|
end
|
74
81
|
|
75
82
|
def instance_of(expected, value)
|
@@ -81,7 +88,7 @@ class KindValidator < ActiveModel::EachValidator
|
|
81
88
|
end
|
82
89
|
|
83
90
|
def array_with(expected, value)
|
84
|
-
return if value.kind_of?(Array) && !value.empty? && (value - Kind
|
91
|
+
return if value.kind_of?(::Array) && !value.empty? && (value - Kind::Array[expected]).empty?
|
85
92
|
|
86
93
|
"must be an array with: #{expected.join(', ')}"
|
87
94
|
end
|
@@ -89,7 +96,7 @@ class KindValidator < ActiveModel::EachValidator
|
|
89
96
|
def array_of(expected, value)
|
90
97
|
types = Array(expected)
|
91
98
|
|
92
|
-
return if value.kind_of?(Array) && !value.empty? && value.all? { |value| types.any? { |type| value.kind_of?(type) } }
|
99
|
+
return if value.kind_of?(::Array) && !value.empty? && value.all? { |value| types.any? { |type| value.kind_of?(type) } }
|
93
100
|
|
94
101
|
"must be an array of: #{types.map { |klass| klass.name }.join(', ')}"
|
95
102
|
end
|