kind 3.1.0 → 5.2.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 (100) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -0
  3. data/.travis.sh +67 -12
  4. data/.travis.yml +7 -5
  5. data/CHANGELOG.md +1647 -0
  6. data/Gemfile +22 -7
  7. data/README.md +920 -486
  8. data/kind.gemspec +1 -1
  9. data/lib/kind.rb +2 -314
  10. data/lib/kind/__lib__/attributes.rb +66 -0
  11. data/lib/kind/__lib__/kind.rb +71 -0
  12. data/lib/kind/__lib__/undefined.rb +14 -0
  13. data/lib/kind/action.rb +92 -0
  14. data/lib/kind/active_model/validation.rb +3 -4
  15. data/lib/kind/basic.rb +73 -0
  16. data/lib/kind/basic/error.rb +29 -0
  17. data/lib/kind/{undefined.rb → basic/undefined.rb} +8 -1
  18. data/lib/kind/dig.rb +31 -11
  19. data/lib/kind/either.rb +30 -0
  20. data/lib/kind/either/left.rb +29 -0
  21. data/lib/kind/either/methods.rb +17 -0
  22. data/lib/kind/either/monad.rb +65 -0
  23. data/lib/kind/either/monad/wrapper.rb +19 -0
  24. data/lib/kind/either/right.rb +38 -0
  25. data/lib/kind/empty.rb +4 -10
  26. data/lib/kind/empty/constant.rb +7 -0
  27. data/lib/kind/enum.rb +63 -0
  28. data/lib/kind/enum/item.rb +40 -0
  29. data/lib/kind/enum/methods.rb +72 -0
  30. data/lib/kind/function.rb +47 -0
  31. data/lib/kind/functional.rb +89 -0
  32. data/lib/kind/functional/action.rb +89 -0
  33. data/lib/kind/immutable_attributes.rb +34 -0
  34. data/lib/kind/immutable_attributes/initializer.rb +70 -0
  35. data/lib/kind/immutable_attributes/reader.rb +38 -0
  36. data/lib/kind/maybe.rb +35 -159
  37. data/lib/kind/maybe/methods.rb +21 -0
  38. data/lib/kind/maybe/monad.rb +82 -0
  39. data/lib/kind/maybe/monad/wrapper.rb +19 -0
  40. data/lib/kind/maybe/none.rb +50 -0
  41. data/lib/kind/maybe/some.rb +132 -0
  42. data/lib/kind/maybe/typed.rb +35 -0
  43. data/lib/kind/maybe/wrapper.rb +37 -0
  44. data/lib/kind/monad.rb +22 -0
  45. data/lib/kind/monads.rb +5 -0
  46. data/lib/kind/objects.rb +17 -0
  47. data/lib/kind/objects/basic_object.rb +45 -0
  48. data/lib/kind/objects/modules.rb +32 -0
  49. data/lib/kind/objects/modules/core/array.rb +19 -0
  50. data/lib/kind/objects/modules/core/class.rb +13 -0
  51. data/lib/kind/objects/modules/core/comparable.rb +13 -0
  52. data/lib/kind/objects/modules/core/enumerable.rb +13 -0
  53. data/lib/kind/objects/modules/core/enumerator.rb +13 -0
  54. data/lib/kind/objects/modules/core/file.rb +13 -0
  55. data/lib/kind/objects/modules/core/float.rb +13 -0
  56. data/lib/kind/objects/modules/core/hash.rb +19 -0
  57. data/lib/kind/objects/modules/core/integer.rb +13 -0
  58. data/lib/kind/objects/modules/core/io.rb +13 -0
  59. data/lib/kind/objects/modules/core/method.rb +13 -0
  60. data/lib/kind/objects/modules/core/module.rb +17 -0
  61. data/lib/kind/objects/modules/core/numeric.rb +13 -0
  62. data/lib/kind/objects/modules/core/proc.rb +13 -0
  63. data/lib/kind/objects/modules/core/queue.rb +14 -0
  64. data/lib/kind/objects/modules/core/range.rb +13 -0
  65. data/lib/kind/objects/modules/core/regexp.rb +13 -0
  66. data/lib/kind/objects/modules/core/string.rb +19 -0
  67. data/lib/kind/objects/modules/core/struct.rb +13 -0
  68. data/lib/kind/objects/modules/core/symbol.rb +13 -0
  69. data/lib/kind/objects/modules/core/time.rb +13 -0
  70. data/lib/kind/objects/modules/custom/boolean.rb +19 -0
  71. data/lib/kind/objects/modules/custom/callable.rb +19 -0
  72. data/lib/kind/objects/modules/custom/lambda.rb +19 -0
  73. data/lib/kind/objects/modules/stdlib/open_struct.rb +15 -0
  74. data/lib/kind/objects/modules/stdlib/set.rb +19 -0
  75. data/lib/kind/objects/nil.rb +17 -0
  76. data/lib/kind/objects/not_nil.rb +13 -0
  77. data/lib/kind/objects/object.rb +56 -0
  78. data/lib/kind/objects/respond_to.rb +30 -0
  79. data/lib/kind/objects/union_type.rb +44 -0
  80. data/lib/kind/presence.rb +35 -0
  81. data/lib/kind/result.rb +31 -0
  82. data/lib/kind/result/abstract.rb +53 -0
  83. data/lib/kind/result/failure.rb +31 -0
  84. data/lib/kind/result/methods.rb +17 -0
  85. data/lib/kind/result/monad.rb +69 -0
  86. data/lib/kind/result/monad/wrapper.rb +19 -0
  87. data/lib/kind/result/success.rb +40 -0
  88. data/lib/kind/try.rb +46 -0
  89. data/lib/kind/validator.rb +112 -1
  90. data/lib/kind/version.rb +1 -1
  91. data/test.sh +4 -4
  92. metadata +81 -13
  93. data/lib/kind/active_model/kind_validator.rb +0 -96
  94. data/lib/kind/checker.rb +0 -15
  95. data/lib/kind/checker/factory.rb +0 -35
  96. data/lib/kind/checker/protocol.rb +0 -73
  97. data/lib/kind/error.rb +0 -19
  98. data/lib/kind/is.rb +0 -19
  99. data/lib/kind/of.rb +0 -11
  100. 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,316 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'kind/version'
