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.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -0
  3. data/.travis.sh +37 -12
  4. data/.travis.yml +10 -4
  5. data/CHANGELOG.md +1230 -0
  6. data/Gemfile +10 -2
  7. data/README.md +938 -460
  8. data/lib/kind.rb +52 -298
  9. data/lib/kind/active_model/kind_validator.rb +7 -7
  10. data/lib/kind/core.rb +9 -0
  11. data/lib/kind/core/deprecation.rb +29 -0
  12. data/lib/kind/core/kind.rb +61 -0
  13. data/lib/kind/core/undefined.rb +7 -0
  14. data/lib/kind/deprecations/built_in_type_checkers.rb +23 -0
  15. data/lib/kind/deprecations/checker.rb +16 -0
  16. data/lib/kind/deprecations/checker/factory.rb +31 -0
  17. data/lib/kind/deprecations/checker/protocol.rb +73 -0
  18. data/lib/kind/deprecations/is.rb +35 -0
  19. data/lib/kind/deprecations/of.rb +258 -0
  20. data/lib/kind/{types.rb → deprecations/types.rb} +15 -9
  21. data/lib/kind/dig.rb +40 -0
  22. data/lib/kind/empty.rb +5 -11
  23. data/lib/kind/error.rb +2 -6
  24. data/lib/kind/maybe.rb +22 -113
  25. data/lib/kind/maybe/none.rb +57 -0
  26. data/lib/kind/maybe/result.rb +51 -0
  27. data/lib/kind/maybe/some.rb +90 -0
  28. data/lib/kind/maybe/typed.rb +29 -0
  29. data/lib/kind/maybe/wrappable.rb +35 -0
  30. data/lib/kind/presence.rb +33 -0
  31. data/lib/kind/try.rb +36 -0
  32. data/lib/kind/type_checker.rb +73 -0
  33. data/lib/kind/type_checkers.rb +30 -0
  34. data/lib/kind/type_checkers/core/array.rb +17 -0
  35. data/lib/kind/type_checkers/core/class.rb +13 -0
  36. data/lib/kind/type_checkers/core/comparable.rb +13 -0
  37. data/lib/kind/type_checkers/core/enumerable.rb +13 -0
  38. data/lib/kind/type_checkers/core/enumerator.rb +13 -0
  39. data/lib/kind/type_checkers/core/file.rb +13 -0
  40. data/lib/kind/type_checkers/core/float.rb +13 -0
  41. data/lib/kind/type_checkers/core/hash.rb +17 -0
  42. data/lib/kind/type_checkers/core/integer.rb +13 -0
  43. data/lib/kind/type_checkers/core/io.rb +13 -0
  44. data/lib/kind/type_checkers/core/method.rb +13 -0
  45. data/lib/kind/type_checkers/core/module.rb +17 -0
  46. data/lib/kind/type_checkers/core/numeric.rb +13 -0
  47. data/lib/kind/type_checkers/core/proc.rb +13 -0
  48. data/lib/kind/type_checkers/core/queue.rb +14 -0
  49. data/lib/kind/type_checkers/core/range.rb +13 -0
  50. data/lib/kind/type_checkers/core/regexp.rb +13 -0
  51. data/lib/kind/type_checkers/core/string.rb +17 -0
  52. data/lib/kind/type_checkers/core/struct.rb +13 -0
  53. data/lib/kind/type_checkers/core/symbol.rb +13 -0
  54. data/lib/kind/type_checkers/core/time.rb +13 -0
  55. data/lib/kind/type_checkers/custom/boolean.rb +19 -0
  56. data/lib/kind/type_checkers/custom/callable.rb +19 -0
  57. data/lib/kind/type_checkers/custom/lambda.rb +19 -0
  58. data/lib/kind/type_checkers/stdlib/open_struct.rb +13 -0
  59. data/lib/kind/type_checkers/stdlib/set.rb +17 -0
  60. data/lib/kind/undefined.rb +4 -2
  61. data/lib/kind/validator.rb +1 -1
  62. data/lib/kind/version.rb +1 -1
  63. data/test.sh +4 -4
  64. metadata +52 -7
  65. data/lib/kind/checker.rb +0 -83
  66. data/lib/kind/is.rb +0 -19
  67. 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/error'
10
- require 'kind/of'
11
- require 'kind/is'
12
- require 'kind/checker'
13
- require 'kind/types'
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
- WRONG_NUMBER_OF_ARGUMENTS = 'wrong number of arguments (given 1, expected 2)'.freeze
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
- MODULE_OR_CLASS = 'Module/Class'.freeze
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
- __checkers__
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.of?(kind, *args)
55
- Kind.of(kind).instance?(*args)
39
+ def self.of_module?(value)
40
+ KIND.of_module?(value)
56
41
  end
57
42
 
58
- # --------------------- #
59
- # Special type checkers #
60
- # --------------------- #
43
+ def self.respond_to(value, *method_names)
44
+ method_names.each { |method_name| KIND.respond_to!(method_name, value) }
61
45
 
62
- module Is
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
- module Of
81
- # -- Class
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
- return callable if callable.respond_to?(:call)
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
- raise Kind::Error.new('Callable'.freeze, callable)
57
+ return Is
268
58
  end
269
59
 
270
- const_set(:Callable, ::Module.new do
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
- def self.instance(value, options = Empty::HASH)
280
- default = options[:or]
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
- def self.__kind_undefined(value)
292
- if Kind::Undefined == value
293
- raise Kind::Error.new('Callable'.freeze, Kind::Undefined)
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
- def self.__is_instance__(value);
300
- value.respond_to?(:call)
301
- end
302
- end)
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
- def self.Callable?(*args)
305
- Kind::Of::Callable.instance?(*args)
75
+ Checker::Factory.create(kind)
306
76
  end
77
+ end
307
78
 
308
- # ---------------------- #
309
- # Built-in type checkers #
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
- Types.add(Kind::Maybe::Result, name: 'Maybe'.freeze)
330
- Types.add(Kind::Maybe::Result, name: 'Optional'.freeze)
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.of.Class(value) || value < expected
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.of.Module(value) || value.kind_of?(expected)
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.of.Array(expected)).empty?
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,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Core
5
+ require 'kind/core/deprecation'
6
+ require 'kind/core/kind'
7
+ require 'kind/core/undefined'
8
+ end
9
+ end
@@ -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