kind 4.0.0 → 5.3.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 (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