4
-
5
- require 'ostruct'
6
-
7
- require 'kind/empty'
8
- require 'kind/undefined'
9
- require 'kind/checker'
10
- require 'kind/maybe'
11
-
12
- require 'kind/error'
13
- require 'kind/of'
14
- require 'kind/is'
15
- require 'kind/types'
16
-
17
- 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)
36
- end
37
-
38
- def self.of?(kind, *args)
39
- Kind.of(kind).instance?(*args)
40
- end
41
-
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
62
- end
63
-
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
241
-
242
- def self.Callable(object = Undefined, options = Empty::HASH)
243
- default = options[:or]
244
-
245
- return Kind::Of::Callable if Undefined == object && default.nil?
246
-
247
- callable = object || default
248
-
249
- return callable if callable.respond_to?(:call)
250
-
251
- raise Kind::Error.new('Callable'.freeze, callable)
252
- end
253
-
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
262
-
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
274
-
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
282
-
283
- def self.__is_instance__(value);
284
- value.respond_to?(:call)
285
- end
286
- end)
287
-
288
- def self.Callable?(*args)
289
- Kind::Of::Callable.instance?(*args)
290
- end
291
-
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
312
-
313
- Types.add(Kind::Maybe::Result, name: 'Maybe'.freeze)
314
- Types.add(Kind::Maybe::Result, name: 'Optional'.freeze)
315
- end
316
- end
3
+ require 'kind/basic'
4
+ require 'kind/objects'
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind/__lib__/kind'
4
+ require 'kind/__lib__/undefined'
5
+
6
+ module Kind
7
+ module ATTRIBUTES
8
+ extend self
9
+
10
+ def name!(name)
11
+ KIND.of!(::Symbol, name)
12
+ end
13
+
14
+ def value(kind, default, visibility = :private)
15
+ [kind, default, visibility]
16
+ end
17
+
18
+ def value_to_assign(kind, default, hash, name)
19
+ raw_value = hash[name]
20
+
21
+ return raw_value if kind.nil? && UNDEFINED == default
22
+
23
+ value = resolve_value_to_assign(kind, default, raw_value)
24
+
25
+ (kind.nil? || kind === value) ? value : nil
26
+ end
27
+
28
+ def value!(kind, default)
29
+ return value(kind, default) unless kind.nil?
30
+
31
+ raise Error.new("kind expected to not be nil")
32
+ end
33
+
34
+ def value_to_assign!(kind, default, hash, name)
35
+ value = resolve_value_to_assign(kind, default, hash[name])
36
+
37
+ Kind.of(kind, value, label: name)
38
+ end
39
+
40
+ private
41
+
42
+ def resolve_value_to_assign(kind, default, value)
43
+ if kind == ::Proc
44
+ UNDEFINED == default ? value : KIND.value(kind, value, default)
45
+ else
46
+ default_is_a_callable = default.respond_to?(:call)
47
+
48
+ default_value =
49
+ if default_is_a_callable
50
+ default_fn = Proc === default ? default : default.method(:call)
51
+
52
+ default_fn.arity != 0 ? default_fn.call(value) : default_fn.call
53
+ else
54
+ default
55
+ end
56
+
57
+ return value if UNDEFINED == default_value
58
+ return default_value || value if kind.nil?
59
+
60
+ default_is_a_callable ? KIND.value(kind, default_value, value) : KIND.value(kind, value, default_value)
61
+ end
62
+ end
63
+ end
64
+
65
+ private_constant :ATTRIBUTES
66
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module KIND
5
+ extend self
6
+
7
+ def null?(value) # :nodoc:
8
+ value.nil? || Undefined == value
9
+ end
10
+
11
+ def of?(kind, values) # :nodoc:
12
+ of_kind = -> value { kind === value }
13
+
14
+ values.empty? ? of_kind : values.all?(&of_kind)
15
+ end
16
+
17
+ def of!(kind, value, kind_name = nil) # :nodoc:
18
+ return value if kind === value
19
+
20
+ error!(kind_name || kind.name, value)
21
+ end
22
+
23
+ def error!(kind_name, value, label = nil) # :nodoc:
24
+ raise Error.new(kind_name, value, label: label)
25
+ end
26
+
27
+ def of_class?(value) # :nodoc:
28
+ value.kind_of?(::Class)
29
+ end
30
+
31
+ def of_module?(value) # :nodoc:
32
+ ::Module == value || (value.kind_of?(::Module) && !of_class?(value))
33
+ end
34
+
35
+ def of_module_or_class!(value) # :nodoc:
36
+ of!(::Module, value, 'Module/Class')
37
+ end
38
+
39
+ def respond_to!(method_name, value) # :nodoc:
40
+ return value if value.respond_to?(method_name)
41
+
42
+ raise Error.new("expected #{value} to respond to :#{method_name}")
43
+ end
44
+
45
+ def interface?(method_names, value) # :nodoc:
46
+ method_names.all? { |method_name| value.respond_to?(method_name) }
47
+ end
48
+
49
+ def value(kind, arg, default) # :nodoc:
50
+ kind === arg ? arg : default
51
+ end
52
+
53
+ def is?(expected, value) # :nodoc:
54
+ is(of_module_or_class!(expected), value)
55
+ end
56
+
57
+ private
58
+
59
+ def is(expected_kind, value) # :nodoc:
60
+ kind = of_module_or_class!(value)
61
+
62
+ if of_class?(kind)
63
+ kind <= expected_kind || expected_kind == ::Class
64
+ else
65
+ kind == expected_kind || kind.kind_of?(expected_kind)
66
+ end
67
+ end
68
+ end
69
+
70
+ private_constant :KIND
71
+ end