kind 4.0.0 → 5.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -1
  3. data/.travis.sh +39 -7
  4. data/.travis.yml +1 -2
  5. data/CHANGELOG.md +486 -28
  6. data/Gemfile +13 -6
  7. data/README.md +153 -49
  8. data/kind.gemspec +1 -1
  9. data/lib/kind.rb +2 -84
  10. data/lib/kind/__lib__/action_steps.rb +57 -0
  11. data/lib/kind/__lib__/attributes.rb +66 -0
  12. data/lib/kind/__lib__/kind.rb +51 -0
  13. data/lib/kind/__lib__/of.rb +17 -0
  14. data/lib/kind/__lib__/strict.rb +49 -0
  15. data/lib/kind/__lib__/undefined.rb +14 -0
  16. data/lib/kind/action.rb +127 -0
  17. data/lib/kind/active_model/validation.rb +3 -4
  18. data/lib/kind/basic.rb +79 -0
  19. data/lib/kind/basic/error.rb +29 -0
  20. data/lib/kind/{undefined.rb → basic/undefined.rb} +6 -1
  21. data/lib/kind/dig.rb +21 -5
  22. data/lib/kind/either.rb +30 -0
  23. data/lib/kind/either/left.rb +29 -0
  24. data/lib/kind/either/methods.rb +17 -0
  25. data/lib/kind/either/monad.rb +65 -0
  26. data/lib/kind/either/monad/wrapper.rb +19 -0
  27. data/lib/kind/either/right.rb +38 -0
  28. data/lib/kind/empty.rb +2 -2
  29. data/lib/kind/empty/constant.rb +7 -0
  30. data/lib/kind/enum.rb +63 -0
  31. data/lib/kind/enum/item.rb +40 -0
  32. data/lib/kind/enum/methods.rb +72 -0
  33. data/lib/kind/function.rb +45 -0
  34. data/lib/kind/functional.rb +89 -0
  35. data/lib/kind/functional/action.rb +90 -0
  36. data/lib/kind/immutable_attributes.rb +34 -0
  37. data/lib/kind/immutable_attributes/initializer.rb +70 -0
  38. data/lib/kind/immutable_attributes/reader.rb +38 -0
  39. data/lib/kind/maybe.rb +37 -12
  40. data/lib/kind/maybe/methods.rb +21 -0
  41. data/lib/kind/maybe/monad.rb +82 -0
  42. data/lib/kind/maybe/monad/wrapper.rb +19 -0
  43. data/lib/kind/maybe/none.rb +12 -19
  44. data/lib/kind/maybe/some.rb +68 -26
  45. data/lib/kind/maybe/typed.rb +11 -5
  46. data/lib/kind/maybe/{wrappable.rb → wrapper.rb} +9 -7
  47. data/lib/kind/monad.rb +22 -0
  48. data/lib/kind/monads.rb +5 -0
  49. data/lib/kind/objects.rb +17 -0
  50. data/lib/kind/objects/basic_object.rb +43 -0
  51. data/lib/kind/objects/modules.rb +32 -0
  52. data/lib/kind/{type_checkers → objects/modules}/core/array.rb +3 -1
  53. data/lib/kind/{type_checkers → objects/modules}/core/class.rb +1 -1
  54. data/lib/kind/{type_checkers → objects/modules}/core/comparable.rb +1 -1
  55. data/lib/kind/{type_checkers → objects/modules}/core/enumerable.rb +1 -1
  56. data/lib/kind/{type_checkers → objects/modules}/core/enumerator.rb +1 -1
  57. data/lib/kind/{type_checkers → objects/modules}/core/file.rb +1 -1
  58. data/lib/kind/{type_checkers → objects/modules}/core/float.rb +1 -1
  59. data/lib/kind/{type_checkers → objects/modules}/core/hash.rb +3 -1
  60. data/lib/kind/{type_checkers → objects/modules}/core/integer.rb +1 -1
  61. data/lib/kind/{type_checkers → objects/modules}/core/io.rb +1 -1
  62. data/lib/kind/{type_checkers → objects/modules}/core/method.rb +1 -1
  63. data/lib/kind/{type_checkers → objects/modules}/core/module.rb +1 -1
  64. data/lib/kind/{type_checkers → objects/modules}/core/numeric.rb +1 -1
  65. data/lib/kind/{type_checkers → objects/modules}/core/proc.rb +1 -1
  66. data/lib/kind/{type_checkers → objects/modules}/core/queue.rb +1 -1
  67. data/lib/kind/{type_checkers → objects/modules}/core/range.rb +1 -1
  68. data/lib/kind/{type_checkers → objects/modules}/core/regexp.rb +1 -1
  69. data/lib/kind/{type_checkers → objects/modules}/core/string.rb +3 -1
  70. data/lib/kind/{type_checkers → objects/modules}/core/struct.rb +1 -1
  71. data/lib/kind/{type_checkers → objects/modules}/core/symbol.rb +1 -1
  72. data/lib/kind/{type_checkers → objects/modules}/core/time.rb +1 -1
  73. data/lib/kind/{type_checkers → objects/modules}/custom/boolean.rb +2 -2
  74. data/lib/kind/{type_checkers → objects/modules}/custom/callable.rb +1 -1
  75. data/lib/kind/{type_checkers → objects/modules}/custom/lambda.rb +1 -1
  76. data/lib/kind/{type_checkers → objects/modules}/stdlib/open_struct.rb +3 -1
  77. data/lib/kind/{type_checkers → objects/modules}/stdlib/set.rb +3 -1
  78. data/lib/kind/objects/nil.rb +17 -0
  79. data/lib/kind/objects/not_nil.rb +9 -0
  80. data/lib/kind/objects/object.rb +56 -0
  81. data/lib/kind/objects/respond_to.rb +30 -0
  82. data/lib/kind/objects/union_type.rb +44 -0
  83. data/lib/kind/presence.rb +4 -2
  84. data/lib/kind/result.rb +31 -0
  85. data/lib/kind/result/abstract.rb +53 -0
  86. data/lib/kind/result/failure.rb +33 -0
  87. data/lib/kind/result/methods.rb +17 -0
  88. data/lib/kind/result/monad.rb +74 -0
  89. data/lib/kind/result/monad/wrapper.rb +19 -0
  90. data/lib/kind/result/success.rb +53 -0
  91. data/lib/kind/strict/disabled.rb +34 -0
  92. data/lib/kind/try.rb +21 -11
  93. data/lib/kind/validator.rb +111 -0
  94. data/lib/kind/version.rb +1 -1
  95. metadata +78 -48
  96. data/lib/kind/active_model/kind_validator.rb +0 -96
  97. data/lib/kind/core.rb +0 -9
  98. data/lib/kind/core/deprecation.rb +0 -29
  99. data/lib/kind/core/kind.rb +0 -61
  100. data/lib/kind/core/undefined.rb +0 -7
  101. data/lib/kind/deprecations/built_in_type_checkers.rb +0 -23
  102. data/lib/kind/deprecations/checker.rb +0 -16
  103. data/lib/kind/deprecations/checker/factory.rb +0 -31
  104. data/lib/kind/deprecations/checker/protocol.rb +0 -73
  105. data/lib/kind/deprecations/is.rb +0 -35
  106. data/lib/kind/deprecations/of.rb +0 -258
  107. data/lib/kind/deprecations/types.rb +0 -121
  108. data/lib/kind/error.rb +0 -15
  109. data/lib/kind/maybe/result.rb +0 -51
  110. data/lib/kind/type_checker.rb +0 -73
  111. data/lib/kind/type_checkers.rb +0 -30
