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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31c64b5797c2bc7b2b1da5a704af8f66ddd34773296a8f5b70fc92ffd8b66246
4
- data.tar.gz: ceac47580bc50b6f7b346193ec2c8d9429c7e26726219ee45ea8a5b56051a8e0
3
+ metadata.gz: 0115f034c70fde8d181ffb42e0d2fddb0bb7376e84120d8f7017ce9708ccab53
4
+ data.tar.gz: 1e24f96749ad14ce29bf86314423be332a7a424ff9c562e7451d2ab0d08a7fef
5
5
  SHA512:
6
- metadata.gz: b94da43b377655485792594548f3a8d2e321ce313cd88ef6ff7b9bca1fba2411a602eaba99b2fa6be0d28e4054242ca0bc19c51df8ea7c08898455a09c0b345a
7
- data.tar.gz: c1ac05bf6246d5a9f10f80bdec7adab1c62b87bc40bd0d9e57b9532e5de2c8598bf97de1f12d062d31e494543a87b4b68410c2581adb9ddbbf12088d2e100427
6
+ metadata.gz: 675a83c3e389538b39d75772b55b5f0ce179b2bedd3234ee973865312aa9bbe8e681350412597bca0ce3e7842878f27004139b88c2b8489c0c27f4d1cd6238fd
7
+ data.tar.gz: 03d5592c9bd8eaa9591aa7b914feae2ab60678ead26aba64f7f175c673e26a584c2d3fd32bec20fb868c28e101f96e0a2bcf5e14effb15148cb905b4ca8b548d
data/.tool-versions ADDED
@@ -0,0 +1 @@
1
+ ruby 2.7.2
data/.travis.sh CHANGED
@@ -1,20 +1,50 @@
1
1
  #!/bin/bash
2
2
 
3
- bundle exec rake test
3
+ RUBY_V=$(ruby -v)
4
4
 
5
- ruby_v=$(ruby -v)
5
+ function run_with_bundler {
6
+ rm Gemfile.lock
6
7
 
7
- ACTIVEMODEL_VERSION='3.2' bundle update && bundle exec rake test
8
- ACTIVEMODEL_VERSION='4.0' bundle update && bundle exec rake test
9
- ACTIVEMODEL_VERSION='4.1' bundle update && bundle exec rake test
10
- ACTIVEMODEL_VERSION='4.2' bundle update && bundle exec rake test
11
- ACTIVEMODEL_VERSION='5.0' bundle update && bundle exec rake test
12
- ACTIVEMODEL_VERSION='5.1' bundle update && bundle exec rake test
8
+ if [ ! -z "$1" ]; then
9
+ bundle_cmd="bundle _$1_"
10
+ else
11
+ bundle_cmd="bundle"
12
+ fi
13
13
 
14
- if [[ ! $ruby_v =~ '2.2.0' ]]; then
15
- ACTIVEMODEL_VERSION='5.2' bundle update && bundle exec rake test
14
+ eval "$2 $bundle_cmd update"
15
+ eval "$2 $bundle_cmd exec rake test"
16
+ }
17
+
18
+ function run_with_am_version_and_bundler {
19
+ run_with_bundler "$2" "ACTIVEMODEL_VERSION=$1"
20
+ }
21
+
22
+ if [[ $RUBY_V =~ "ruby 2.[12]." ]]; then
23
+ run_with_bundler "$BUNDLER_V1"
24
+
25
+ run_with_am_version_and_bundler "3.2" "$BUNDLER_V1"
16
26
  fi
17
27
 
18
- if [[ $ruby_v =~ '2.5.' ]] || [[ $ruby_v =~ '2.6.' ]] || [[ $ruby_v =~ '2.7.' ]]; then
19
- ACTIVEMODEL_VERSION='6.0' bundle update && bundle exec rake test
28
+ RUBY_2_2345="ruby 2.[2345]."
29
+
30
+ if [[ $RUBY_V =~ $RUBY_2_2345 ]]; then
31
+ run_with_bundler "$BUNDLER_V1"
32
+
33
+ run_with_am_version_and_bundler "4.0" "$BUNDLER_V1"
34
+ run_with_am_version_and_bundler "4.1" "$BUNDLER_V1"
35
+ run_with_am_version_and_bundler "4.2" "$BUNDLER_V1"
36
+ run_with_am_version_and_bundler "5.0" "$BUNDLER_V1"
37
+ run_with_am_version_and_bundler "5.1" "$BUNDLER_V1"
38
+ run_with_am_version_and_bundler "5.2" "$BUNDLER_V1"
39
+ fi
40
+
41
+ RUBY_2_567="ruby 2.[567]."
42
+ RUBY_3_x_x="ruby 3.0."
43
+
44
+ if [[ $RUBY_V =~ $RUBY_2_567 ]] || [[ $RUBY_V =~ $RUBY_3_x_x ]]; then
45
+ gem install bundler -v ">= 2" --no-doc
46
+
47
+ run_with_bundler
48
+ run_with_am_version_and_bundler "6.0"
49
+ run_with_am_version_and_bundler "6.1"
20
50
  fi
data/.travis.yml CHANGED
@@ -1,24 +1,26 @@
1
1
  ---
2
2
  language: ruby
3
3
 
4
- sudo: false
5
-
6
4
  cache:
7
5
  bundler: true
8
6
  directories:
9
7
  - /home/travis/.rvm/
10
8
 
11
9
  rvm:
12
- - 2.2.0
10
+ - 2.1.10
11
+ - 2.2.2
13
12
  - 2.3.0
14
13
  - 2.4.0
15
14
  - 2.5.0
16
15
  - 2.6.0
17
16
  - 2.7.0
17
+ - 3.0.0
18
+
19
+ env:
20
+ - BUNDLER_V1="1.17.3"
18
21
 
19
22
  before_install:
20
- - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
21
- - gem install bundler -v '< 2'
23
+ - gem install bundler -v "$BUNDLER_V1"
22
24
 
23
25
  install: bundle install --jobs=3 --retry=3
24
26
 
