kind 3.0.1 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
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)