kind 3.1.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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -0
  3. data/.travis.sh +37 -12
  4. data/.travis.yml +6 -3
  5. data/CHANGELOG.md +1230 -0
  6. data/Gemfile +10 -2
  7. data/README.md +817 -487
  8. data/lib/kind.rb +53 -283
  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/{checker.rb → deprecations/checker.rb} +3 -2
  16. data/lib/kind/{checker → deprecations/checker}/factory.rb +1 -5
  17. data/lib/kind/{checker → deprecations/checker}/protocol.rb +3 -3
  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} +14 -8
  21. data/lib/kind/dig.rb +13 -9
  22. data/lib/kind/empty.rb +5 -11
  23. data/lib/kind/error.rb +2 -6
  24. data/lib/kind/maybe.rb +12 -161
  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 +51 -9
  65. data/lib/kind/is.rb +0 -19
  66. data/lib/kind/of.rb +0 -11
data/lib/kind.rb CHANGED
@@ -1,316 +1,86 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'kind/version'
4
-
3
+ require 'set'
5
4
  require 'ostruct'
6
5
 
6
+ require 'kind/version'
7
+ require 'kind/core'
8
+
9
+ require 'kind/error'
7
10
  require 'kind/empty'
11
+ require 'kind/dig'
12
+ require 'kind/try'
13
+ require 'kind/presence'
8
14
  require 'kind/undefined'
9
- require 'kind/checker'
15
+ require 'kind/type_checker'
16
+
17
+ require 'kind/type_checkers'
10
18
  require 'kind/maybe'
11
19
 
12
- require 'kind/error'
13
- require 'kind/of'
14
- require 'kind/is'
15
- 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'
16
25
 
17
26
  module Kind
18
- WRONG_NUMBER_OF_ARGUMENTS = 'wrong number of arguments (given 1, expected 2)'.freeze
19
-
20
- private_constant :WRONG_NUMBER_OF_ARGUMENTS
21
-
22
- def self.is(expected = Undefined, object = Undefined)
23
- return Is if Undefined == expected && Undefined == object
24
-
25
- return Kind::Is.(expected, object) if Undefined != object
26
-
27
- raise ArgumentError, WRONG_NUMBER_OF_ARGUMENTS
28
- end
29
-
30
- def self.of(kind = Undefined, object = Undefined)
31
- return Of if Undefined == kind && Undefined == object
32
-
33
- return Kind::Of.(kind, object) if Undefined != object
34
-
35
- Kind::Checker::Factory.create(kind)
27
+ def self.is?(kind, arg)
28
+ KIND.is?(kind, arg)
36
29
  end
37
30
 
38
31
  def self.of?(kind, *args)
39
- Kind.of(kind).instance?(*args)
32
+ KIND.of?(kind, args)
40
33
  end
41
34
 
42
- # --------------------- #
43
- # Special type checkers #
44
- # --------------------- #
45
-
46
- module Is
47
- def self.Class(value)
48
- value.kind_of?(::Class)
49
- end
50
-
51
- def self.Module(value)
52
- ::Module == value || (value.is_a?(::Module) && !self.Class(value))
53
- end
54
-
55
- def self.Boolean(value)
56
- Kind.of.Class(value) <= TrueClass || value <= FalseClass
57
- end
58
-
59
- def self.Callable(value)
60
- value.respond_to?(:call)
61
- end
35
+ def self.of_class?(value)
36
+ KIND.of_class?(value)
62
37
  end
63
38
 