data/CHANGELOG.md ADDED
@@ -0,0 +1,1309 @@
1
+ # Changelog <!-- omit in toc -->
2
+
3
+ This project follows [semver 2.0.0](http://semver.org/spec/v2.0.0.html) and the recommendations of [keepachangelog.com](http://keepachangelog.com/).
4
+
5
+ - [Unreleased](#unreleased)
6
+ - [5.1.0 (2021-02-23)](#510-2021-02-23)
7
+ - [Added](#added)
8
+ - [Deprecated](#deprecated)
9
+ - [5.0.0 (2021-02-22)](#500-2021-02-22)
10
+ - [Breaking Changes](#breaking-changes)
11
+ - [Removed](#removed)
12
+ - [4.1.0 (2021-02-22)](#410-2021-02-22)
13
+ - [Added](#added-1)
14
+ - [4.0.0 (2021-02-22)](#400-2021-02-22)
15
+ - [Added](#added-2)
16
+ - [Deprecated](#deprecated-1)
17
+ - [Fixed](#fixed)
18
+ - [3.1.0 (2020-07-08)](#310-2020-07-08)
19
+ - [Added](#added-3)
20
+ - [3.0.0 (2020-06-25)](#300-2020-06-25)
21
+ - [Breaking Changes](#breaking-changes-1)
22
+ - [Added](#added-4)
23
+ - [2.3.0 (2020-06-24)](#230-2020-06-24)
24
+ - [Added](#added-5)
25
+ - [2.2.0 (2020-06-23)](#220-2020-06-23)
26
+ - [Added](#added-6)
27
+ - [2.1.0 (2020-05-12)](#210-2020-05-12)
28
+ - [Added](#added-7)
29
+ - [Breaking Changes](#breaking-changes-2)
30
+ - [2.0.0 (2020-05-07)](#200-2020-05-07)
31
+ - [Added](#added-8)
32
+ - [Breaking Changes](#breaking-changes-3)
33
+ - [Removed](#removed-1)
34
+ - [1.9.0 (2020-05-06)](#190-2020-05-06)
35
+ - [Added](#added-9)
36
+ - [1.8.0 (2020-05-03)](#180-2020-05-03)
37
+ - [Added](#added-10)
38
+ - [1.7.0 (2020-05-03)](#170-2020-05-03)
39
+ - [Fixed](#fixed-1)
40
+ - [1.6.0 (2020-04-17)](#160-2020-04-17)
41
+ - [Added](#added-11)
42
+ - [Changes](#changes)
43
+ - [1.5.0 (2020-04-12)](#150-2020-04-12)
44
+ - [Added](#added-12)
45
+ - [1.4.0 (2020-04-12)](#140-2020-04-12)
46
+ - [Added](#added-13)
47
+ - [1.3.0 (2020-04-12)](#130-2020-04-12)
48
+ - [Added](#added-14)
49
+ - [1.2.0 (2020-04-12)](#120-2020-04-12)
50
+ - [Added](#added-15)
51
+ - [1.1.0 (2020-04-09)](#110-2020-04-09)
52
+ - [Added](#added-16)
53
+ - [Fixed](#fixed-2)
54
+ - [1.0.0 (2020-03-16)](#100-2020-03-16)
55
+ - [Added](#added-17)
56
+ - [0.6.0 (2020-01-06)](#060-2020-01-06)
57
+ - [Added](#added-18)
58
+ - [0.5.0 (2020-01-04)](#050-2020-01-04)
59
+ - [Added](#added-19)
60
+ - [0.4.0 (2020-01-03)](#040-2020-01-03)
61
+ - [Added](#added-20)
62
+ - [0.3.0 (2020-01-03)](#030-2020-01-03)
63
+ - [Added](#added-21)
64
+ - [Breaking Changes](#breaking-changes-4)
65
+ - [0.2.0 (2020-01-02)](#020-2020-01-02)
66
+ - [Added](#added-22)
67
+ - [0.1.0 (2019-12-26)](#010-2019-12-26)
68
+ - [Added](#added-23)
69
+
70
+ ## Unreleased
71
+
72
+ <!--
73
+ ### Added
74
+ ### Breaking Changes
75
+ ### Deprecated
76
+ ### Removed
77
+ ### Fixed
78
+ -->
79
+
80
+ 5.1.0 (2021-02-23)
81
+ ------------------
82
+
83
+ ### Added
84
+
85
+ * [#45](https://github.com/serradura/kind/pull/45) - Add support to Ruby `>= 2.1.0`.
86
+
87
+ ### Deprecated
88
+
89
+ * [#45](https://github.com/serradura/kind/pull/45) - `kind/active_model/validation` is deprecated; use `kind/validator` instead.
90
+
91
+ 5.0.0 (2021-02-22)
92
+ ------------------
93
+
94
+ ### Breaking Changes
95
+
96
+ * [#44](https://github.com/serradura/kind/pull/44) - Now, do you need to require `"kind/empty/constant"` to define the constant `Empty` as a `Kind::Empty` alias.
97
+
98
+ ### Removed
99
+
100
+ * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Is.call`
101
+
102
+ * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Of.call`
103
+
104
+ * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Types.add`.
105
+
106
+ * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Of::<Type>` and `Kind::Is::<Type>` modules.
107
+
108
+ * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Checker`, `Kind::Checker::Protocol`, `Kind::Checker::Factory`.
109
+
110
+ * [#44](https://github.com/serradura/kind/pull/44) - Remove the invocation of `Kind.is` without arguments.
111
+
112
+ * [#44](https://github.com/serradura/kind/pull/44) - Remove the invocation of `Kind.of` without arguments.
113
+
114
+ * [#44](https://github.com/serradura/kind/pull/44) - Remove the invocation of `Kind.of` with a single argument (the kind).
115
+
116
+ 4.1.0 (2021-02-22)
117
+ ------------------
118
+
119
+ ### Added
120
+
121
+ * [#43](https://github.com/serradura/kind/pull/43) - Make `Kind::Maybe::Typed` verify the kind of the value via `===`, because of this, now is possible to use type checkers in typed Maybes.
122
+ ```ruby
123
+ Kind::Maybe(Kind::Boolean).wrap(nil).value_or(false) # false
124
+
125
+ Kind::Maybe(Kind::Boolean).wrap(true).value_or(false) # true
126
+ ```
127
+
128
+ * [#43](https://github.com/serradura/kind/pull/43) - Add `Kind::<Type>.maybe` and `Kind::<Type>.optional`. This method returns a typed Maybe with the expected kind when it is invoked without arguments. But, if it receives arguments, it will behave like the `Kind::Maybe.wrap` method. e.g.
129
+ ```ruby
130
+ Kind::Integer.maybe #<Kind::Maybe::Typed:0x0000... @kind=Kind::Integer>
131
+
132
+ Kind::Integer.maybe(0).some? # true
133
+ Kind::Integer.maybe { 1 }.some? # true
134
+ Kind::Integer.maybe(2) { |n| n * 2 }.some? # true
135
+
136
+ Kind::Integer.maybe { 2 / 0 }.none? # true
137
+ Kind::Integer.maybe(2) { |n| n / 0 }.none? # true
138
+ Kind::Integer.maybe('2') { |n| n * n }.none? # true
139
+ ```
140
+
141
+ * [#43](https://github.com/serradura/kind/pull/43) - Make the `:respond_to` kind validation verify by one or multiple methods. e.g.
142
+ ```ruby
143
+ validates :params, kind: { respond_to: [:[], :values_at] }
144
+ ```
145
+
146
+ * [#43](https://github.com/serradura/kind/pull/43) - Make the `:of` kind validation verify the expected value kind using `===`, because of this, now is possible to use type checkers as expected kinds. e.g.
147
+ ```ruby
148
+ validates :alive, kind: Kind::Boolean
149
+ ```
150
+
151
+ 4.0.0 (2021-02-22)
152
+ ------------------
153
+
154
+ ### Added
155
+
156
+ * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.of_class?` to verify if a given value is a `Class`.
157
+
158
+ * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.of_module?` to verify if a given value is a `Module`.
159
+
160
+ * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.of_module_or_class()` that returns the given value if it is a module or a class. If not, a `Kind::Error` will be raised.
161
+ ```ruby
162
+ Kind.of_module_or_class(String) # String
163
+ Kind.of_module_or_class(1) # Kind::Error (1 expected to be a kind of Module/Class)
164
+ ```
165
+
166
+ * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.respond_to(object, *method_names)`, this method returns the given object if it responds to all of the method names. But if the object does not respond to some of the expected methods, an error will be raised.
167
+ ```ruby
168
+ Kind.respond_to('', :upcase) # ""
169
+ Kind.respond_to('', :upcase, :strip) # ""
170
+
171
+ Kind.respond_to(1, :upcase) # expected 1 to respond to :upcase
172
+ Kind.respond_to(2, :to_s, :upcase) # expected 2 to respond to :upcase
173
+ ```
174
+
175
+ * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind::Try.call()`. This method invokes a public method with or without arguments like public_send does, except that if the receiver does not respond to it the call returns `nil` rather than raising an exception.
176
+ ```ruby
177
+ Kind::Try.(' foo ', :strip) # "foo"
178
+ Kind::Try.({a: 1}, :[], :a) # 1
179
+ Kind::Try.({a: 1}, :[], :b) # nil
180
+ Kind::Try.({a: 1}, :fetch, :b, 2) # 2
181
+
182
+ Kind::Try.(:symbol, :strip) # nil
183
+ Kind::Try.(:symbol, :fetch, :b, 2) # nil
184
+
185
+ # It raises an exception if the method name isn't a string or a symbol
186
+ Kind::Try.({a: 1}, 1, :a) # TypeError (1 is not a symbol nor a string)
187
+ ```
188
+
189
+ * [#40](https://github.com/serradura/kind/pull/40), [#41](https://github.com/serradura/kind/pull/40) - Add `Kind::DEPRECATION` module to be used to warn about all of the deprecations. You can use the `DISABLE_KIND_DEPRECATION` environment variable to disable the warning messages.
190
+
191
+ * [#40](https://github.com/serradura/kind/pull/40), [#41](https://github.com/serradura/kind/pull/40) - Add type checkers modules that have several utility methods related to type checking/handling.
192
+ ```ruby
193
+ # All of the methods used with the Kind::String can be used with any other type checker module.
194
+
195
+ # Kind::<Type>.name
196
+ # Kind::<Type>.kind
197
+ # The type checker can return its kind and its name
198
+ Kind::String.name # "String"
199
+ Kind::String.kind # ::String
200
+
201
+ # Kind::<Type>.===
202
+ # Can check if a given value is an instance of its kind.
203
+ Kind::String === 'foo' # true
204
+ Kind::String === :foo # false
205
+
206
+ # Kind::<Type>.value?(value)
207
+ # Can check if a given value is an instance of its kind.
208
+ Kind::String.value?('foo') # true
209
+ Kind::String.value?(:foo) # false
210
+
211
+ # If it doesn't receive an argument, a lambda will be returned and it will know how to do the type verification.
212
+ [1, 2, 'foo', 3, 'Bar'].select?(&Kind::String.value?) # ["foo", "bar"]
213
+
214
+ # Kind::<Type>.or_nil(value)
215
+ # Can return nil if the given value isn't an instance of its kind
216
+ Kind::String.or_nil('foo') # "foo"
217
+ Kind::String.or_nil(:foo) # nil
218
+
219
+ # Kind::<Type>.or_undefined(value)
220
+ # Can return Kind::Undefined if the given value isn't an instance of its kind
221
+ Kind::String.or_undefined('foo') # "foo"
222
+ Kind::String.or_undefined(:foo) # Kind::Undefined
223
+
224
+ # Kind::<Type>.or(fallback, value)
225
+ # Can return a fallback if the given value isn't an instance of its kind
226
+ Kind::String.or(nil, 'foo') # "foo"
227
+ Kind::String.or(nil, :foo) # nil
228
+
229
+ # If it doesn't receive a second argument (the value), it will return a callable that knows how to expose an instance of the expected type or a fallback if the given value is wrong.
230
+ [1, 2, 'foo', 3, 'Bar'].map(&Kind::String.or('')) # ["", "", "foo", "", "Bar"]
231
+ [1, 2, 'foo', 3, 'Bar'].map(&Kind::String.or(nil)) # [nil, nil, "foo", nil, "Bar"]
232
+
233
+ # An error will be raised if the fallback didn't have the expected kind or if not nil / Kind::Undefined.
234
+ [1, 2, 'foo', 3, 'Bar'].map(&Kind::String.or(:foo)) # Kind::Error (:foo expected to be a kind of String)
235
+
236
+ # Kind::<Type>[value]
237
+ # Will raise Kind::Error if the given value isn't an instance of the expected kind
238
+ Kind::String['foo'] # "foo"
239
+ Kind::String[:foo ] # Kind::Error (:foo expected to be a kind of String)
240
+ ```
241
+ * List of all type checkers:
242
+ * **Core:**
243
+ * `Kind::Array`
244
+ * `Kind::Class`
245
+ * `Kind::Comparable`
246
+ * `Kind::Enumerable`
247
+ * `Kind::Enumerator`
248
+ * `Kind::File`
249
+ * `Kind::Float`
250
+ * `Kind::Hash`
251
+ * `Kind::Integer`
252
+ * `Kind::IO`
253
+ * `Kind::Method`
254
+ * `Kind::Module`
255
+ * `Kind::Numeric`
256
+ * `Kind::Proc`
257
+ * `Kind::Queue`
258
+ * `Kind::Range`
259
+ * `Kind::Regexp`
260
+ * `Kind::String`
261
+ * `Kind::Struct`
262
+ * `Kind::Symbol`
263
+ * `Kind::Time`
264
+ * **Custom:**
265
+ * `Kind::Boolean`
266
+ * `Kind::Callable`
267
+ * `Kind::Lambda`
268
+ * **Stdlib:**
269
+ * `Kind::OpenStruct`
270
+ * `Kind::Set`
271
+
272
+ * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind::Of()`. This method allows the creation of type checkers in runtime. To do this, the kind must respond to the method `.===`, and if doesn't have the `.name` method (which needs to return a string), a hash must be provided with a filled `:name` property.
273
+ ```ruby
274
+ # Example using a class (an object which responds to .=== and has the .name method):
275
+ # This object will have all of the default methods that a standard type checker (e.g: Kind::String) has.
276
+ kind_of_string = Kind::Of(String)
277
+
278
+ kind_of_string[''] # ""
279
+ kind_of_string[{}] # Kind::Error ({} expected to be a kind of String)
280
+
281
+ # Example using a lambda (an object which responds to .===) and a hash with the kind name.
282
+
283
+ PositiveInteger = Kind::Of(-> value { value.kind_of?(Integer) && value > 0 }, name: 'PositiveInteger')
284
+
285
+ # PositiveInteger.name
286
+ # PositiveInteger.kind
287
+ # The type checker can return its kind and its name
288
+ PositiveInteger.name # "PositiveInteger"
289
+ PositiveInteger.kind # #<Proc:0x0000.... >
290
+
291
+ # PositiveInteger.===
292
+ # Can check if a given value is an instance of its kind.
293
+ PositiveInteger === 1 # true
294
+ PositiveInteger === 0 # false
295
+
296
+ # PositiveInteger.value?(value)
297
+ # Can check if a given value is an instance of its kind.
298
+ PositiveInteger.value?(1) # true
299
+ PositiveInteger.value?(-1) # false
300
+
301
+ # If it doesn't receive an argument, a lambda will be returned and it will know how to do the type verification.
302
+ [1, 2, 0, 3, -1].select?(&PositiveInteger.value?) # [1, 2, 3]
303
+
304
+ # PositiveInteger.or_nil(value)
305
+ # Can return nil if the given value isn't an instance of its kind
306
+ PositiveInteger.or_nil(1) # 1
307
+ PositiveInteger.or_nil(0) # nil
308
+
309
+ # PositiveInteger.or_undefined(value)
310
+ # Can return Kind::Undefined if the given value isn't an instance of its kind
311
+ PositiveInteger.or_undefined(2) # 2
312
+ PositiveInteger.or_undefined(-1) # Kind::Undefined
313
+
314
+ # PositiveInteger.or(fallback, value)
315
+ # Can return a fallback if the given value isn't an instance of its kind
316
+ PositiveInteger.or(nil, 1) # 1
317
+ PositiveInteger.or(nil, 0) # nil
318
+
319
+ # If it doesn't receive a second argument (the value), it will return a callable that knows how to expose an instance of the expected type or a fallback if the given value is wrong.
320
+ [1, 2, 0, 3, -1].map(&PositiveInteger.or(1)) # [1, 2, 1, 3, 1]
321
+ [1, 2, 0, 3, -1].map(&PositiveInteger.or(nil)) # [1, 2, nil, 3, nil]
322
+
323
+ # An error will be raised if the fallback didn't have the expected kind or if not nil / Kind::Undefined.
324
+ [1, 2, 0, 3, -1].map(&PositiveInteger.or(:foo)) # Kind::Error (:foo expected to be a kind of PositiveInteger)
325
+
326
+ # PositiveInteger[value]
327
+ # Will raise Kind::Error if the given value isn't an instance of the expected kind
328
+ PositiveInteger[1] # 1
329
+ PositiveInteger[:foo] # Kind::Error (:foo expected to be a kind of PositiveInteger)
330
+ ```
331
+ * [#40](https://github.com/serradura/kind/pull/40), [#41](https://github.com/serradura/kind/pull/40) - Add type checkers methods.
332
+ ```ruby
333
+ # All of the methods used with the Kind::String? can be used with any other type checker method.
334
+
335
+ # Kind::<Type>?(*values)
336
+ # Can check if a given value (one or many) is an instance of its kind.
337
+ Kind::String?('foo') # true
338
+ Kind::String?('foo', 'bar') # true
339
+ Kind::String?('foo', :bar) # false
340
+
341
+ # If it doesn't receive an argument, a lambda will be returned and it will know how to do the type verification.
342
+ [1, 2, 'foo', 3, 'Bar'].select?(&Kind::String?) # ["foo", "bar"]
343
+ ```
344
+ * List of all type checkers:
345
+ * **Core:**
346
+ * `Kind::Array?`
347
+ * `Kind::Class?`
348
+ * `Kind::Comparable?`
349
+ * `Kind::Enumerable?`
350
+ * `Kind::Enumerator?`
351
+ * `Kind::File?`
352
+ * `Kind::Float?`
353
+ * `Kind::Hash?`
354
+ * `Kind::Integer?`
355
+ * `Kind::IO?`
356
+ * `Kind::Method?`
357
+ * `Kind::Module?`
358
+ * `Kind::Numeric?`
359
+ * `Kind::Proc?`
360
+ * `Kind::Queue?`
361
+ * `Kind::Range?`
362
+ * `Kind::Regexp?`
363
+ * `Kind::String?`
364
+ * `Kind::Struct?`
365
+ * `Kind::Symbol?`
366
+ * `Kind::Time?`
367
+ * **Custom:**
368
+ * `Kind::Boolean?`
369
+ * `Kind::Callable?`
370
+ * `Kind::Lambda?`
371
+ * **Stdlib:**
372
+ * `Kind::OpenStruct?`
373
+ * `Kind::Set?`
374
+
375
+ * [#41](https://github.com/serradura/kind/pull/41) - Make `Kind::Dig.call` extract values from regular objects.
376
+ ```ruby
377
+ class Person
378
+ attr_reader :name
379
+
380
+ def initialize(name)
381
+ @name = name
382
+ end
383
+ end
384
+
385
+ person = Person.new('Rodrigo')
386
+
387
+ Kind::Dig.(person, [:name]) # "Rodrigo"
388
+
389
+ Kind::Dig.({people: [person]}, [:people, 0, :name]) # "Rodrigo"
390
+ ```
391
+
392
+ * [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::Presence.call`. Returns the given value if it's present otherwise it will return `nil`.
393
+ ```ruby
394
+ Kind::Presence.(true) # true
395
+ Kind::Presence.('foo') # "foo"
396
+ Kind::Presence.([1, 2]) # [1, 2]
397
+ Kind::Presence.({a: 3}) # {a: 3}
398
+ Kind::Presence.(Set.new([4])) # #<Set: {4}>
399
+
400
+ Kind::Presence.('') # nil
401
+ Kind::Presence.(' ') # nil
402
+ Kind::Presence.("\t\n\r") # nil
403
+ Kind::Presence.("\u00a0") # nil
404
+
405
+ Kind::Presence.([]) # nil
406
+ Kind::Presence.({}) # nil
407
+ Kind::Presence.(Set.new) # nil
408
+
409
+ Kind::Presence.(nil) # nil
410
+ Kind::Presence.(false) # nil
411
+
412
+ # nil will be returned if the given object responds to the method blank? and this method result is true.
413
+ MyObject = Struct.new(:is_blank) do
414
+ def blank?
415
+ is_blank
416
+ end
417
+ end
418
+
419
+ my_object = MyObject.new
420
+
421
+ my_object.is_blank = true
422
+
423
+ Kind::Presence.(my_object) # nil
424
+
425
+ my_object.is_blank = false
426
+
427
+ Kind::Presence.(my_object) # #<struct MyObject is_blank=false>
428
+ ```
429
+
430
+ * [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::Maybe#presence`, this method will return None if the wrapped value wasn't present.
431
+ ```ruby
432
+ result1 = Kind::Maybe(Hash).wrap(foo: '').dig(:foo).presence
433
+ result1.none? # true
434
+ result1.value # nil
435
+
436
+ result2 = Kind::Maybe(Hash).wrap(foo: 'bar').dig(:foo).presence
437
+ result2.none? # false
438
+ result2.value # "bar"
439
+ ```
440
+
441
+ * [#41](https://github.com/serradura/kind/pull/41) - Make `Kind::Maybe#wrap` receive a block and intercept StandardError exceptions. And a None will be returned if some exception happening.
442
+ ```ruby
443
+ Kind::Maybe.wrap { 2 / 0 } # #<Kind::Maybe::None:0x0000... @value=#<ZeroDivisionError: divided by 0>>
444
+
445
+ Kind::Maybe(Numeric).wrap(2) { |number| number / 0 } # #<Kind::Maybe::None:0x0000... @value=#<ZeroDivisionError: divided by 0>>
446
+ ```
447
+
448
+ * [#41](https://github.com/serradura/kind/pull/41) - Make `Kind::Maybe#map` intercept StandardError exceptions.
449
+ * Now the `#map` and `#then` methods will intercept any StandardError and return None with the exception or their values.
450
+ * Add `#map!` and `#then!` that allows the exception leak, so, the user must handle the exception by himself or use this method when he wants to see the error be raised.
451
+ * If an exception (StandardError) is returned by the methods `#then`, `#map` it will be resolved as None.
452
+ ```ruby
453
+ # Handling StandardError exceptions
454
+ result1 = Kind::Maybe[2].map { |number| number / 0 }
455
+ result1.none? # true
456
+ result1.value # #<ZeroDivisionError: divided by 0>
457
+
458
+ result2 = Kind::Maybe[3].then { |number| number / 0 }
459
+ result2.none? # true
460
+ result2.value # #<ZeroDivisionError: divided by 0>
461
+
462
+ # Leaking StandardError exceptions
463
+ Kind::Maybe[2].map! { |number| number / 0 } # ZeroDivisionError (divided by 0)
464
+
465
+ Kind::Maybe[2].then! { |number| number / 0 } # ZeroDivisionError (divided by 0)
466
+ ```
467
+
468
+ * [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::TypeCheckers#value`. This method ensures that you will have a value of the expected kind. But, in the case of the given value be invalid, this method will require a default value (with the expected kind) to be returned.
469
+ ```ruby
470
+ # Using built-in type checkers
471
+ Kind::String.value(1, default: '') # ""
472
+ Kind::String.value('1', default: '') # "1"
473
+
474
+ Kind::String.value('1', default: 1) # Kind::Error (1 expected to be a kind of String)
475
+
476
+ # Using custom type checkers
477
+ PositiveInteger = Kind::Of(-> value { value.kind_of?(Integer) && value > 0 }, name: 'PositiveInteger')
478
+
479
+ PositiveInteger.value(0, default: 1) # 1
480
+ PositiveInteger.value(2, default: 1) # 2
481
+
482
+ PositiveInteger.value(-1, default: 0) # Kind::Error (0 expected to be a kind of PositiveInteger)
483
+ ```
484
+
485
+ * [#41](https://github.com/serradura/kind/pull/41) - Add the method `value_or_empty` for some type checkers. This method is available for some type checkers (`Kind::Array`, `Kind::Hash`, `Kind::String`, `Kind::Set`), and it will return an empty frozen value if the given value hasn't the expected kind.
486
+ ```ruby
487
+ Kind::Array.value_or_empty({}) # []
488
+ Kind::Array.value_or_empty({}).frozen? # true
489
+ ```
490
+
491
+ * [#42](https://github.com/serradura/kind/pull/42) - Add the method `Kind.value`. This method ensures that you will have a value of the expected kind. But, in the case of the given value be invalid, this method will require a default value (with the expected kind) to be returned.
492
+ ```ruby
493
+ Kind.value(String, '1', default: '') # "1"
494
+
495
+ Kind.value(String, 1, default: '') # ""
496
+
497
+ Kind.value(String, 1, default: 2) # Kind::Error (2 expected to be a kind of String)
498
+ ```
499
+
500
+ * [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Presence.to_proc`. This method allow you to make use of the `Kind::Presence` in methods that receive a block as an argument. e.g:
501
+ ```ruby
502
+ ['', [], {}, '1', [2]].map(&Kind::Presence) # [nil, nil, nil, "1", [2]]
503
+ ```
504
+
505
+ * [#42](https://github.com/serradura/kind/pull/42) - `Kind::Maybe(<Type>).{new,[],wrap}` Now, these methods know how to get the value of another Maybe monad.
506
+ ```ruby
507
+ some_number = Kind::Some(2)
508
+
509
+ Kind::Maybe(Numeric)[some_number] # #<Kind::Maybe::Some:0x0000... @value=2>
510
+
511
+ Kind::Maybe(Numeric).new(some_number) # #<Kind::Maybe::Some:0x0000... @value=2>
512
+
513
+ Kind::Maybe(Numeric).wrap(some_number) # #<Kind::Maybe::Some:0x0000... @value=2>
514
+
515
+ Kind::Maybe(Numeric).wrap { some_number } # #<Kind::Maybe::Some:0x0000... @value=2>
516
+
517
+ Kind::Maybe(Numeric).wrap(some_number) { |number| number / 2 } # #<Kind::Maybe::Some:0x0000... @value=1>
518
+ ```
519
+
520
+ * [#42](https://github.com/serradura/kind/pull/42) - `Kind::Maybe(<Type>).wrap(arg) { |arg_value| }` if the block receives an argument, the typed Maybe monad will verify if the argument is from the expected kind.
521
+ ```ruby
522
+ Kind::Maybe(Numeric).wrap('2') { |number| number / 0 } # #<Kind::Maybe::None:0x0000... @value=nil>
523
+
524
+ Kind::Maybe(Numeric).wrap(2) { |number| number / 0 } # #<Kind::Maybe::None:0x0000... @value=#<ZeroDivisionError: divided by 0>>
525
+ ```
526
+
527
+ * [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Maybe#check`. This method returns the current Some after verifies if the block output was truthy.
528
+ ```ruby
529
+ person_name = ->(params) do
530
+ Kind::Maybe(Hash)
531
+ .wrap(params)
532
+ .then { |hash| hash.values_at(:first_name, :last_name) }
533
+ .then { |names| names.map(&Kind::Presence).tap(&:compact!) }
534
+ .check { |names| names.size == 2 }
535
+ .then { |(first_name, last_name)| "#{first_name} #{last_name}" }
536
+ .value_or { 'John Doe' }
537
+ end
538
+
539
+ person_name.('') # "John Doe"
540
+ person_name.(nil) # "John Doe"
541
+ person_name.(last_name: 'Serradura') # "John Doe"
542
+ person_name.(first_name: 'Rodrigo') # "John Doe"
543
+
544
+ person_name.(first_name: 'Rodrigo', last_name: 'Serradura') # "Rodrigo Serradura"
545
+ ```
546
+
547
+ * [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Dig[]`. This method knows how to create a lambda that will know how to perform the dig strategy.
548
+ ```ruby
549
+ results = [
550
+ { person: {} },
551
+ { person: { name: 'Foo Bar'} },
552
+ { person: { name: 'Rodrigo Serradura'} },
553
+ ].map(&Kind::Dig[:person, :name])
554
+
555
+ p results # [nil, "Foo Bar", "Rodrigo Serradura"],
556
+ ```
557
+
558
+ * [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Try[]`. This method knows how to create a lambda that will know how to perform the try strategy.
559
+ ```ruby
560
+ results =
561
+ [
562
+ {},
563
+ {name: 'Foo Bar'},
564
+ {name: 'Rodrigo Serradura'},
565
+ ].map(&Kind::Try[:fetch, :name, 'John Doe'])
566
+
567
+ p results # ["John Doe", "Foo Bar", "Rodrigo Serradura"]
568
+ ```
569
+
570
+ ### Deprecated
571
+
572
+ * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Is.call`
573
+
574
+ * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Of.call`
575
+
576
+ * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Types.add`.
577
+
578
+ * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Of::<Type>` and `Kind::Is::<Type>` modules.
579
+
580
+ * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Checker`, `Kind::Checker::Protocol`, `Kind::Checker::Factory`.
581
+
582
+ * [#40](https://github.com/serradura/kind/pull/40) - Deprecate the invocation of `Kind.is` without arguments.
583
+
584
+ * [#40](https://github.com/serradura/kind/pull/40) - Deprecate the invocation of `Kind.of` without arguments.
585
+
586
+ * [#40](https://github.com/serradura/kind/pull/40) - Deprecate the invocation of `Kind.of` with a single argument (the kind).
587
+
588
+ ### Fixed
589
+
590
+ * [#40](https://github.com/serradura/kind/pull/40) - Make `Kind::Maybe.try!()` raises an error if it was called without a block or arguments.
591
+
592
+ [⬆️ &nbsp;Back to Top](#changelog-)
593
+
594
+ 3.1.0 (2020-07-08)
595
+ ------------------
596
+
597
+ ### Added
598
+
599
+ * [#33](https://github.com/serradura/kind/pull/33) - Add new type checker.
600
+ - `Kind::Of::OpenStruct`, `Kind::Is::OpenStruct`
601
+
602
+ * [#33](https://github.com/serradura/kind/pull/33) - Add `Kind::Maybe::Result#dig`. It extracts the nested value in a sequence of objects, if any step returns `nil` the operation will stop and `None` will be returned, otherwise a `Some` will be returned with the final value.
603
+ ```ruby
604
+ class User
605
+ def self.find_by(id:)
606
+ return :user_1 if id == 1
607
+ end
608
+ end
609
+
610
+ Kind::Optional(Hash).wrap(user: { id: 2 }).dig(:user).value # {:id=>2}
611
+
612
+ # --
613
+
614
+ user_id = Kind::Optional(Hash).wrap(user: { id: 1 }).dig(:user, :id)
615
+
616
+ user_id.then { |id| User.find_by(id: id) }.value # :user_id
617
+ ```
618
+
619
+ * [#33](https://github.com/serradura/kind/pull/33) - Add the utility module `Kind::Dig`. It has the same behavior of Ruby dig methods ([Hash](https://ruby-doc.org/core-2.3.0/Hash.html#method-i-dig), [Array](https://ruby-doc.org/core-2.3.0/Array.html#method-i-dig), [Struct](https://ruby-doc.org/core-2.3.0/Struct.html#method-i-dig), [OpenStruct](https://ruby-doc.org/stdlib-2.3.0/libdoc/ostruct/rdoc/OpenStruct.html#method-i-dig)), but it will not raise an error if some step can't be digged.
620
+ ```ruby
621
+ s = Struct.new(:a, :b).new(101, 102)
622
+ o = OpenStruct.new(c: 103, d: 104)
623
+ d = { struct: s, ostruct: o, data: [s, o]}
624
+
625
+ Kind::Dig.(s, [:a]) # 101
626
+ Kind::Dig.(o, [:c]) # 103
627
+
628
+ Kind::Dig.(d, [:struct, :b]) # 102
629
+ Kind::Dig.(d, [:data, 0, :b]) # 102
630
+ Kind::Dig.(d, [:data, 0, 'b']) # 102
631
+
632
+ Kind::Dig.(d, [:ostruct, :d]) # 104
633
+ Kind::Dig.(d, [:data, 1, :d]) # 104
634
+ Kind::Dig.(d, [:data, 1, 'd']) # 104
635
+
636
+ Kind::Dig.(d, [:struct, :f]) # nil
637
+ Kind::Dig.(d, [:ostruct, :f]) # nil
638
+ Kind::Dig.(d, [:data, 0, :f]) # nil
639
+ Kind::Dig.(d, [:data, 1, :f]) # nil
640
+ ```
641
+
642
+ [⬆️ &nbsp;Back to Top](#changelog-)
643
+
644
+ 3.0.0 (2020-06-25)
645
+ ------------------
646
+
647
+ ### Breaking Changes
648
+
649
+ * [#31](https://github.com/serradura/kind/pull/31) - Change the `Kind::Maybe::Result#try()` behavior.
650
+ - If you don't want to use the methods `#map`/`#then` to access some value inside of the monad, you could use the `#try` method to do this. It invokes a public method with or without arguments like public_send does, except that if the receiver does not respond to it the call returns `nil` rather than raising an exception. So, if the value wasn't `nil` or `Kind::Undefined` a `Some` will be returned.
651
+ ```ruby
652
+ # Examples using Kind::Maybe
653
+
654
+ Kind::Maybe['foo'].try(:upcase).value # "FOO"
655
+
656
+ Kind::Maybe[{}].try(:fetch, :number, 0).value # 0
657
+
658
+ Kind::Maybe[{number: 1}].try(:fetch, :number).value # 1
659
+
660
+ Kind::Maybe[' foo '].try { |value| value.strip }.value # "foo"
661
+
662
+ # Examples using Kind::Optional
663
+
664
+ Kind::Optional[1].try(:strip).value_or('') # ""
665
+
666
+ Kind::Optional[' Rodrigo '].try(:strip).value_or("") # 'Rodrigo'
667
+ ```
668
+
669
+ ### Added
670
+
671
+ * [#31](https://github.com/serradura/kind/pull/31) - Add `Kind::Maybe::Result#try!()` that have almost of the same behavior of `Kind::Maybe::Result#try()`, the difference is because it will raise an error when the monad value doesn't respond to the expected method.
672
+ ```ruby
673
+ Kind::Maybe[{}].try(:upcase) # => #<Kind::Maybe::None:0x0000... @value=nil>
674
+
675
+ Kind::Maybe[{}].try!(:upcase) # => NoMethodError (undefined method `upcase' for {}:Hash)
676
+ ```
677
+
678
+ [⬆️ &nbsp;Back to Top](#changelog-)
679
+
680
+ 2.3.0 (2020-06-24)
681
+ ------------------
682
+
683
+ ### Added
684
+
685
+ * [#30](https://github.com/serradura/kind/pull/30) - Add `Kind::Maybe.wrap()` as an alias for `Kind::Maybe.new()`.
686
+
687
+ * [#30](https://github.com/serradura/kind/pull/30) - Add `Kind::Maybe::Typed` and the methods `Kind::Maybe()`, `Kind::Optional()` to create typed monads. It will return `Some` if the given value has the expected kind or `None` if it hasn't.
688
+ ```ruby
689
+ Double = ->(arg) do
690
+ Kind::Optional(Numeric)
691
+ .wrap(arg)
692
+ .then { |number| number * 2 }
693
+ end
694
+ ```
695
+
696
+ [⬆️ &nbsp;Back to Top](#changelog-)
697
+
698
+ 2.2.0 (2020-06-23)
699
+ ------------------
700
+
701
+ ### Added
702
+
703
+ * [#29](https://github.com/serradura/kind/pull/29) - Improve the comparison of values with `Kind::Undefined`.
704
+ - I've been using `Kind.of(ActiveRecord::Relation, some_ar_relation)` in one of my apps and I found an unexpected behavior, the relations were always been executed. The reason is `ActiveRecord::AssociationRelation#==` behavior, which always performs a query (`to_a`). So, to avoid this and other unexpected behaviors, I decided to invert the comparison with `Kind::Undefined` to ensure a regular equality checking.
705
+
706
+ [⬆️ &nbsp;Back to Top](#changelog-)
707
+
708
+ 2.1.0 (2020-05-12)
709
+ ------------------
710
+
711
+ ### Added
712
+
713
+ * [#28](https://github.com/serradura/kind/pull/28) - Allow passing multiple arguments to `Kind.of.<Type>.instance?(*args)`
714
+
715
+ * [#28](https://github.com/serradura/kind/pull/28) - Allow passing multiple arguments to `Kind.of.<Type>?(*args)`
716
+
717
+ * [#28](https://github.com/serradura/kind/pull/28) - Add `Kind::Some()` and `Kind::None()`. e.g:
718
+ ```ruby
719
+ Double = ->(arg) do
720
+ number = Kind::Of::Numeric.or_nil(arg)
721
+
722
+ Kind::Optional[number].then { |number| number * 2 }
723
+ end
724
+
725
+ Add = -> params do
726
+ a, b = Kind::Of::Hash(params, or: Empty::HASH).values_at(:a, :b)
727
+
728
+ return Kind::None unless Kind::Of::Numeric?(a, b)
729
+
730
+ Kind::Some(a + b)
731
+ end
732
+
733
+ Kind::Optional[a: 1, b: 2].then(&Add).value_or(0) # 3
734
+
735
+ Add.({}).some? # false
736
+
737
+ Add.(a: 1, b: '2').some? # false
738
+
739
+ Add.(a: 2, b: 2).then(&Double).value # 8
740
+ ```
741
+
742
+ * [#28](https://github.com/serradura/kind/pull/28) - Add `Kind.of?(<Type>, *args)` to check if one or many values are the expected kind.
743
+ ```ruby
744
+ Kind.of?(Numeric, 1, 2.0, 3) # true
745
+ Kind.of?(Numeric, 1, '2', 3) # false
746
+ ```
747
+
748
+ * [#28](https://github.com/serradura/kind/pull/28) - Make the `Kind.of?(<Type>)` returns a lambda that knows how to do the type verification.
749
+ ```ruby
750
+ [1, '2', 3].select(&Kind.of?(Numeric)) # [1, 3]
751
+ ```
752
+
753
+ ### Breaking Changes
754
+
755
+ * [#28](https://github.com/serradura/kind/pull/28) - Make `Kind.of.<Type>.to_proc` have the same behavior of `Kind.of.<Type>.instance(value)` (returns the value if it has the expected kind or raise `Kind::Error` if it haven't). This change is because now we have a method to verify if the given value is an instance of the expected kind (`Kind.of.<Type>?`), and this new method has a `to_proc` behavior when is called without arguments.
756
+ ```ruby
757
+ [1, 2, 3].map(&Kind::Of::Numeric) # [1, 2, 3]
758
+
759
+ [1, '2', 3].map(&Kind::Of::Numeric) # Kind::Error ("2" expected to be a kind of Numeric)
760
+
761
+ [1, '2', 3].select(&Kind::Of::Numeric?) # [1, 3]
762
+ ```
763
+
764
+ [⬆️ &nbsp;Back to Top](#changelog-)
765
+
766
+ 2.0.0 (2020-05-07)
767
+ ------------------
768
+
769
+ ### Added
770
+
771
+ * [#24](https://github.com/serradura/kind/pull/24) - Improve the `kind: { is: }` validation to check the inheritance of *classes*/*modules*.
772
+
773
+ ### Breaking Changes
774
+
775
+ * [#24](https://github.com/serradura/kind/pull/24) - Change the `Kind.{of,is}.Callable` verification. Now, it only verifies if the given object `respond_to?(:call)`.
776
+
777
+ ### Removed
778
+
779
+ * [#24](https://github.com/serradura/kind/pull/24) - Remove `kind: { is_a: }` from `Kind::Validator`.
780
+ * [#24](https://github.com/serradura/kind/pull/24) - Remove `kind: { klass: }` from `Kind::Validator`.
781
+
782
+ [⬆️ &nbsp;Back to Top](#changelog-)
783
+
784
+ 1.9.0 (2020-05-06)
785
+ ------------------
786
+
787
+ ### Added
788
+
789
+ * [#23](https://github.com/serradura/kind/pull/23) - Add `Kind.of.<Type>.to_proc` as an alias for `Kind.of.<Type>.instance?`.
790
+ ```ruby
791
+ collection = [
792
+ {number: 1},
793
+ 'number 0',
794
+ {number: 2},
795
+ [0],
796
+ ]
797
+
798
+ collection
799
+ .select(&Kind.of.Hash)
800
+ .reduce(0) { |total, item| total + item[:number] }
801
+ ```
802
+
803
+ * [#23](https://github.com/serradura/kind/pull/23) - Add `Kind::Validator` (`ActiveModel` validator) as an alternative (substitute) of [`type_validator`](https://github.com/serradura/type_validator).
804
+ ```ruby
805
+ require 'kind/active_model/validation'
806
+
807
+ class Person
808
+ include ActiveModel::Validations
809
+
810
+ attr_reader :name, :age
811
+
812
+ validates :name, kind: { of: String }
813
+ validates :age, kind: { of: Integer }
814
+
815
+ def initialize(name:, age:)
816
+ @name, @age = name, age
817
+ end
818
+ end
819
+
820
+ person = Person.new(name: 'John', age: '21')
821
+
822
+ person.valid? # false
823
+
824
+ person.errors[:age] # ['must be a kind of: Integer']
825
+ ```
826
+
827
+ [⬆️ &nbsp;Back to Top](#changelog-)
828
+
829
+ 1.8.0 (2020-05-03)
830
+ ------------------
831
+
832
+ ### Added
833
+
834
+ * [#22](https://github.com/serradura/kind/pull/22) - `Kind.of.<Type>.instance?`returns a lambda when called without an argument.
835
+ ```ruby
836
+ collection = [
837
+ {number: 1},
838
+ 'number 0',
839
+ {number: 2},
840
+ [0],
841
+ ]
842
+
843
+ collection
844
+ .select(&Kind::Of::Hash.instance?)
845
+ .reduce(0) { |total, item| total + item[:number] }
846
+ ```
847
+
848
+ * [#22](https://github.com/serradura/kind/pull/22) - Add new methods `.as_optional`, `.as_maybe` in the type checkers.
849
+ ```ruby
850
+ def person_name(params)
851
+ Kind::Of::Hash
852
+ .as_optional(params)
853
+ .map { |data| data.values_at(:first_name, :last_name).compact }
854
+ .map { |first, last| "#{first} #{last}" if first && last }
855
+ .value_or { 'John Doe' }
856
+ end
857
+
858
+ person_name('') # "John Doe"
859
+ person_name(nil) # "John Doe"
860
+ person_name(first_name: 'Rodrigo') # "John Doe"
861
+ person_name(last_name: 'Serradura') # "John Doe"
862
+ person_name(first_name: 'Rodrigo', last_name: 'Serradura') # "Rodrigo Serradura"
863
+
864
+ # A lambda will be returned if these methods receive only one argument
865
+
866
+ collection = [
867
+ {number: 1},
868
+ 'number 0',
869
+ {number: 2},
870
+ [0],
871
+ ]
872
+
873
+ collection
874
+ .map(&Kind.of.Hash.as_optional)
875
+ .select(&:some?)
876
+ .reduce(0) { |total, item| total + item.value[:number] }
877
+ ```
878
+
879
+ [⬆️ &nbsp;Back to Top](#changelog-)
880
+
881
+ 1.7.0 (2020-05-03)
882
+ ------------------
883
+
884
+ ### Fixed
885
+
886
+ * [#20](https://github.com/serradura/kind/pull/20) - Fix the verification of modules using `Kind.is()`.
887
+
888
+ [⬆️ &nbsp;Back to Top](#changelog-)
889
+
890
+ 1.6.0 (2020-04-17)
891
+ ------------------
892
+
893
+ ### Added
894
+
895
+ * [#19](https://github.com/serradura/kind/pull/19) - Add aliases to perform the strict type verification (in registered type checkers).
896
+ ```ruby
897
+ # Kind.of.<Type>[]
898
+
899
+ Kind.of.Hash[nil] # raise Kind::Error, "nil expected to be a kind of Hash"
900
+ Kind.of.Hash[''] # raise Kind::Error, "'' expected to be a kind of Hash"
901
+ Kind.of.Hash[a: 1] # {a: 1}
902
+ Kind.of.Hash['', or: {}] # {}
903
+
904
+ # Kind.of.<Type>.instance()
905
+
906
+ Kind.of.Array.instance(nil) # raise Kind::Error, "nil expected to be a kind of Array"
907
+ Kind.of.Array.instance('') # raise Kind::Error, "'' expected to be a kind of Array"
908
+ Kind.of.Array.instance([]) # []
909
+ Kind.of.Array.instance('', or: []) # []
910
+ ```
911
+
912
+ * [#19](https://github.com/serradura/kind/pull/19) - Add `.or_undefined` method for any type checker.
913
+ ```ruby
914
+ Kind.of.String.or_undefined(nil) # Kind::Undefined
915
+ Kind.of.String.or_undefined("something") # "something"
916
+ ```
917
+
918
+ * [#19](https://github.com/serradura/kind/pull/19) - Allow a dynamical verification of types.
919
+ ```ruby
920
+ class User
921
+ end
922
+
923
+ class AdminUser < User
924
+ end
925
+
926
+ Kind.of(User, User.new) # #<User:0x0000...>
927
+ Kind.of(User, {}) # Kind::Error ({} expected to be a kind of User)
928
+ ```
929
+
930
+ * [#19](https://github.com/serradura/kind/pull/19) - Allow the creation of type checkers dynamically (without register one).
931
+ ```ruby
932
+ class User
933
+ end
934
+
935
+ kind_of_user = Kind.of(User)
936
+
937
+ kind_of_user[{}] # Kind::Error ({} expected to be a kind of User)
938
+ kind_of_user[User.new] # #<User:0x0000...>
939
+
940
+ kind_of_user.instance({}) # Kind::Error ({} expected to be a kind of User)
941
+ kind_of_user.instance(User.new) # #<User:0x0000...>
942
+
943
+ kind_of_user.instance?({}) # false
944
+ kind_of_user.instance?(User.new) # true
945
+
946
+ kind_of_user.class?(Hash) # false
947
+ kind_of_user.class?(User) # true
948
+
949
+ kind_of_user.or_undefined({}) # Kind::Undefined
950
+ kind_of_user.or_undefined(User.new) # #<User:0x0000...>
951
+ ```
952
+
953
+ * [#19](https://github.com/serradura/kind/pull/19) - Add a new type checkers.
954
+ - `Kind::Of::Set`
955
+ - `Kind::Of::Maybe`, `Kind::Of::Optional`
956
+
957
+ * [#19](https://github.com/serradura/kind/pull/19) - Add `Kind::Empty` with several constants having empty frozen objects.
958
+ ```ruby
959
+ Kind::Empty::SET
960
+ Kind::Empty::HASH
961
+ Kind::Empty::ARRAY
962
+ Kind::Empty::STRING
963
+
964
+ # If there isn't any constant named as Empty, the gem will use it to create an alias for Kind::Empty.
965
+
966
+ Empty::SET == Kind::Empty::SET
967
+ Empty::HASH == Kind::Empty::HASH
968
+ Empty::ARRAY == Kind::Empty::ARRAY
969
+ Empty::STRING == Kind::Empty::STRING
970
+ ```
971
+
972
+ ### Changes
973
+
974
+ * [#19](https://github.com/serradura/kind/pull/19) - Change the output of `Kind::Undefined.to_s`, `Kind::Undefined.inspect`, the previous output was `"Undefined"` and the new is `"Kind::Undefined"`
975
+ ```ruby
976
+ Kind::Undefined.to_s # "Kind::Undefined"
977
+ Kind::Undefined.inspect # "Kind::Undefined"
978
+ ```
979
+
980
+ [⬆️ &nbsp;Back to Top](#changelog-)
981
+
982
+ 1.5.0 (2020-04-12)
983
+ ------------------
984
+
985
+ ### Added
986
+
987
+ * [#18](https://github.com/serradura/kind/pull/18) - Refactor `Kind::Maybe`.
988
+
989
+ * [#18](https://github.com/serradura/kind/pull/18) - Add `Kind::Maybe::Value` module, that has the `.some?` and `.none?` methods. Available to check if the given value is `Some` or `None`.
990
+ ```ruby
991
+ Kind::Maybe::Value.some?(1) # true
992
+ Kind::Maybe::Value.some?(nil) # false
993
+ Kind::Maybe::Value.some?(Kind::Undefined) # false
994
+
995
+ Kind::Maybe::Value.none?(1) # false
996
+ Kind::Maybe::Value.none?(nil) # true
997
+ Kind::Maybe::Value.none?(Kind::Undefined) # true
998
+ ```
999
+
1000
+ [⬆️ &nbsp;Back to Top](#changelog-)
1001
+
1002
+ 1.4.0 (2020-04-12)
1003
+ ------------------
1004
+
1005
+ ### Added
1006
+
1007
+ * [#17](https://github.com/serradura/kind/pull/17) - Transform `Kind::Optional` into `Kind::Maybe`. `Kind::Optional` still is available but as an alias for `Kind::Maybe`.
1008
+
1009
+ [⬆️ &nbsp;Back to Top](#changelog-)
1010
+
1011
+ 1.3.0 (2020-04-12)
1012
+ ------------------
1013
+
1014
+ ### Added
1015
+
1016
+ * [#16](https://github.com/serradura/kind/pull/16) - Add a new special type checkers.
1017
+ - `Kind::Of::Callable` for check if the given object respond to `call`.
1018
+ - `Kind::Is::Callable` if the given value is a `class`, it will verifies if its `public_instance_methods.include?(:call)`.
1019
+
1020
+ [⬆️ &nbsp;Back to Top](#changelog-)
1021
+
1022
+ 1.2.0 (2020-04-12)
1023
+ ------------------
1024
+
1025
+ ### Added
1026
+
1027
+ * [#15](https://github.com/serradura/kind/pull/15) - Add `Kind::Optional` the maybe monad, it encapsulates an optional value. A `Kind::Optional` either contains a value (represented as `Some`), or it is empty (represented as `None`). This data structure is helpful to transform a value through several operations, but if any of them returns `nil` or `Kind::Undefined` as its result, the next operations will be avoided.
1028
+ ```ruby
1029
+ # Some value
1030
+
1031
+ optional =
1032
+ Kind::Optional.new(2)
1033
+ .map { |value| value * 2 }
1034
+ .map { |value| value * 2 }
1035
+
1036
+ puts optional.value # 8
1037
+ puts optional.some? # true
1038
+ puts optional.none? # false
1039
+
1040
+ puts optional.value_or(0) # 8
1041
+ puts optional.value_or { 0 } # 8
1042
+
1043
+ # None value
1044
+
1045
+ even_number = Kind::Optional.new(3).map { |n| n if n.even? }
1046
+
1047
+ even_number.none? # true
1048
+
1049
+ even_number.value_or(0) # 0
1050
+
1051
+ # Utility method
1052
+
1053
+ # Kind::Optional#try
1054
+ # You could use the `#try` method to perform a method of the wrapped object and return its value.
1055
+
1056
+ Kind::Optional.new(' Rodrigo ').try(:strip) # "Rodrigo"
1057
+
1058
+ # Method aliases
1059
+
1060
+ # Kind::Optional[] is an alias for Kind::Optional.new
1061
+ Kind::Optional[2].map { |n| n if n.even? }.value_or(0) # 2
1062
+
1063
+ # Kind::Optional::Result#then is an alias for Kind::Optional::Result#map
1064
+ Kind::Optional[1].then { |n| n if n.even? }.value_or(0) # 0
1065
+ ```
1066
+
1067
+ * [#15](https://github.com/serradura/kind/pull/15) - Add new methods to `Kind::Undefined`.
1068
+ ```ruby
1069
+ Kind::Undefined.to_s # 'Undefined'
1070
+ Kind::Undefined.inspect # 'Undefined'
1071
+
1072
+ Kind::Undefined.clone # #<Kind::Undefined:0x0000...>
1073
+ Kind::Undefined.dup # #<Kind::Undefined:0x0000...>
1074
+
1075
+ Kind::Undefined.clone == Kind::Undefined # true
1076
+ Kind::Undefined.clone === Kind::Undefined # true
1077
+
1078
+ Kind::Undefined.dup == Kind::Undefined # true
1079
+ Kind::Undefined.dup === Kind::Undefined # true
1080
+
1081
+ value = Kind::Undefined
1082
+
1083
+ Kind::Undefined.default(value, 1) # 1
1084
+ ```
1085
+
1086
+ [⬆️ &nbsp;Back to Top](#changelog-)
1087
+
1088
+ 1.1.0 (2020-04-09)
1089
+ ------------------
1090
+
1091
+ ### Added
1092
+
1093
+ * [#14](https://github.com/serradura/kind/pull/14) - Add `Kind::Undefined` representing an undefined value to contrast with `nil`.
1094
+
1095
+ ### Fixed
1096
+
1097
+ * [#14](https://github.com/serradura/kind/pull/14) - Raise a `Kind::Error` if `nil` is the argument of any strict type checker.
1098
+ ```ruby
1099
+ Kind.of.Hash(nil) # raise Kind::Error, "nil expected to be a kind of Hash"
1100
+ ```
1101
+
1102
+ [⬆️ &nbsp;Back to Top](#changelog-)
1103
+
1104
+ 1.0.0 (2020-03-16)
1105
+ ------------------
1106
+
1107
+ ### Added
1108
+
1109
+ * [#12](https://github.com/serradura/kind/pull/12) - Register type checkers respecting their namespaces.
1110
+ ```ruby
1111
+ module Account
1112
+ class User
1113
+ Kind::Types.add(self)
1114
+ end
1115
+ end
1116
+
1117
+ module Account
1118
+ class User
1119
+ class Membership
1120
+ Kind::Types.add(self)
1121
+ end
1122
+ end
1123
+ end
1124
+
1125
+ account_user = Account::User.new
1126
+
1127
+ Kind.of.Account::User(account_user) # #<Account::User:0x0000...>
1128
+ Kind.of.Account::User({}) # Kind::Error ({} expected to be a kind of Account::User)
1129
+
1130
+ Kind.of.Account::User.or_nil({}) # nil
1131
+
1132
+ Kind.of.Account::User.instance?({}) # false
1133
+ Kind.of.Account::User.instance?(account_user) # true
1134
+
1135
+ Kind.of.Account::User.class?(Hash) # false
1136
+ Kind.of.Account::User.class?(Account::User) # true
1137
+
1138
+ # ---
1139
+
1140
+ membership = Account::User::Membership.new
1141
+
1142
+ Kind.of.Account::User::Membership(membership) # #<Account::User::Membership:0x0000...>
1143
+ Kind.of.Account::User::Membership({}) # Kind::Error ({} expected to be a kind of Account::User::Membership)
1144
+
1145
+ Kind.of.Account::User::Membership.or_nil({}) # nil
1146
+
1147
+ Kind.of.Account::User::Membership.instance?({}) # false
1148
+ Kind.of.Account::User::Membership.instance?(membership) # true
1149
+
1150
+ Kind.of.Account::User::Membership.class?(Hash) # false
1151
+ Kind.of.Account::User::Membership.class?(Account::User::Membership) # true
1152
+ ```
1153
+
1154
+ [⬆️ &nbsp;Back to Top](#changelog-)
1155
+
1156
+ 0.6.0 (2020-01-06)
1157
+ ------------------
1158
+
1159
+ ### Added
1160
+
1161
+ * [#11](https://github.com/serradura/kind/pull/11) - Register the `Queue` (`Thread::Queue`) type checker. This registering creates:
1162
+ - `Kind::Of::Queue`, `Kind::Is::Queue`
1163
+
1164
+ [⬆️ &nbsp;Back to Top](#changelog-)
1165
+
1166
+ 0.5.0 (2020-01-04)
1167
+ ------------------
1168
+
1169
+ ### Added
1170
+
1171
+ * [#4](https://github.com/serradura/kind/pull/4) - Allow defining a default value when the verified object is `nil`.
1172
+ ```ruby
1173
+ Kind.of.Hash(nil, or: {}) # {}
1174
+ ```
1175
+
1176
+ [⬆️ &nbsp;Back to Top](#changelog-)
1177
+
1178
+ 0.4.0 (2020-01-03)
1179
+ ------------------
1180
+
1181
+ ### Added
1182
+
1183
+ * [#3](https://github.com/serradura/kind/pull/3) - Require `2.2.0` as the minimum Ruby version.
1184
+
1185
+ [⬆️ &nbsp;Back to Top](#changelog-)
1186
+
1187
+ 0.3.0 (2020-01-03)
1188
+ ------------------
1189
+
1190
+ ### Added
1191
+
1192
+ * [#2](https://github.com/serradura/kind/pull/2) - Add `Kind::Checker` to create an object which knows how to do a type checking. (PR: #2)
1193
+ ```ruby
1194
+ class User
1195
+ end
1196
+
1197
+ user = User.new
1198
+
1199
+ UserKind = Kind::Checker.new(User)
1200
+
1201
+ UserKind.class?(User) # true
1202
+ UserKind.class?(String) # false
1203
+
1204
+ UserKind.instance?(user) # true
1205
+ UserKind.instance?(1) # false
1206
+
1207
+ UserKind.or_nil(user) # #<User:0x0000...>
1208
+ UserKind.or_nil(1) # nil
1209
+ ```
1210
+
1211
+ ### Breaking Changes
1212
+
1213
+ * [#2](https://github.com/serradura/kind/pull/2) - Replace `instance_eval` in modules by singleton objects to define the type checkers (via `Kind::Types.add()`). The behavior still the same, but the constants become a `Kind::Checker` object instead of a module.
1214
+
1215
+ [⬆️ &nbsp;Back to Top](#changelog-)
1216
+
1217
+ 0.2.0 (2020-01-02)
1218
+ ------------------
1219
+
1220
+ ### Added
1221
+
1222
+ * [#1](https://github.com/serradura/kind/pull/1) - Register type checkers for several Ruby classes/modules. (PR: #1)
1223
+ - **Classes:**
1224
+ - `Kind::Of::Symbol` , `Kind::Is::Symbol`
1225
+ - `Kind::Of::Numeric` , `Kind::Is::Numeric`
1226
+ - `Kind::Of::Integer` , `Kind::Is::Integer`
1227
+ - `Kind::Of::Float` , `Kind::Is::Float`
1228
+ - `Kind::Of::Regexp` , `Kind::Is::Regexp`
1229
+ - `Kind::Of::Time` , `Kind::Is::Time`
1230
+ - `Kind::Of::Array` , `Kind::Is::Array`
1231
+ - `Kind::Of::Range` , `Kind::Is::Range`
1232
+ - `Kind::Of::Hash` , `Kind::Is::Hash`
1233
+ - `Kind::Of::Struct` , `Kind::Is::Struct`
1234
+ - `Kind::Of::Enumerator`, `Kind::Is::Enumerator`
1235
+ - `Kind::Of::Method` , `Kind::Is::Method`
1236
+ - `Kind::Of::Proc` , `Kind::Is::Proc`
1237
+ - `Kind::Of::IO` , `Kind::Is::IO`
1238
+ - `Kind::Of::File` , `Kind::Is::File`
1239
+ - **Modules:**
1240
+ - `Kind::Of::Enumerable`, `Kind::Is::Enumerable`
1241
+ - `Kind::Of::Comparable`, `Kind::Is::Comparable`
1242
+
1243
+ * [#1](https://github.com/serradura/kind/pull/1) - Create special type checkers.
1244
+ - `Kind::Of::Boolean` for check if the given object is `true` or `false`.
1245
+ - `Kind::Of::Lambda` for check if the given object is a `lambda`.
1246
+ - `Kind::Of::Module` for check if the given object is a *module*.
1247
+
1248
+ [⬆️ &nbsp;Back to Top](#changelog-)
1249
+
1250
+ 0.1.0 (2019-12-26)
1251
+ ------------------
1252
+
1253
+ ### Added
1254
+
1255
+ * Require `2.3.0` as the minimum Ruby version.
1256
+
1257
+ * `Kind::Error` for defining type checkers errors.
1258
+
1259
+ * `Kind::Of.call()` for check if the given *class* is the *class/superclass* of object, or if the given *module* is included in the object. `Kind::Error` will be raised, If the object hasn't the expected kind.
1260
+ ```ruby
1261
+ Kind::Of.(String, '') # ''
1262
+ Kind::Of.(String, 1) # Kind::Error (1 expected to be a kind of String)
1263
+ ```
1264
+
1265
+ * `Kind::Of::Class()` for check if the given object is a *class*.
1266
+
1267
+ * `Kind::Is.call()` for check if the first kind is equal or a parent class/module of the second one.
1268
+ ```ruby
1269
+ Kind::Is.(String, String) # true
1270
+ Kind::Is.(Symbol, String) # false
1271
+ ```
1272
+
1273
+ * `Kind.of` is a shortcut for `Kind::Of`.
1274
+
1275
+ * `Kind.is` is a shortcut for `Kind::Is`.
1276
+
1277
+ * `Kind::Types.add` allows the registering of new type checkers.
1278
+ ```ruby
1279
+ # Registering Symbol
1280
+
1281
+ Kind::Type.add(Symbol)
1282
+
1283
+ # Adds a method in the Kind::Is module
1284
+
1285
+ class MySymbol < Symbol
1286
+ end
1287
+
1288
+ Kind.is.Symbol(Symbol) # true
1289
+ Kind.is.Symbol(MySymbol) # true
1290
+ Kind.is.Symbol(String) # false
1291
+
1292
+ # Adds a method in the Kind::Of module
1293
+
1294
+ Kind.of.Symbol(:a) # :a
1295
+ Kind.of.Symbol(1) # Kind::Error (1 expected to be a kind of Symbol)
1296
+
1297
+ # Creates a module in Kind::Of with type checking methods related to the given kind.
1298
+
1299
+ Kind::Of::Symbol.class?(Symbol) # true
1300
+ Kind::Of::Symbol.instance?(:a) # true
1301
+ Kind::Of::Symbol.or_nil(:b) # :b
1302
+ Kind::Of::Symbol.or_nil(1) # nil
1303
+ ```
1304
+
1305
+ * Register the `String` and `Hash` type checkers. This registering creates:
1306
+ - `Kind::Of::Hash`, `Kind::Is::Hash`
1307
+ - `Kind::Of::String`, `Kind::Is::String`
1308
+
1309
+ [⬆️ &nbsp;Back to Top](#changelog-)