data/Gemfile CHANGED
@@ -18,24 +18,31 @@ activemodel = case activemodel_version
18
18
 
19
19
  simplecov_version =
20
20
  case RUBY_VERSION
21
- when /\A2.[23]/ then '0.17.1'
21
+ when /\A2.[123]/ then '0.17.1'
22
22
  when /\A2.4/ then '~> 0.18.5'
23
23
  else '~> 0.19'
24
24
  end
25
25
 
26
+ is_ruby_2_1 = RUBY_VERSION <= '2.2.0'
27
+
28
+ minitest_version =
29
+ if activemodel_version
30
+ activemodel_version < '4.1' ? '~> 4.2' : '~> 5.0'
31
+ else
32
+ is_ruby_2_1 ? '~> 4.2' : '~> 5.0'
33
+ end
34
+
26
35
  group :test do
27
36
  if activemodel_version
28
37
  gem 'activesupport', activemodel, require: false
29
- gem 'activemodel', activemodel, require: false
30
- gem 'minitest', activemodel_version < '4.1' ? '~> 4.2' : '~> 5.0'
31
- else
32
- gem 'minitest', '~> 5.0'
38
+ gem 'activemodel' , activemodel, require: false
33
39
  end
34
40
 
41
+ gem 'minitest' , minitest_version
35
42
  gem 'simplecov', simplecov_version, require: false