64
- module Of
65
- # -- Class
66
-
67
- def self.Class(object = Undefined)
68
- return Class if Undefined == object
69
-
70
- self.call(::Class, object)
71
- end
72
-
73
- const_set(:Class, ::Module.new do
74
- extend Checker::Protocol
75
-
76
- def self.__kind; ::Class; end
77
-
78
- def self.class?(value); Kind::Is.Class(value); end
79
-
80
- def self.__is_instance__(value); class?(value); end
81
- end)
82
-
83
- def self.Class?(*args)
84
- Kind::Of::Class.instance?(*args)
85
- end
86
-
87
- # -- Module
88
-
89
- def self.Module(object = Undefined)
90
- return Module if Undefined == object
91
-
92
- self.call(::Module, object)
93
- end
94
-
95
- const_set(:Module, ::Module.new do
96
- extend Checker::Protocol
97
-
98
- def self.__kind_undefined(value)
99
- __kind_error(Kind::Undefined) if Kind::Undefined == value
100
-
101
- yield
102
- end
103
-
104
- def self.__kind_error(value)
105
- raise Kind::Error.new('Module'.freeze, value)
106
- end
107
-
108
- def self.__kind_of(value)
109
- return value if Kind::Is.Module(value)
110
-
111
- __kind_error(value)
112
- end
113
-
114
- def self.__kind; ::Module; end
115
-
116
- def self.class?(value); Kind::Is.Module(value); end
117
-
118
- def self.instance(value, options = Empty::HASH)
119
- default = options[:or]
120
-
121
- if ::Kind::Maybe::Value.none?(default)
122
- __kind_undefined(value) { __kind_of(value) }
123
- else
124
- return value if Kind::Undefined != value && instance?(value)
125
-
126
- __kind_undefined(default) { __kind_of(default) }
127
- end
128
- end
129
-
130
- def self.__is_instance__(value); class?(value); end
131
- end)
132
-
133
- def self.Module?(*args)
134
- Kind::Of::Module.instance?(*args)
135
- end
136
-
137
- # -- Boolean
138
-
139
- def self.Boolean(object = Undefined, options = Empty::HASH)
140
- default = options[:or]
141
-
142
- return Kind::Of::Boolean if Undefined == object && default.nil?
143
-
144
- bool = object.nil? ? default : object
145
-
146
- return bool if bool.is_a?(::TrueClass) || bool.is_a?(::FalseClass)
147
-
148
- raise Kind::Error.new('Boolean'.freeze, bool)
149
- end
150
-
151
- const_set(:Boolean, ::Module.new do
152
- extend Checker::Protocol
153
-
154
- def self.__kind; [TrueClass, FalseClass].freeze; end
155
-
156
- def self.class?(value); Kind.is.Boolean(value); end
157
-
158
- def self.instance(value, options= Empty::HASH)
159
- default = options[:or]
160
-
161
- if ::Kind::Maybe::Value.none?(default)
162
- __kind_undefined(value) { Kind::Of::Boolean(value) }
163
- else
164
- return value if Kind::Undefined != value && instance?(value)
165
-
166
- __kind_undefined(default) { Kind::Of::Boolean(default) }
167
- end
168
- end
169
-
170
- def self.__kind_undefined(value)
171
- if Kind::Undefined == value
172
- raise Kind::Error.new('Boolean'.freeze, Kind::Undefined)
173
- else
174
- yield
175
- end
176
- end
177
-
178
- def self.__is_instance__(value);
179
- value.is_a?(TrueClass) || value.is_a?(FalseClass)
180
- end
181
-
182
- def self.or_undefined(value)
183
- result = or_nil(value)
184
- result.nil? ? Kind::Undefined : result
185
- end
186
- end)
187
-
188
- def self.Boolean?(*args)
189
- Kind::Of::Boolean.instance?(*args)
190
- end
191
-
192
- # -- Lambda
193
-
194
- def self.Lambda(object = Undefined, options = Empty::HASH)
195
- default = options[:or]
196
-
197
- return Kind::Of::Lambda if Undefined == object && default.nil?
198
-
199
- func = object || default
200
-
201
- return func if func.is_a?(::Proc) && func.lambda?
202
-
203
- raise Kind::Error.new('Lambda'.freeze, func)
204
- end
205
-
206
- const_set(:Lambda, ::Module.new do
207
- extend Checker::Protocol
208
-
209
- def self.__kind; ::Proc; end
210
-
211
- def self.instance(value, options = Empty::HASH)
212
- default = options[:or]
213
-
214
- if ::Kind::Maybe::Value.none?(default)
215
- __kind_undefined(value) { Kind::Of::Lambda(value) }
216
- else
217
- return value if Kind::Undefined != value && instance?(value)
218
-
219
- __kind_undefined(default) { Kind::Of::Lambda(default) }
220
- end
221
- end
222
-
223
- def self.__kind_undefined(value)
224
- if Kind::Undefined == value
225
- raise Kind::Error.new('Lambda'.freeze, Kind::Undefined)
226
- else
227
- yield
228
- end
229
- end
230
-
231
- def self.__is_instance__(value)
232
- value.is_a?(__kind) && value.lambda?
233
- end
234
- end)
235
-
236
- def self.Lambda?(*args)
237
- Kind::Of::Lambda.instance?(*args)
238
- end
239
-
240
- # -- Callable
39
+ def self.of_module?(value)
40
+ KIND.of_module?(value)
41
+ end
241
42
 
