kind 3.0.1 → 5.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 +42 -12
  4. data/.travis.yml +7 -5
  5. data/CHANGELOG.md +1309 -0
  6. data/Gemfile +22 -7
  7. data/README.md +990 -490
  8. data/kind.gemspec +1 -1
  9. data/lib/kind.rb +29 -292
  10. data/lib/kind/active_model/validation.rb +3 -4
  11. data/lib/kind/core.rb +15 -0
  12. data/lib/kind/core/dig.rb +40 -0
  13. data/lib/kind/core/empty.rb +13 -0
  14. data/lib/kind/core/empty/constant.rb +7 -0
  15. data/lib/kind/{error.rb → core/error.rb} +2 -6
  16. data/lib/kind/core/maybe.rb +42 -0
  17. data/lib/kind/core/maybe/none.rb +57 -0
  18. data/lib/kind/core/maybe/result.rb +51 -0
  19. data/lib/kind/core/maybe/some.rb +90 -0
  20. data/lib/kind/core/maybe/typed.rb +29 -0
  21. data/lib/kind/core/maybe/wrappable.rb +33 -0
  22. data/lib/kind/core/presence.rb +33 -0
  23. data/lib/kind/core/try.rb +34 -0
  24. data/lib/kind/core/type_checker.rb +87 -0
  25. data/lib/kind/core/type_checkers.rb +30 -0
  26. data/lib/kind/core/type_checkers/custom/boolean.rb +19 -0
  27. data/lib/kind/core/type_checkers/custom/callable.rb +19 -0
  28. data/lib/kind/core/type_checkers/custom/lambda.rb +19 -0
  29. data/lib/kind/core/type_checkers/ruby/array.rb +17 -0
  30. data/lib/kind/core/type_checkers/ruby/class.rb +13 -0
  31. data/lib/kind/core/type_checkers/ruby/comparable.rb +13 -0
  32. data/lib/kind/core/type_checkers/ruby/enumerable.rb +13 -0
  33. data/lib/kind/core/type_checkers/ruby/enumerator.rb +13 -0
  34. data/lib/kind/core/type_checkers/ruby/file.rb +13 -0
  35. data/lib/kind/core/type_checkers/ruby/float.rb +13 -0
  36. data/lib/kind/core/type_checkers/ruby/hash.rb +17 -0
  37. data/lib/kind/core/type_checkers/ruby/integer.rb +13 -0
  38. data/lib/kind/core/type_checkers/ruby/io.rb +13 -0
  39. data/lib/kind/core/type_checkers/ruby/method.rb +13 -0
  40. data/lib/kind/core/type_checkers/ruby/module.rb +17 -0
  41. data/lib/kind/core/type_checkers/ruby/numeric.rb +13 -0
  42. data/lib/kind/core/type_checkers/ruby/proc.rb +13 -0
  43. data/lib/kind/core/type_checkers/ruby/queue.rb +14 -0
  44. data/lib/kind/core/type_checkers/ruby/range.rb +13 -0
  45. data/lib/kind/core/type_checkers/ruby/regexp.rb +13 -0
  46. data/lib/kind/core/type_checkers/ruby/string.rb +17 -0
  47. data/lib/kind/core/type_checkers/ruby/struct.rb +13 -0
  48. data/lib/kind/core/type_checkers/ruby/symbol.rb +13 -0
  49. data/lib/kind/core/type_checkers/ruby/time.rb +13 -0
  50. data/lib/kind/core/type_checkers/stdlib/open_struct.rb +13 -0
  51. data/lib/kind/core/type_checkers/stdlib/set.rb +17 -0
  52. data/lib/kind/{undefined.rb → core/undefined.rb} +4 -2
  53. data/lib/kind/core/utils/kind.rb +61 -0
  54. data/lib/kind/core/utils/undefined.rb +7 -0
  55. data/lib/kind/validator.rb +108 -1
  56. data/lib/kind/version.rb +1 -1
  57. data/test.sh +4 -4
  58. metadata +50 -15
  59. data/lib/kind/active_model/kind_validator.rb +0 -96
  60. data/lib/kind/checker.rb +0 -15
  61. data/lib/kind/checker/factory.rb +0 -35
  62. data/lib/kind/checker/protocol.rb +0 -73
  63. data/lib/kind/empty.rb +0 -21
  64. data/lib/kind/is.rb +0 -19
  65. data/lib/kind/maybe.rb +0 -183
  66. data/lib/kind/of.rb +0 -11
  67. data/lib/kind/types.rb +0 -115
data/kind.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.description = %q{A simple type system (at runtime) for Ruby - free of dependencies.}
11
11
  spec.homepage = 'https://github.com/serradura/kind'
12
12
  spec.license = 'MIT'
13
- spec.required_ruby_version = Gem::Requirement.new('>= 2.2.0')
13
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.1.0')
14
14
 
15
15
  spec.metadata['homepage_uri'] = spec.homepage
16
16
  spec.metadata['source_code_uri'] = 'https://github.com/serradura/kind'
data/lib/kind.rb CHANGED
@@ -1,314 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'kind/version'
4
-
5
- require 'kind/empty'
6
- require 'kind/undefined'
7
- require 'kind/checker'
8
- require 'kind/maybe'
9
-
10
- require 'kind/error'
11
- require 'kind/of'
12
- require 'kind/is'
13
- require 'kind/types'
3
+ require 'set'
4
+ require 'ostruct'
14
5
 
15
6
  module Kind
16
- WRONG_NUMBER_OF_ARGUMENTS = 'wrong number of arguments (given 1, expected 2)'.freeze
17
-
18
- private_constant :WRONG_NUMBER_OF_ARGUMENTS
7
+ require 'kind/version'
8
+ require 'kind/core'
19
9
 