36
43
  end
37
44
 
38
- gem 'rake', '~> 13.0'
45
+ gem 'rake', is_ruby_2_1 ? '~> 12.3' : '~> 13.0'
39
46
 
40
47
  # Specify your gem's dependencies in type_validator.gemspec
41
48
  gemspec
data/README.md CHANGED
@@ -1,12 +1,9 @@
1
1
  <p align="center">
2
2
  <h1 align="center">🤷 kind</h1>
3
3
  <p align="center"><i>A simple type system (at runtime) for Ruby - free of dependencies.</i></p>
4
- <br>
5
4
  </p>
6
5
 
7
6
  <p align="center">
8
- <img src="https://img.shields.io/badge/ruby->%3D%202.2.0-ruby.svg?colorA=99004d&colorB=cc0066" alt="Ruby">
9
-
10
7
  <a href="https://rubygems.org/gems/kind">
11
8
  <img alt="Gem" src="https://img.shields.io/gem/v/kind.svg?style=flat-square">
12
9
  </a>
@@ -15,6 +12,14 @@
15
12
  <img alt="Build Status" src="https://travis-ci.com/serradura/kind.svg?branch=master">
16
13
  </a>
17
14
 
15
+ <br />
16
+
17
+ <img src="https://img.shields.io/badge/ruby%20%3E=%202.1,%20%3C%203.1-ruby.svg?colorA=99004d&colorB=cc0066" alt="Ruby">
18
+
19
+ <img src="https://img.shields.io/badge/rails%20%3E=%203.2.0,%20%3C%207.0-rails.svg?colorA=8B0000&colorB=FF0000" alt="Rails">
20
+
21
+ <br />
22
+
18
23
  <a href="https://codeclimate.com/github/serradura/kind/maintainability">
19
24
  <img alt="Maintainability" src="https://api.codeclimate.com/v1/badges/711329decb2806ccac95/maintainability">
20
25
  </a>