242
- def self.Callable(object = Undefined, options = Empty::HASH)
243
- default = options[:or]
43
+ def self.respond_to(value, *method_names)
44
+ method_names.each { |method_name| KIND.respond_to!(method_name, value) }
244
45
 
245
- return Kind::Of::Callable if Undefined == object && default.nil?
46
+ value
47
+ end
246
48
 
247
- callable = object || default
49
+ def self.of_module_or_class(value)
50
+ KIND.of_module_or_class!(value)
51
+ end
248
52
 
249
- 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}')
250
56
 
251
- raise Kind::Error.new('Callable'.freeze, callable)
57
+ return Is
252
58
  end
253
59
 
254
- const_set(:Callable, ::Module.new do
255
- extend Checker::Protocol
256
-
257
- def self.__kind; Object; end
258
-
259
- def self.class?(value)
260
- Kind::Is::Callable(value)
261
- end
60
+ return is?(expected, object) if UNDEFINED != object
262
61
 
263
- def self.instance(value, options = Empty::HASH)
264
- default = options[:or]
265
-
266
- if ::Kind::Maybe::Value.none?(default)
267
- __kind_undefined(value) { Kind::Of::Callable(value) }
268
- else
269
- return value if Kind::Undefined != value && instance?(value)
270
-
271
- __kind_undefined(default) { Kind::Of::Callable(default) }
272
- end
273
- end
62
+ raise ArgumentError, 'wrong number of arguments (given 1, expected 2)'
63
+ end
274
64
 
275
- def self.__kind_undefined(value)
276
- if Kind::Undefined == value
277
- raise Kind::Error.new('Callable'.freeze, Kind::Undefined)
278
- else
279
- yield
280
- end
281
- 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}')
282
68
 
283
- def self.__is_instance__(value);
284
- value.respond_to?(:call)
285
- end
286
- 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>)')
287
74
 
288
- def self.Callable?(*args)
289
- Kind::Of::Callable.instance?(*args)
75
+ Checker::Factory.create(kind)
290
76
  end
77
+ end
291
78
 
292
- # ---------------------- #
293
- # Built-in type checkers #
294
- # ---------------------- #
295
-
296
- # -- Classes
297
- [
298
- String, Symbol, Numeric, Integer, Float, Regexp, Time,
299
- Array, Range, Hash, Struct, Enumerator, Set, OpenStruct,
300
- Method, Proc,
301
- IO, File
302
- ].each { |klass| Types.add(klass) }
303
-
304
- Types.add(Queue, name: 'Queue'.freeze)
305
-
306
- # -- Modules
307
- [
308
- Enumerable, Comparable
309
- ].each { |klass| Types.add(klass) }
310
-
311
- # -- Kind::Of::Maybe
79
+ def self.value(kind, value, default:)
80
+ KIND.value(kind, value, of(kind, default))
81
+ end
312
82
 
313
- Types.add(Kind::Maybe::Result, name: 'Maybe'.freeze)
314
- Types.add(Kind::Maybe::Result, name: 'Optional'.freeze)
83
+ def self.Of(kind, opt = Empty::HASH)
84
+ TypeChecker::Object.new(kind, opt)
315
85
  end
316
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