20
- def self.is(expected = Undefined, object = Undefined)
21
- return Is if Undefined == expected && Undefined == object
10
+ extend self
22
11
 
23
- return Kind::Is.(expected, object) if Undefined != object
24
-
25
- raise ArgumentError, WRONG_NUMBER_OF_ARGUMENTS
12
+ def is?(kind, arg)
13
+ KIND.is?(kind, arg)
26
14
  end
27
15
 
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
16
+ alias is is?
32
17
 
33
- Kind::Checker::Factory.create(kind)
18
+ def of?(kind, *args)
19
+ KIND.of?(kind, args)
34
20
  end
35
21
 
36
- def self.of?(kind, *args)
37
- Kind.of(kind).instance?(*args)
22
+ def of_class?(value)
23
+ KIND.of_class?(value)
38
24
  end
39
25
 
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
26
+ def of_module?(value)
27
+ KIND.of_module?(value)
60
28
  end
61
29
 
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
30
+ def respond_to(value, *method_names)
31
+ method_names.each { |method_name| KIND.respond_to!(method_name, value) }
155
32
 
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
239
-
240
- def self.Callable(object = Undefined, options = Empty::HASH)
241
- default = options[:or]
242
-
243
- return Kind::Of::Callable if Undefined == object && default.nil?
244
-
245
- callable = object || default
246
-
247
- return callable if callable.respond_to?(:call)
248
-
249
- raise Kind::Error.new('Callable'.freeze, callable)
250
- end
251
-
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
260
-
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
272
-
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
280
-
281
- def self.__is_instance__(value);
282
- value.respond_to?(:call)
283
- end
284
- end)
285
-
286
- def self.Callable?(*args)
287
- Kind::Of::Callable.instance?(*args)
288
- end
289
-
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) }
33
+ value
34
+ end
301
35
 
302
- Types.add(Queue, name: 'Queue'.freeze)
36
+ def of_module_or_class(value)
37
+ KIND.of_module_or_class!(value)
38
+ end
303
39
 
304
- # -- Modules
305
- [
306
- Enumerable, Comparable
307
- ].each { |klass| Types.add(klass) }
40
+ def of(kind, object)
41
+ KIND.of!(kind, object)
42
+ end
308
43
 
309
- # -- Kind::Of::Maybe
44
+ def value(kind, value, default:)
45
+ KIND.value(kind, value, of(kind, default))
46
+ end
310
47
 
311
- Types.add(Kind::Maybe::Result, name: 'Maybe'.freeze)
312
- Types.add(Kind::Maybe::Result, name: 'Optional'.freeze)
48
+ def Of(kind, opt = Empty::HASH)
49
+ TypeChecker::Object.new(kind, opt)
313
50
  end
314
51
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'kind'
3
+ warn '[DEPRECATION] "kind/active_model/validation" is deprecated; use "kind/validator" instead.' \
4
+ 'It will be removed on next major release.'
5
+
4
6
  require 'kind/validator'
5
- require 'active_model'
6
- require 'active_model/validations'
7
- require_relative 'kind_validator'
data/lib/kind/core.rb ADDED
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/core/utils/kind'
4
+ require 'kind/core/utils/undefined'
5
+
6
+ require 'kind/core/error'
7
+ require 'kind/core/empty'
8
+ require 'kind/core/dig'
9
+ require 'kind/core/try'
10
+ require 'kind/core/presence'
11
+ require 'kind/core/undefined'
12
+ require 'kind/core/maybe'
13
+
14
+ require 'kind/core/type_checker'
15
+ require 'kind/core/type_checkers'
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Dig
5
+ extend self
6
+
7
+ def call(data, keys)
8
+ return unless keys.kind_of?(::Array)
9
+
10
+ keys.reduce(data) do |memo, key|
11
+ value = get(memo, key)
12
+
13
+ break if KIND.null?(value)
14
+
15
+ value
16
+ end
17
+ end
18
+
19
+ def [](*keys)
20
+ ->(data) { call(data, keys) }
21
+ end
22
+
23
+ private
24
+
25
+ def get(data, key)
26
+ return data[key] if ::Hash === data
27
+
28
+ case data
29
+ when ::Array
30
+ data[key] if key.respond_to?(:to_int)
31
+ when ::OpenStruct
32
+ data[key] if key.respond_to?(:to_sym)
33
+ when ::Struct
34
+ data[key] rescue nil if key.respond_to?(:to_int) || key.respond_to?(:to_sym)
35
+ else
36
+ data.public_send(key) if key.respond_to?(:to_sym) && data.respond_to?(key)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Empty
5
+ SET = ::Set.new.freeze
6
+ HASH = {}.freeze
7
+ ARRAY = [].freeze
8
+ STRING = ''.freeze
9
+
10
+ ARY = ARRAY
11
+ STR = STRING
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ if defined?(Empty)
4
+ raise LoadError, "already initialized constant Empty"
5
+ else
6
+ Empty = Kind::Empty
7
+ end
@@ -2,12 +2,8 @@
2
2
 
3
3
  module Kind
4
4
  class Error < TypeError
5
- UNDEFINED_OBJECT = Object.new
6
-
7
- private_constant :UNDEFINED_OBJECT
8
-
9
- def initialize(arg, object = UNDEFINED_OBJECT)
10
- if UNDEFINED_OBJECT == object
5
+ def initialize(arg, object = UNDEFINED)
6
+ if UNDEFINED == object
11
7
  # Will be used when the exception was raised with a message. e.g:
12
8
  # raise Kind::Error, "some message"
13
9
  super(arg)