@@ -34,11 +39,12 @@ One of the goals of this project is to do simple type checking like `"some strin
34
39
 
35
40
  Version | Documentation
36
41
  ---------- | -------------
37
- unreleased | https://github.com/serradura/u-case/blob/main/README.md
38
- 4.0.0 | https://github.com/serradura/u-case/blob/v4.x/README.md
39
- 3.1.0 | https://github.com/serradura/u-case/blob/v3.x/README.md
40
- 2.3.0 | https://github.com/serradura/u-case/blob/v2.x/README.md
41
- 1.9.0 | https://github.com/serradura/u-case/blob/v1.x/README.md
42
+ unreleased | https://github.com/serradura/kind/blob/main/README.md
43
+ 5.3.0 | https://github.com/serradura/kind/blob/v5.x/README.md
44
+ 4.1.0 | https://github.com/serradura/kind/blob/v4.x/README.md
45
+ 3.1.0 | https://github.com/serradura/kind/blob/v3.x/README.md
46
+ 2.3.0 | https://github.com/serradura/kind/blob/v2.x/README.md
47
+ 1.9.0 | https://github.com/serradura/kind/blob/v1.x/README.md
42
48
 
43
49
  ## Table of Contents <!-- omit in toc -->
44
50
  - [Compatibility](#compatibility)
@@ -51,17 +57,18 @@ unreleased | https://github.com/serradura/u-case/blob/main/README.md
51
57
  - [Kind::\<Type\>.or_undefined()](#kindtypeor_undefined)
52
58
  - [Kind::\<Type\>.or()](#kindtypeor)
53
59
  - [Kind::\<Type\>.value()](#kindtypevalue-1)
60
+ - [Kind::\<Type\>.maybe](#kindtypemaybe)
54
61
  - [Kind::\<Type\>?](#kindtype-2)
55
- - [Kind::{Array,Hash,String,Set}.value_or_empty()](#kindarrayhashstringsetvalue_or_empty)
56
- - [List of all type checkers (Kind::<Type>)](#list-of-all-type-checkers-kindtype)
62
+ - [Kind::{Array,Hash,String,Set}.empty_or()](#kindarrayhashstringsetempty_or)
63
+ - [List of all type handlers](#list-of-all-type-handlers)
57
64
  - [Core](#core)
58
65
  - [Stdlib](#stdlib)
59
66
  - [Custom](#custom)
60
- - [Creating type checkers](#creating-type-checkers)
67
+ - [Creating type handlers](#creating-type-handlers)
61
68
  - [Dynamic creation](#dynamic-creation)
62
69
  - [Using a class or a module](#using-a-class-or-a-module)
63
70
  - [Using an object which responds to ===](#using-an-object-which-responds-to-)
64
- - [Kind::<Type> module](#kindtype-module)
71
+ - [Kind::<Type> object](#kindtype-object)
65
72
  - [Utility methods](#utility-methods)
66
73
  - [Kind.of_class?()](#kindof_class)
67
74
  - [Kind.of_module?()](#kindof_module)
@@ -92,11 +99,19 @@ unreleased | https://github.com/serradura/u-case/blob/main/README.md
92
99
  - [Kind::Maybe#try!](#kindmaybetry-1)
93
100
  - [Kind::Maybe#dig](#kindmaybedig)
94
101
  - [Kind::Maybe#check](#kindmaybecheck)
102
+ - [Kind::Maybe#presence](#kindmaybepresence)
95
103
  - [Kind::Empty](#kindempty)
104
+ - [Defining Empty as Kind::Empty an alias](#defining-empty-as-kindempty-an-alias)
96
105
  - [Kind::Validator (ActiveModel::Validations)](#kindvalidator-activemodelvalidations)
97
106
  - [Usage](#usage-1)
98
- - [Defining the default validation strategy](#defining-the-default-validation-strategy)
99
- - [Using the `allow_nil` and `strict` options](#using-the-allow_nil-and-strict-options)
107
+ - [Object#===](#object)
108
+ - [Kind.is](#kindis-1)
109
+ - [Object#instance_of?](#objectinstance_of)
110
+ - [Object#respond_to?](#objectrespond_to)
111
+ - [Array.new.all? { |item| item.kind_of?(Class) }](#arraynewall--item-itemkind_ofclass-)
112
+ - [Array.new.all? { |item| expected_values.include?(item) }](#arraynewall--item-expected_valuesincludeitem-)
113
+ - [Defining the default validation strategy](#defining-the-default-validation-strategy)
114
+ - [Using the `allow_nil` and `strict` options](#using-the-allow_nil-and-strict-options)
100
115
  - [Similar Projects](#similar-projects)
101
116
  - [Development](#development)
102
117
  - [Contributing](#contributing)
@@ -105,10 +120,11 @@ unreleased | https://github.com/serradura/u-case/blob/main/README.md
105
120
 
106
121
  ## Compatibility
107
122
 
108
- | u-case | branch | ruby | activemodel |
123
+ | kind | branch | ruby | activemodel |
109
124
  | -------------- | ------- | -------- | -------------- |
110
- | unreleased | main | >= 2.2.0 | >= 3.2, <= 6.1 |
111
- | 4.0.0 | v4.x | >= 2.2.0 | >= 3.2, <= 6.1 |
125
+ | unreleased | main | >= 2.1.0 | >= 3.2, <= 6.1 |
126
+ | 5.3.0 | v5.x | >= 2.1.0 | >= 3.2, <= 6.1 |
127
+ | 4.1.0 | v4.x | >= 2.2.0 | >= 3.2, <= 6.1 |
112
128
  | 3.1.0 | v3.x | >= 2.2.0 | >= 3.2, <= 6.1 |
113
129
  | 2.3.0 | v2.x | >= 2.2.0 | >= 3.2, <= 6.0 |
114
130
  | 1.9.0 | v1.x | >= 2.2.0 | >= 3.2, <= 6.0 |
@@ -257,6 +273,39 @@ Kind::String.value('1', default: 1) # Kind::Error (1 expected to be a kind of S
257
273
 
258
274
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
259
275
 
276
+ ### Kind::\<Type\>.maybe
277
+
278
+ This method exposes a [typed `Kind::Maybe`](#kindmaybetype) and using it will be possible to apply a sequence of operations in the case of the wrapped value has the expected kind.
279
+
280
+ ```ruby
281
+ Double = ->(value) do
282
+ Kind::Numeric.maybe(value)
283
+ .then { |number| number * 2 }
284
+ .value_or(0)
285
+ end
286
+
287
+ Double.('2') # 0
288
+ Double.(2) # 4
289
+ ```
290
+
291
+ If it is invoked without arguments, it returns the typed Maybe. But, if it receives arguments, it will behave like the `Kind::Maybe.wrap` method. e.g.
292
+
293
+ ```ruby
294
+ Kind::Integer.maybe #<Kind::Maybe::Typed:0x0000... @kind=Kind::Integer>
295
+
296
+ Kind::Integer.maybe(0).some? # true
297
+ Kind::Integer.maybe { 1 }.some? # true
298
+ Kind::Integer.maybe(2) { |n| n * 2 }.some? # true
299
+
300
+ Kind::Integer.maybe { 2 / 0 }.none? # true
301
+ Kind::Integer.maybe(2) { |n| n / 0 }.none? # true
302
+ Kind::Integer.maybe('2') { |n| n * n }.none? # true
303
+ ```
304
+
305
+ > **Note:** You can use `Kind::\<Type\>.optional` as an alias for `Kind::\<Type\>.maybe`.
306
+
307
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
308
+
260
309
  ### Kind::\<Type\>?
261
310
 
262
311
  There is a second way to do a type verification and know if one or multiple values has the expected type. You can use the predicate kind methods (`Kind::Hash?`). e.g:
@@ -279,17 +328,17 @@ collection.select(&Kind::Enumerable?) # [{:number=>1}, {:number=>3}, [:number, 5
279
328
 
280
329
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
281
330
 
282
- ### Kind::{Array,Hash,String,Set}.value_or_empty()
331
+ ### Kind::{Array,Hash,String,Set}.empty_or()
283
332
 
284
- 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 one hasn't the expected kind.
333
+ This method is available for some type handlers (`Kind::Array`, `Kind::Hash`, `Kind::String`, `Kind::Set`), and it will return an empty frozen value if the given one hasn't the expected kind.
285
334
  ```ruby
