kind 1.9.0 → 3.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/.travis.yml +4 -1
- data/README.md +445 -154
- data/lib/kind.rb +55 -48
- data/lib/kind/active_model/kind_validator.rb +36 -16
- data/lib/kind/checker.rb +3 -63
- data/lib/kind/checker/factory.rb +35 -0
- data/lib/kind/checker/protocol.rb +73 -0
- data/lib/kind/error.rb +1 -1
- data/lib/kind/maybe.rb +90 -17
- data/lib/kind/types.rb +15 -4
- data/lib/kind/undefined.rb +1 -1
- data/lib/kind/validator.rb +2 -2
- data/lib/kind/version.rb +1 -1
- metadata +4 -2
data/lib/kind.rb
CHANGED
@@ -4,12 +4,12 @@ require 'kind/version'
|
|
4
4
|
|
5
5
|
require 'kind/empty'
|
6
6
|
require 'kind/undefined'
|
7
|
+
require 'kind/checker'
|
7
8
|
require 'kind/maybe'
|
8
9
|
|
9
10
|
require 'kind/error'
|
10
11
|
require 'kind/of'
|
11
12
|
require 'kind/is'
|
12
|
-
require 'kind/checker'
|
13
13
|
require 'kind/types'
|
14
14
|
|
15
15
|
module Kind
|
@@ -18,35 +18,23 @@ module Kind
|
|
18
18
|
private_constant :WRONG_NUMBER_OF_ARGUMENTS
|
19
19
|
|
20
20
|
def self.is(expected = Undefined, object = Undefined)
|
21
|
-
return Is if
|
21
|
+
return Is if Undefined == expected && Undefined == object
|
22
22
|
|
23
|
-
return Kind::Is.(expected, object) if
|
23
|
+
return Kind::Is.(expected, object) if Undefined != object
|
24
24
|
|
25
25
|
raise ArgumentError, WRONG_NUMBER_OF_ARGUMENTS
|
26
26
|
end
|
27
27
|
|
28
|
-
MODULE_OR_CLASS = 'Module/Class'.freeze
|
29
|
-
|
30
|
-
private_constant :MODULE_OR_CLASS
|
31
|
-
|
32
28
|
def self.of(kind = Undefined, object = Undefined)
|
33
|
-
return Of if
|
29
|
+
return Of if Undefined == kind && Undefined == object
|
34
30
|
|
35
|
-
return Kind::Of.(kind, object) if
|
31
|
+
return Kind::Of.(kind, object) if Undefined != object
|
36
32
|
|
37
|
-
|
38
|
-
kind_name = kind.name
|
39
|
-
|
40
|
-
if Kind::Of.const_defined?(kind_name, false)
|
41
|
-
Kind::Of.const_get(kind_name)
|
42
|
-
else
|
43
|
-
Checker.new(Kind::Of.(Module, kind, MODULE_OR_CLASS))
|
44
|
-
end
|
45
|
-
end
|
33
|
+
Kind::Checker::Factory.create(kind)
|
46
34
|
end
|
47
35
|
|
48
|
-
|
49
|
-
|
36
|
+
def self.of?(kind, *args)
|
37
|
+
Kind.of(kind).instance?(*args)
|
50
38
|
end
|
51
39
|
|
52
40
|
# --------------------- #
|
@@ -55,20 +43,19 @@ module Kind
|
|
55
43
|
|
56
44
|
module Is
|
57
45
|
def self.Class(value)
|
58
|
-
value.
|
46
|
+
value.kind_of?(::Class)
|
59
47
|
end
|
60
48
|
|
61
49
|
def self.Module(value)
|
62
|
-
|
50
|
+
::Module == value || (value.is_a?(::Module) && !self.Class(value))
|
63
51
|
end
|
64
52
|
|
65
53
|
def self.Boolean(value)
|
66
|
-
|
67
|
-
klass <= TrueClass || klass <= FalseClass
|
54
|
+
Kind.of.Class(value) <= TrueClass || value <= FalseClass
|
68
55
|
end
|
69
56
|
|
70
57
|
def self.Callable(value)
|
71
|
-
value.respond_to?(:call)
|
58
|
+
value.respond_to?(:call)
|
72
59
|
end
|
73
60
|
end
|
74
61
|
|
@@ -76,13 +63,13 @@ module Kind
|
|
76
63
|
# -- Class
|
77
64
|
|
78
65
|
def self.Class(object = Undefined)
|
79
|
-
return Class if
|
66
|
+
return Class if Undefined == object
|
80
67
|
|
81
68
|
self.call(::Class, object)
|
82
69
|
end
|
83
70
|
|
84
71
|
const_set(:Class, ::Module.new do
|
85
|
-
extend
|
72
|
+
extend Checker::Protocol
|
86
73
|
|
87
74
|
def self.__kind; ::Class; end
|
88
75
|
|
@@ -91,18 +78,26 @@ module Kind
|
|
91
78
|
def self.__is_instance__(value); class?(value); end
|
92
79
|
end)
|
93
80
|
|
81
|
+
def self.Class?(*args)
|
82
|
+
Kind::Of::Class.instance?(*args)
|
83
|
+
end
|
84
|
+
|
94
85
|
# -- Module
|
95
86
|
|
96
87
|
def self.Module(object = Undefined)
|
97
|
-
return Module if
|
88
|
+
return Module if Undefined == object
|
98
89
|
|
99
90
|
self.call(::Module, object)
|
100
91
|
end
|
101
92
|
|
102
93
|
const_set(:Module, ::Module.new do
|
103
|
-
extend
|
94
|
+
extend Checker::Protocol
|
104
95
|
|
105
|
-
def self.
|
96
|
+
def self.__kind_undefined(value)
|
97
|
+
__kind_error(Kind::Undefined) if Kind::Undefined == value
|
98
|
+
|
99
|
+
yield
|
100
|
+
end
|
106
101
|
|
107
102
|
def self.__kind_error(value)
|
108
103
|
raise Kind::Error.new('Module'.freeze, value)
|
@@ -114,11 +109,7 @@ module Kind
|
|
114
109
|
__kind_error(value)
|
115
110
|
end
|
116
111
|
|
117
|
-
def self.
|
118
|
-
__kind_error(Kind::Undefined) if value == Kind::Undefined
|
119
|
-
|
120
|
-
yield
|
121
|
-
end
|
112
|
+
def self.__kind; ::Module; end
|
122
113
|
|
123
114
|
def self.class?(value); Kind::Is.Module(value); end
|
124
115
|
|
@@ -128,7 +119,7 @@ module Kind
|
|
128
119
|
if ::Kind::Maybe::Value.none?(default)
|
129
120
|
__kind_undefined(value) { __kind_of(value) }
|
130
121
|
else
|
131
|
-
return value if
|
122
|
+
return value if Kind::Undefined != value && instance?(value)
|
132
123
|
|
133
124
|
__kind_undefined(default) { __kind_of(default) }
|
134
125
|
end
|
@@ -137,12 +128,16 @@ module Kind
|
|
137
128
|
def self.__is_instance__(value); class?(value); end
|
138
129
|
end)
|
139
130
|
|
131
|
+
def self.Module?(*args)
|
132
|
+
Kind::Of::Module.instance?(*args)
|
133
|
+
end
|
134
|
+
|
140
135
|
# -- Boolean
|
141
136
|
|
142
137
|
def self.Boolean(object = Undefined, options = Empty::HASH)
|
143
138
|
default = options[:or]
|
144
139
|
|
145
|
-
return Kind::Of::Boolean if
|
140
|
+
return Kind::Of::Boolean if Undefined == object && default.nil?
|
146
141
|
|
147
142
|
bool = object.nil? ? default : object
|
148
143
|
|
@@ -152,7 +147,7 @@ module Kind
|
|
152
147
|
end
|
153
148
|
|
154
149
|
const_set(:Boolean, ::Module.new do
|
155
|
-
extend
|
150
|
+
extend Checker::Protocol
|
156
151
|
|
157
152
|
def self.__kind; [TrueClass, FalseClass].freeze; end
|
158
153
|
|
@@ -164,14 +159,14 @@ module Kind
|
|
164
159
|
if ::Kind::Maybe::Value.none?(default)
|
165
160
|
__kind_undefined(value) { Kind::Of::Boolean(value) }
|
166
161
|
else
|
167
|
-
return value if
|
162
|
+
return value if Kind::Undefined != value && instance?(value)
|
168
163
|
|
169
164
|
__kind_undefined(default) { Kind::Of::Boolean(default) }
|
170
165
|
end
|
171
166
|
end
|
172
167
|
|
173
168
|
def self.__kind_undefined(value)
|
174
|
-
if
|
169
|
+
if Kind::Undefined == value
|
175
170
|
raise Kind::Error.new('Boolean'.freeze, Kind::Undefined)
|
176
171
|
else
|
177
172
|
yield
|
@@ -188,12 +183,16 @@ module Kind
|
|
188
183
|
end
|
189
184
|
end)
|
190
185
|
|
186
|
+
def self.Boolean?(*args)
|
187
|
+
Kind::Of::Boolean.instance?(*args)
|
188
|
+
end
|
189
|
+
|
191
190
|
# -- Lambda
|
192
191
|
|
193
192
|
def self.Lambda(object = Undefined, options = Empty::HASH)
|
194
193
|
default = options[:or]
|
195
194
|
|
196
|
-
return Kind::Of::Lambda if
|
195
|
+
return Kind::Of::Lambda if Undefined == object && default.nil?
|
197
196
|
|
198
197
|
func = object || default
|
199
198
|
|
@@ -203,7 +202,7 @@ module Kind
|
|
203
202
|
end
|
204
203
|
|
205
204
|
const_set(:Lambda, ::Module.new do
|
206
|
-
extend
|
205
|
+
extend Checker::Protocol
|
207
206
|
|
208
207
|
def self.__kind; ::Proc; end
|
209
208
|
|
@@ -213,14 +212,14 @@ module Kind
|
|
213
212
|
if ::Kind::Maybe::Value.none?(default)
|
214
213
|
__kind_undefined(value) { Kind::Of::Lambda(value) }
|
215
214
|
else
|
216
|
-
return value if
|
215
|
+
return value if Kind::Undefined != value && instance?(value)
|
217
216
|
|
218
217
|
__kind_undefined(default) { Kind::Of::Lambda(default) }
|
219
218
|
end
|
220
219
|
end
|
221
220
|
|
222
221
|
def self.__kind_undefined(value)
|
223
|
-
if
|
222
|
+
if Kind::Undefined == value
|
224
223
|
raise Kind::Error.new('Lambda'.freeze, Kind::Undefined)
|
225
224
|
else
|
226
225
|
yield
|
@@ -232,12 +231,16 @@ module Kind
|
|
232
231
|
end
|
233
232
|
end)
|
234
233
|
|
234
|
+
def self.Lambda?(*args)
|
235
|
+
Kind::Of::Lambda.instance?(*args)
|
236
|
+
end
|
237
|
+
|
235
238
|
# -- Callable
|
236
239
|
|
237
240
|
def self.Callable(object = Undefined, options = Empty::HASH)
|
238
241
|
default = options[:or]
|
239
242
|
|
240
|
-
return Kind::Of::Callable if
|
243
|
+
return Kind::Of::Callable if Undefined == object && default.nil?
|
241
244
|
|
242
245
|
callable = object || default
|
243
246
|
|
@@ -247,7 +250,7 @@ module Kind
|
|
247
250
|
end
|
248
251
|
|
249
252
|
const_set(:Callable, ::Module.new do
|
250
|
-
extend
|
253
|
+
extend Checker::Protocol
|
251
254
|
|
252
255
|
def self.__kind; Object; end
|
253
256
|
|
@@ -261,14 +264,14 @@ module Kind
|
|
261
264
|
if ::Kind::Maybe::Value.none?(default)
|
262
265
|
__kind_undefined(value) { Kind::Of::Callable(value) }
|
263
266
|
else
|
264
|
-
return value if
|
267
|
+
return value if Kind::Undefined != value && instance?(value)
|
265
268
|
|
266
269
|
__kind_undefined(default) { Kind::Of::Callable(default) }
|
267
270
|
end
|
268
271
|
end
|
269
272
|
|
270
273
|
def self.__kind_undefined(value)
|
271
|
-
if
|
274
|
+
if Kind::Undefined == value
|
272
275
|
raise Kind::Error.new('Callable'.freeze, Kind::Undefined)
|
273
276
|
else
|
274
277
|
yield
|
@@ -280,6 +283,10 @@ module Kind
|
|
280
283
|
end
|
281
284
|
end)
|
282
285
|
|
286
|
+
def self.Callable?(*args)
|
287
|
+
Kind::Of::Callable.instance?(*args)
|
288
|
+
end
|
289
|
+
|
283
290
|
# ---------------------- #
|
284
291
|
# Built-in type checkers #
|
285
292
|
# ---------------------- #
|
@@ -18,8 +18,8 @@ class KindValidator < ActiveModel::EachValidator
|
|
18
18
|
|
19
19
|
return validate_with_default_strategy(expected, value) if expected
|
20
20
|
|
21
|
-
return kind_of(expected, value) if expected = options[:of]
|
22
|
-
return
|
21
|
+
return kind_of(expected, value) if expected = options[:of]
|
22
|
+
return kind_is(expected, value) if expected = options[:is]
|
23
23
|
return respond_to(expected, value) if expected = options[:respond_to]
|
24
24
|
return instance_of(expected, value) if expected = options[:instance_of]
|
25
25
|
return array_with(expected, value) if expected = options[:array_with]
|
@@ -32,26 +32,38 @@ class KindValidator < ActiveModel::EachValidator
|
|
32
32
|
send(Kind::Validator.default_strategy, expected, value)
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
35
|
+
def kind_of(expected, value)
|
36
36
|
types = Array(expected)
|
37
37
|
|
38
|
-
return if types.any? { |type| value.
|
38
|
+
return if types.any? { |type| value.kind_of?(type) }
|
39
39
|
|
40
|
-
"must be
|
40
|
+
"must be a kind of: #{types.map { |klass| klass.name }.join(', ')}"
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
types = Array(expected)
|
43
|
+
CLASS_OR_MODULE = 'Class/Module'.freeze
|
45
44
|
|
46
|
-
|
45
|
+
def kind_is(expected, value)
|
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
|
+
|
50
|
+
result.empty? || result.size < expected.size ? nil : result.join(', ')
|
49
51
|
end
|
50
52
|
|
51
|
-
def
|
52
|
-
|
53
|
+
def kind_is_not(expected, value)
|
54
|
+
case expected
|
55
|
+
when Class
|
56
|
+
return if expected == Kind.of.Class(value) || value < expected
|
53
57
|
|
54
|
-
|
58
|
+
"must be the class or a subclass of `#{expected.name}`"
|
59
|
+
when Module
|
60
|
+
return if value.kind_of?(Class) && value <= expected
|
61
|
+
return if expected == Kind.of.Module(value) || value.kind_of?(expected)
|
62
|
+
|
63
|
+
"must include the `#{expected.name}` module"
|
64
|
+
else
|
65
|
+
raise Kind::Error.new(CLASS_OR_MODULE, expected)
|
66
|
+
end
|
55
67
|
end
|
56
68
|
|
57
69
|
def respond_to(method_name, value)
|
@@ -60,17 +72,25 @@ class KindValidator < ActiveModel::EachValidator
|
|
60
72
|
"must respond to the method `#{method_name}`"
|
61
73
|
end
|
62
74
|
|
63
|
-
def
|
75
|
+
def instance_of(expected, value)
|
64
76
|
types = Array(expected)
|
65
77
|
|
66
|
-
return if
|
78
|
+
return if types.any? { |type| value.instance_of?(type) }
|
67
79
|
|
68
|
-
"must be an
|
80
|
+
"must be an instance of: #{types.map { |klass| klass.name }.join(', ')}"
|
69
81
|
end
|
70
82
|
|
71
83
|
def array_with(expected, value)
|
72
|
-
return if value.
|
84
|
+
return if value.kind_of?(Array) && !value.empty? && (value - Kind.of.Array(expected)).empty?
|
73
85
|
|
74
86
|
"must be an array with: #{expected.join(', ')}"
|
75
87
|
end
|
88
|
+
|
89
|
+
def array_of(expected, value)
|
90
|
+
types = Array(expected)
|
91
|
+
|
92
|
+
return if value.kind_of?(Array) && !value.empty? && value.all? { |value| types.any? { |type| value.kind_of?(type) } }
|
93
|
+
|
94
|
+
"must be an array of: #{types.map { |klass| klass.name }.join(', ')}"
|
95
|
+
end
|
76
96
|
end
|
data/lib/kind/checker.rb
CHANGED
@@ -1,70 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'kind/checker/factory'
|
4
|
+
require 'kind/checker/protocol'
|
3
5
|
module Kind
|
4
|
-
module Checkable
|
5
|
-
def class?(value)
|
6
|
-
Kind::Is.__call__(__kind, value)
|
7
|
-
end
|
8
|
-
|
9
|
-
def instance(value, options = Empty::HASH)
|
10
|
-
default = options[:or]
|
11
|
-
|
12
|
-
return Kind::Of.(__kind, value) if ::Kind::Maybe::Value.none?(default)
|
13
|
-
|
14
|
-
value != Kind::Undefined && instance?(value) ? value : Kind::Of.(__kind, default)
|
15
|
-
end
|
16
|
-
|
17
|
-
def [](value, options = options = Empty::HASH)
|
18
|
-
instance(value, options)
|
19
|
-
end
|
20
|
-
|
21
|
-
def instance?(value = Kind::Undefined)
|
22
|
-
return __is_instance__(value) if value != Kind::Undefined
|
23
|
-
|
24
|
-
to_proc
|
25
|
-
end
|
26
|
-
|
27
|
-
def __is_instance__(value)
|
28
|
-
value.is_a?(__kind)
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_proc
|
32
|
-
@to_proc ||=
|
33
|
-
-> checker { -> value { checker.__is_instance__(value) } }.call(self)
|
34
|
-
end
|
35
|
-
|
36
|
-
def or_nil(value)
|
37
|
-
return value if instance?(value)
|
38
|
-
end
|
39
|
-
|
40
|
-
def or_undefined(value)
|
41
|
-
or_nil(value) || Kind::Undefined
|
42
|
-
end
|
43
|
-
|
44
|
-
def as_maybe(value = Kind::Undefined)
|
45
|
-
return __as_maybe__(value) if value != Kind::Undefined
|
46
|
-
|
47
|
-
as_maybe_to_proc
|
48
|
-
end
|
49
|
-
|
50
|
-
def as_optional(value = Kind::Undefined)
|
51
|
-
as_maybe(value)
|
52
|
-
end
|
53
|
-
|
54
|
-
def __as_maybe__(value)
|
55
|
-
Kind::Maybe.new(or_nil(value))
|
56
|
-
end
|
57
|
-
|
58
|
-
def as_maybe_to_proc
|
59
|
-
@as_maybe_to_proc ||=
|
60
|
-
-> checker { -> value { checker.__as_maybe__(value) } }.call(self)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
private_constant :Checkable
|
65
|
-
|
66
6
|
class Checker
|
67
|
-
include
|
7
|
+
include Protocol
|
68
8
|
|
69
9
|
attr_reader :__kind
|
70
10
|
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'singleton'
|
4
|
+
|
5
|
+
module Kind
|
6
|
+
class Checker
|
7
|
+
class Factory
|
8
|
+
include Singleton
|
9
|
+
|
10
|
+
def self.create(kind)
|
11
|
+
instance.create(kind)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
@__checkers__ = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
MODULE_OR_CLASS = 'Module/Class'.freeze
|
19
|
+
|
20
|
+
private_constant :MODULE_OR_CLASS
|
21
|
+
|
22
|
+
def create(kind)
|
23
|
+
@__checkers__[kind] ||= begin
|
24
|
+
kind_name = kind.name
|
25
|
+
|
26
|
+
if Kind::Of.const_defined?(kind_name, false)
|
27
|
+
Kind::Of.const_get(kind_name)
|
28
|
+
else
|
29
|
+
Kind::Checker.new(Kind::Of.(Module, kind, MODULE_OR_CLASS))
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|