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.
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 +6 -3
  5. data/CHANGELOG.md +1267 -0
  6. data/Gemfile +10 -2
  7. data/README.md +1005 -489
  8. data/lib/kind.rb +53 -281
  9. data/lib/kind/active_model/kind_validator.rb +20 -13
  10. data/lib/kind/core.rb +10 -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/core/wrong_number_of_args.rb +9 -0
  15. data/lib/kind/deprecations/built_in_type_checkers.rb +23 -0
  16. data/lib/kind/{checker.rb → deprecations/checker.rb} +3 -2
  17. data/lib/kind/{checker → deprecations/checker}/factory.rb +1 -5
  18. data/lib/kind/{checker → deprecations/checker}/protocol.rb +3 -3
  19. data/lib/kind/deprecations/is.rb +35 -0
  20. data/lib/kind/deprecations/of.rb +258 -0
  21. data/lib/kind/{types.rb → deprecations/types.rb} +14 -8
  22. data/lib/kind/dig.rb +40 -0
  23. data/lib/kind/empty.rb +5 -11
  24. data/lib/kind/error.rb +2 -6
  25. data/lib/kind/maybe.rb +14 -130
  26. data/lib/kind/maybe/none.rb +57 -0
  27. data/lib/kind/maybe/result.rb +51 -0
  28. data/lib/kind/maybe/some.rb +90 -0
  29. data/lib/kind/maybe/typed.rb +29 -0
  30. data/lib/kind/maybe/wrappable.rb +33 -0
  31. data/lib/kind/presence.rb +33 -0
  32. data/lib/kind/try.rb +34 -0
  33. data/lib/kind/type_checker.rb +87 -0
  34. data/lib/kind/type_checkers.rb +30 -0
  35. data/lib/kind/type_checkers/core/array.rb +17 -0
  36. data/lib/kind/type_checkers/core/class.rb +13 -0
  37. data/lib/kind/type_checkers/core/comparable.rb +13 -0
  38. data/lib/kind/type_checkers/core/enumerable.rb +13 -0
  39. data/lib/kind/type_checkers/core/enumerator.rb +13 -0
  40. data/lib/kind/type_checkers/core/file.rb +13 -0
  41. data/lib/kind/type_checkers/core/float.rb +13 -0
  42. data/lib/kind/type_checkers/core/hash.rb +17 -0
  43. data/lib/kind/type_checkers/core/integer.rb +13 -0
  44. data/lib/kind/type_checkers/core/io.rb +13 -0
  45. data/lib/kind/type_checkers/core/method.rb +13 -0
  46. data/lib/kind/type_checkers/core/module.rb +17 -0
  47. data/lib/kind/type_checkers/core/numeric.rb +13 -0
  48. data/lib/kind/type_checkers/core/proc.rb +13 -0
  49. data/lib/kind/type_checkers/core/queue.rb +14 -0
  50. data/lib/kind/type_checkers/core/range.rb +13 -0
  51. data/lib/kind/type_checkers/core/regexp.rb +13 -0
  52. data/lib/kind/type_checkers/core/string.rb +17 -0
  53. data/lib/kind/type_checkers/core/struct.rb +13 -0
  54. data/lib/kind/type_checkers/core/symbol.rb +13 -0
  55. data/lib/kind/type_checkers/core/time.rb +13 -0
  56. data/lib/kind/type_checkers/custom/boolean.rb +19 -0
  57. data/lib/kind/type_checkers/custom/callable.rb +19 -0
  58. data/lib/kind/type_checkers/custom/lambda.rb +19 -0
  59. data/lib/kind/type_checkers/stdlib/open_struct.rb +13 -0
  60. data/lib/kind/type_checkers/stdlib/set.rb +17 -0
  61. data/lib/kind/undefined.rb +4 -2
  62. data/lib/kind/validator.rb +1 -1
  63. data/lib/kind/version.rb +1 -1
  64. data/test.sh +4 -4
  65. metadata +53 -9
  66. data/lib/kind/is.rb +0 -19
  67. 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/error'
11
- require 'kind/of'
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
- def self.is(expected = Undefined, object = Undefined)
21
- return Is if Undefined == expected && Undefined == object
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
- return Kind::Is.(expected, object) if Undefined != object
24
-
25
- raise ArgumentError, WRONG_NUMBER_OF_ARGUMENTS
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
- Kind.of(kind).instance?(*args)
32
+ KIND.of?(kind, args)
38
33
  end
39
34
 
40
- # --------------------- #
41
- # Special type checkers #
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
- module Of
63
- # -- Class
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
- def self.Callable(object = Undefined, options = Empty::HASH)
241
- default = options[:or]
43
+ def self.respond_to(value, *method_names)
44
+ method_names.each { |method_name| KIND.respond_to!(method_name, value) }
242
45
 
243
- return Kind::Of::Callable if Undefined == object && default.nil?
46
+ value
47
+ end
244
48
 
245
- callable = object || default
49
+ def self.of_module_or_class(value)
50
+ KIND.of_module_or_class!(value)
51
+ end
246
52
 
247
- 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}')
248
56
 
249
- raise Kind::Error.new('Callable'.freeze, callable)
57
+ return Is
250
58
  end
251
59
 
252
- const_set(:Callable, ::Module.new do
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
- def self.instance(value, options = Empty::HASH)
262
- default = options[:or]
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
- def self.__kind_undefined(value)
274
- if Kind::Undefined == value
275
- raise Kind::Error.new('Callable'.freeze, Kind::Undefined)
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
- def self.__is_instance__(value);
282
- value.respond_to?(:call)
283
- end
284
- 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>)')
285
74
 
286
- def self.Callable?(*args)
287
- Kind::Of::Callable.instance?(*args)
75
+ Checker::Factory.create(kind)
288
76
  end
77
+ end
289
78
 
290
- # ---------------------- #
291
- # Built-in type checkers #
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
- Types.add(Kind::Maybe::Result, name: 'Maybe'.freeze)
312
- Types.add(Kind::Maybe::Result, name: 'Optional'.freeze)
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| value.kind_of?(type) }
38
+ return if types.any? { |type| type === value }
39
39
 
40
- "must be a kind of: #{types.map { |klass| klass.name }.join(', ')}"
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.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
@@ -66,10 +66,17 @@ class KindValidator < ActiveModel::EachValidator
66
66
  end
67
67
  end
68
68
 
69
- def respond_to(method_name, value)
70
- return if value.respond_to?(method_name)
69
+ def respond_to(expected, value)
70
+ method_names = Array(expected)
71
71
 
72
- "must respond to the method `#{method_name}`"
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.of.Array(expected)).empty?
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
data/lib/kind/core.rb ADDED
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Core
5
+ require 'kind/core/wrong_number_of_args'
6
+ require 'kind/core/deprecation'
7
+ require 'kind/core/kind'
8
+ require 'kind/core/undefined'
9
+ end
10
+ end