286
- Kind::Array.value_or_empty({}) # []
287
- Kind::Array.value_or_empty({}).frozen? # true
335
+ Kind::Array.empty_or({}) # []
336
+ Kind::Array.empty_or({}).frozen? # true
288
337
  ```
289
338
 
290
339
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
291
340
 
292
- ### List of all type checkers (Kind::<Type>)
341
+ ### List of all type handlers
293
342
 
294
343
  #### Core
295
344
 
@@ -328,9 +377,9 @@ Kind::Array.value_or_empty({}).frozen? # true
328
377
 
329
378
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
330
379
 
331
- ### Creating type checkers
380
+ ### Creating type handlers
332
381
 
333
- There are two ways to do this, you can create type checkers dynamically or defining a module.
382
+ There are two ways to do this, you can create type handlers dynamically or defining a module.
334
383
 
335
384
  #### Dynamic creation
336
385
 
@@ -346,7 +395,7 @@ kind_of_user = Kind::Of(User)
346
395
 
347
396
  # kind_of_user.name
348
397
  # kind_of_user.kind
349
- # The type checker can return its kind and its name
398
+ # The type handler can return its kind and its name
350
399
  kind_of_user.name # "User"
351
400
  kind_of_user.kind # User
352
401
 
@@ -396,6 +445,10 @@ kind_of_user.value(User.new, default: User.new) # #<User:0x0000...>
396
445
  kind_of_user.value('1', default: User.new) # #<User:0x0000...>
397
446
 
398
447
  kind_of_user.value('1', default: 1) # Kind::Error (1 expected to be a kind of User)
448
+
449
+ # kind_of_user.maybe
450
+ # This method returns a typed Kind::Maybe.
451
+ kind_of_user.maybe('1').value_or(User.new) # #<User:0x0000...>
399
452
  ```
400
453
 
401
454
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
@@ -412,7 +465,7 @@ PositiveInteger = Kind::Of(
412
465
 
413
466
  # PositiveInteger.name
414
467
  # PositiveInteger.kind
415
- # The type checker can return its kind and its name
468
+ # The type handler can return its kind and its name
416
469
  PositiveInteger.name # "PositiveInteger"
417
470
  PositiveInteger.kind # #<Proc:0x0000.... >
418
471
 
@@ -463,13 +516,19 @@ PositiveInteger.value(2, default: 1) # 2
463
516
  PositiveInteger.value('1', default: 1) # 1
464
517
 
465
518
  PositiveInteger.value('1', default: 0) # Kind::Error (0 expected to be a kind of PositiveInteger)
519
+
520
+ # PositiveInteger.maybe
521
+ # This method returns a typed Kind::Maybe.
522
+ PositiveInteger.maybe(0).value_or(1) # 1
523
+
524
+ PositiveInteger.maybe(2).value_or(1) # 2
466
525
  ```
467
526
 
468
527
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
469
528
 
470
- #### Kind::<Type> module
529
+ #### Kind::<Type> object
471
530
 
472
- The idea here is to create a type checker inside of the `Kind` namespace, so to do this, you will only need to use pure Ruby. e.g:
531
+ The idea here is to create a type handler inside of the `Kind` namespace and to do this you will only need to use pure Ruby. e.g:
473
532
 
474
533
  ```ruby
475
534
  class User
@@ -477,9 +536,9 @@ end
477
536
 
478
537
  module Kind
479
538
  module User
480
- extend self, TypeChecker
539
+ extend self, ::Kind::Object
481
540
 
482
- # Define the expected kind of this type checker.
541
+ # Define the expected kind of this type handler.
483
542
  def kind; ::User; end
484
543
  end
485
544
 
@@ -489,7 +548,7 @@ module Kind
489
548
  end
490
549
  end
491
550
 
492
- # Doing this you will have the same methods of a standard type checker (like: `Kind::Symbol`).
551
+ # Doing this you will have the same methods of a standard type handler (like: `Kind::Symbol`).
493
552
 
494
553
  user = User.new
495
554
 
@@ -507,7 +566,7 @@ The advantages of this approach are:
507
566
 
508
567
  The disadvantage is:
509
568
 
510
- 1. You could overwrite some standard type checker or constant. I believe that this will be hard to happen, but must be your concern if you decide to use this kind of approach.
569
+ 1. You could overwrite some standard type handler or constant. I believe that this will be hard to happen, but must be your concern if you decide to use this kind of approach.
511
570
 
512
571
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
513
572
 
@@ -1099,7 +1158,7 @@ def person_name(params)
1099
1158
 
1100
1159
  return default if names.size != 2
1101
1160
 
1102
- first_name, last_name = default
1161
+ first_name, last_name = names
1103
1162
 
1104
1163
  "#{first_name} #{last_name}"
1105
1164
  end
@@ -1126,7 +1185,7 @@ module PersonIntroduction1
1126
1185
  end
1127
1186
 
1128
1187
  def age(optional)
1129
- optional.map { |hash| hash[:age] }.value_or(0)
1188
+ optional.dig(:age).value_or(0)
1130
1189
  end
1131
1190
  end
1132
1191
 
@@ -1336,6 +1395,18 @@ Kind::Maybe(Array)
1336
1395
 
1337
1396
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
1338
1397
 
1398
+ ### Kind::Maybe#presence
1399
+
1400
+ This method will return None if the wrapped value wasn't present.
1401
+
1402
+ ```ruby
1403
+ result = Kind::Maybe(Hash).wrap(foo: '').dig(:foo).presence
1404
+ result.none? # true
1405
+ result.value # nil
1406
+ ```
1407
+
1408
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1409
+
1339
1410
  ## Kind::Empty
1340
1411
 
1341
1412
  When you define a method that has default arguments, for certain data types, you will always create a new object in memory. e.g:
@@ -1366,7 +1437,11 @@ def do_something(value, with_options: Kind::Empty::HASH)
1366
1437
  end
1367
1438
  ```
1368
1439
 
1369
- One last thing, if there is no constant declared as Empty, the `kind` gem will define `Empty` as an alias for `Kind::Empty`. Knowing this, the previous example could be written like this:
1440
+ ### Defining Empty as Kind::Empty an alias
1441
+
1442
+ You can require `kind/empty/constant` to define `Empty` as a `Kind::Empty` alias. But, a `LoadError` will be raised if there is an already defined constant `Empty`.
1443
+
1444
+ So if you required this file, the previous example could be written like this:
1370
1445
 
1371
1446
  ```ruby
1372
1447
  def do_something(value, with_options: Empty::HASH)
@@ -1374,7 +1449,7 @@ def do_something(value, with_options: Empty::HASH)
1374
1449
  end
1375
1450
  ```
1376
1451
 
1377
- Follows the list of constants, if the alias is available to be created:
1452
+ Follows the list of constants if the alias was defined:
1378
1453
 
1379
1454
  - `Empty::SET`
1380
1455
  - `Empty::HASH`
@@ -1385,7 +1460,7 @@ Follows the list of constants, if the alias is available to be created:
1385
1460
 
1386
1461
  ## Kind::Validator (ActiveModel::Validations)
1387
1462
 
1388
- This module enables the capability to validate types via [`ActiveModel::Validations >= 3.2, < 6.1.0`](https://api.rubyonrails.org/classes/ActiveModel/Validations.html). e.g
1463
+ This module enables the capability to validate types via [`ActiveModel::Validations >= 3.2, < 7.0`](https://api.rubyonrails.org/classes/ActiveModel/Validations.html). e.g
1389
1464
 
1390
1465
  ```ruby
1391
1466
  class Person
@@ -1401,26 +1476,37 @@ And to make use of it, you will need to do an explicitly require. e.g:
1401
1476
 
1402
1477
  ```ruby
1403
1478
  # In some Gemfile
1404
- gem 'kind', require: 'kind/active_model/validation'
1479
+ gem 'kind', require: 'kind/validator'
1405
1480
 
1406
1481
  # In some .rb file
1407
- require 'kind/active_model/validation'
1482
+ require 'kind/validator'
1408
1483
  ```
1409
1484
 
1485
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1486
+
1410
1487
  ### Usage
1411
1488
 
1412
- **[Object#kind_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-kind_of-3F)**
1489
+ #### [Object#===](https://ruby-doc.org/core-3.0.0/Object.html#method-i-3D-3D-3D)
1413
1490
 
1414
1491
  ```ruby
1415
1492
  validates :name, kind: { of: String }
1493
+ ```
1416
1494
 
1417
- # Use an array to verify if the attribute
1418
- # is an instance of one of the classes/modules.
1495
+ Use an array to verify if the attribute is an instance of one of the classes/modules.
1419
1496
 
1497
+ ```ruby
1420
1498
  validates :status, kind: { of: [String, Symbol]}
1421
1499
  ```
1422
1500
 
1423
- **[Kind.is](#verifying-the-kind-of-some-classmodule)**
1501
+ Because of kind verification be made via `===` you can use type handlers as the expected kinds.
1502
+
1503
+ ```ruby
1504
+ validates :alive, kind: Kind::Boolean
1505
+ ```
1506
+
1507
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1508
+
1509
+ #### [Kind.is](#verifying-the-kind-of-some-classmodule)
1424
1510
 
1425
1511
  ```ruby
1426
1512
  #
@@ -1456,7 +1542,9 @@ validates :human_kind, kind: { is: Human }
1456
1542
  validates :human_kind, kind: { is: [Person, User] }
1457
1543
  ```
1458
1544
 
1459
- **[Object#instance_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-instance_of-3F)**
1545
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1546
+
1547
+ #### [Object#instance_of?](https://ruby-doc.org/core-3.0.0/Object.html#method-i-instance_of-3F)
1460
1548
 
1461
1549
  ```ruby
1462
1550
  validates :name, kind: { instance_of: String }
@@ -1467,13 +1555,23 @@ validates :name, kind: { instance_of: String }
1467
1555
  validates :name, kind: { instance_of: [String, Symbol] }
1468
1556
  ```
1469
1557
 
1470
- **[Object#respond_to?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-respond_to-3F)**
1558
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1559
+
1560
+ #### [Object#respond_to?](https://ruby-doc.org/core-3.0.0/Object.html#method-i-respond_to-3F)
1471
1561
 
1472
1562
  ```ruby
1473
1563
  validates :handler, kind: { respond_to: :call }
1474
1564
  ```
1475
1565
 
1476
- **Array.new.all? { |item| item.kind_of?(Class) }**
1566
+ This validation can verify one or multiple methods.
1567
+
1568
+ ```ruby
1569
+ validates :params, kind: { respond_to: [:[], :values_at] }
1570
+ ```
1571
+
1572
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1573
+
1574
+ #### Array.new.all? { |item| item.kind_of?(Class) }
1477
1575
 
1478
1576
  ```ruby
1479
1577
  validates :account_types, kind: { array_of: String }
@@ -1484,7 +1582,9 @@ validates :account_types, kind: { array_of: String }
1484
1582
  validates :account_types, kind: { array_of: [String, Symbol] }
1485
1583
  ```
1486
1584
 
1487
- **Array.new.all? { |item| expected_values.include?(item) }**
1585
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1586
+
1587
+ #### Array.new.all? { |item| expected_values.include?(item) }
1488
1588
 
1489
1589
  ```ruby
1490
1590
  # Verifies if the attribute value
@@ -1493,7 +1593,9 @@ validates :account_types, kind: { array_of: [String, Symbol] }
1493
1593
  validates :account_types, kind: { array_with: ['foo', 'bar'] }
1494
1594
  ```
1495
1595
 
1496
- #### Defining the default validation strategy
1596
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1597
+
1598
+ ### Defining the default validation strategy
1497
1599
 
1498
1600
  By default, you can define the attribute type directly (without a hash). e.g.
1499
1601
 
@@ -1515,7 +1617,9 @@ And these are the available options to define the default strategy:
1515
1617
  - `kind_of` *(default)*
1516
1618
  - `instance_of`
1517
1619
 
1518
- #### Using the `allow_nil` and `strict` options
1620
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1621
+
1622
+ ### Using the `allow_nil` and `strict` options
1519
1623
 
1520
1624
  You can use the `allow_nil` option with any of the kind validations. e.g.
1521
1625