kind 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (99) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -1
  3. data/.travis.sh +35 -10
  4. data/CHANGELOG.md +364 -26
  5. data/README.md +37 -36
  6. data/lib/kind.rb +2 -49
  7. data/lib/kind/__lib__/attributes.rb +66 -0
  8. data/lib/kind/__lib__/kind.rb +71 -0
  9. data/lib/kind/__lib__/undefined.rb +14 -0
  10. data/lib/kind/action.rb +92 -0
  11. data/lib/kind/active_model/validation.rb +1 -1
  12. data/lib/kind/basic.rb +73 -0
  13. data/lib/kind/basic/error.rb +29 -0
  14. data/lib/kind/{core → basic}/undefined.rb +6 -1
  15. data/lib/kind/{core/dig.rb → dig.rb} +20 -4
  16. data/lib/kind/either.rb +30 -0
  17. data/lib/kind/either/left.rb +29 -0
  18. data/lib/kind/either/methods.rb +17 -0
  19. data/lib/kind/either/monad.rb +65 -0
  20. data/lib/kind/either/monad/wrapper.rb +19 -0
  21. data/lib/kind/either/right.rb +38 -0
  22. data/lib/kind/{core/empty.rb → empty.rb} +2 -0
  23. data/lib/kind/{core/empty → empty}/constant.rb +0 -0
  24. data/lib/kind/enum.rb +63 -0
  25. data/lib/kind/enum/item.rb +40 -0
  26. data/lib/kind/enum/methods.rb +72 -0
  27. data/lib/kind/function.rb +47 -0
  28. data/lib/kind/functional.rb +89 -0
  29. data/lib/kind/functional/action.rb +89 -0
  30. data/lib/kind/immutable_attributes.rb +34 -0
  31. data/lib/kind/immutable_attributes/initializer.rb +70 -0
  32. data/lib/kind/immutable_attributes/reader.rb +38 -0
  33. data/lib/kind/maybe.rb +69 -0
  34. data/lib/kind/maybe/methods.rb +21 -0
  35. data/lib/kind/maybe/monad.rb +82 -0
  36. data/lib/kind/maybe/monad/wrapper.rb +19 -0
  37. data/lib/kind/{core/maybe → maybe}/none.rb +11 -18
  38. data/lib/kind/maybe/some.rb +132 -0
  39. data/lib/kind/maybe/typed.rb +35 -0
  40. data/lib/kind/{core/maybe/wrappable.rb → maybe/wrapper.rb} +8 -4
  41. data/lib/kind/monad.rb +22 -0
  42. data/lib/kind/monads.rb +5 -0
  43. data/lib/kind/objects.rb +17 -0
  44. data/lib/kind/objects/basic_object.rb +45 -0
  45. data/lib/kind/objects/modules.rb +32 -0
  46. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/array.rb +3 -1
  47. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/class.rb +1 -1
  48. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/comparable.rb +1 -1
  49. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/enumerable.rb +1 -1
  50. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/enumerator.rb +1 -1
  51. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/file.rb +1 -1
  52. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/float.rb +1 -1
  53. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/hash.rb +3 -1
  54. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/integer.rb +1 -1
  55. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/io.rb +1 -1
  56. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/method.rb +1 -1
  57. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/module.rb +1 -1
  58. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/numeric.rb +1 -1
  59. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/proc.rb +1 -1
  60. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/queue.rb +1 -1
  61. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/range.rb +1 -1
  62. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/regexp.rb +1 -1
  63. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/string.rb +3 -1
  64. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/struct.rb +1 -1
  65. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/symbol.rb +1 -1
  66. data/lib/kind/{core/type_checkers/ruby → objects/modules/core}/time.rb +1 -1
  67. data/lib/kind/{core/type_checkers → objects/modules}/custom/boolean.rb +2 -2
  68. data/lib/kind/{core/type_checkers → objects/modules}/custom/callable.rb +1 -1
  69. data/lib/kind/{core/type_checkers → objects/modules}/custom/lambda.rb +1 -1
  70. data/lib/kind/{core/type_checkers → objects/modules}/stdlib/open_struct.rb +3 -1
  71. data/lib/kind/{core/type_checkers → objects/modules}/stdlib/set.rb +3 -1
  72. data/lib/kind/objects/nil.rb +17 -0
  73. data/lib/kind/objects/not_nil.rb +13 -0
  74. data/lib/kind/objects/object.rb +56 -0
  75. data/lib/kind/objects/respond_to.rb +30 -0
  76. data/lib/kind/objects/union_type.rb +44 -0
  77. data/lib/kind/{core/presence.rb → presence.rb} +4 -2
  78. data/lib/kind/result.rb +31 -0
  79. data/lib/kind/result/abstract.rb +53 -0
  80. data/lib/kind/result/failure.rb +31 -0
  81. data/lib/kind/result/methods.rb +17 -0
  82. data/lib/kind/result/monad.rb +69 -0
  83. data/lib/kind/result/monad/wrapper.rb +19 -0
  84. data/lib/kind/result/success.rb +40 -0
  85. data/lib/kind/try.rb +46 -0
  86. data/lib/kind/validator.rb +14 -10
  87. data/lib/kind/version.rb +1 -1
  88. metadata +81 -47
  89. data/lib/kind/core.rb +0 -15
  90. data/lib/kind/core/error.rb +0 -15
  91. data/lib/kind/core/maybe.rb +0 -42
  92. data/lib/kind/core/maybe/result.rb +0 -51
  93. data/lib/kind/core/maybe/some.rb +0 -90
  94. data/lib/kind/core/maybe/typed.rb +0 -29
  95. data/lib/kind/core/try.rb +0 -34
  96. data/lib/kind/core/type_checker.rb +0 -87
  97. data/lib/kind/core/type_checkers.rb +0 -30
  98. data/lib/kind/core/utils/kind.rb +0 -61
  99. data/lib/kind/core/utils/undefined.rb +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0115f034c70fde8d181ffb42e0d2fddb0bb7376e84120d8f7017ce9708ccab53
4
- data.tar.gz: 1e24f96749ad14ce29bf86314423be332a7a424ff9c562e7451d2ab0d08a7fef
3
+ metadata.gz: e522116072626ac76a87df9351e292f31a0f96cefa1bbc07d9e83c50198a25a8
4
+ data.tar.gz: 529cd2b05c6767c2553ce9fa1e157cef564e7fc0092874839c6714e0df797240
5
5
  SHA512:
6
- metadata.gz: 675a83c3e389538b39d75772b55b5f0ce179b2bedd3234ee973865312aa9bbe8e681350412597bca0ce3e7842878f27004139b88c2b8489c0c27f4d1cd6238fd
7
- data.tar.gz: 03d5592c9bd8eaa9591aa7b914feae2ab60678ead26aba64f7f175c673e26a584c2d3fd32bec20fb868c28e101f96e0a2bcf5e14effb15148cb905b4ca8b548d
6
+ metadata.gz: 206cacdc59d7288b4db022dac5c45fe95649845bb0093fbee14eb86444b145651407847b380b831c8267190f1d515b7c775810549c6ee73df61059f1d484129a
7
+ data.tar.gz: ff97ce3f297254fd3932b853588c6d1f47a931c16065b5961e06fc4fe219ec6672db0fe16e1d0ffef4b34d25c6e9c35cc28c655b3cc539b519e916f60162ba04
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 2.7.2
1
+ ruby 3.0.0
data/.travis.sh CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  RUBY_V=$(ruby -v)
4
4
 
5
+ function run_basic_tests {
6
+ if [ ! -z "$1" ]; then
7
+ bundle_cmd="bundle _$1_"
8
+ else
9
+ bundle_cmd="bundle"
10
+ fi
11
+
12
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/{basic/*_test,basic_test}.rb'"
13
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/enum_test.rb'"
14
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/presence_test.rb'"
15
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/dig_test.rb'"
16
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/try_test.rb'"
17
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/maybe_test.rb'"
18
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/immutable_attributes_test.rb'"
19
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/function_test.rb'"
20
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/action_test.rb'"
21
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/{functional/*_test,functional_test}.rb'"
22
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/either/*_test.rb'"
23
+ eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/result/*_test.rb'"
24
+ }
25
+
5
26
  function run_with_bundler {
6
27
  rm Gemfile.lock
7
28
 
@@ -19,17 +40,17 @@ function run_with_am_version_and_bundler {
19
40
  run_with_bundler "$2" "ACTIVEMODEL_VERSION=$1"
20
41
  }
21
42
 
22
- if [[ $RUBY_V =~ "ruby 2.[12]." ]]; then
23
- run_with_bundler "$BUNDLER_V1"
43
+ RUBY_2_12="ruby 2.[12]."
44
+ RUBY_2_2345="ruby 2.[2345]."
45
+ RUBY_2_12345="ruby 2.[12345]."
46
+ RUBY_2_567="ruby 2.[567]."
47
+ RUBY_3_0="ruby 3.0."
24
48
 
49
+ if [[ $RUBY_V =~ $RUBY_2_12 ]]; then
25
50
  run_with_am_version_and_bundler "3.2" "$BUNDLER_V1"
26
51
  fi
27
52
 
28
- RUBY_2_2345="ruby 2.[2345]."
29
-
30
53
  if [[ $RUBY_V =~ $RUBY_2_2345 ]]; then
31
- run_with_bundler "$BUNDLER_V1"
32
-
33
54
  run_with_am_version_and_bundler "4.0" "$BUNDLER_V1"
34
55
  run_with_am_version_and_bundler "4.1" "$BUNDLER_V1"
35
56
  run_with_am_version_and_bundler "4.2" "$BUNDLER_V1"
@@ -38,13 +59,17 @@ if [[ $RUBY_V =~ $RUBY_2_2345 ]]; then
38
59
  run_with_am_version_and_bundler "5.2" "$BUNDLER_V1"
39
60
  fi
40
61
 
41
- RUBY_2_567="ruby 2.[567]."
42
- RUBY_3_x_x="ruby 3.0."
62
+ if [[ $RUBY_V =~ $RUBY_2_12345 ]]; then
63
+ run_basic_tests "$BUNDLER_V1"
64
+ run_with_bundler "$BUNDLER_V1"
65
+ fi
43
66
 
44
- if [[ $RUBY_V =~ $RUBY_2_567 ]] || [[ $RUBY_V =~ $RUBY_3_x_x ]]; then
67
+ if [[ $RUBY_V =~ $RUBY_2_567 ]] || [[ $RUBY_V =~ $RUBY_3_0 ]]; then
45
68
  gem install bundler -v ">= 2" --no-doc
46
69
 
47
- run_with_bundler
48
70
  run_with_am_version_and_bundler "6.0"
49
71
  run_with_am_version_and_bundler "6.1"
72
+
73
+ run_basic_tests
74
+ run_with_bundler
50
75
  fi
data/CHANGELOG.md CHANGED
@@ -3,69 +3,73 @@
3
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
4
 
5
5
  - [Unreleased](#unreleased)
6
- - [5.1.0 (2021-02-23)](#510-2021-02-23)
6
+ - [5.2.0 (2021-03-17)](#520-2021-03-17)
7
7
  - [Added](#added)
8
8
  - [Deprecated](#deprecated)
9
+ - [Changes](#changes)
10
+ - [5.1.0 (2021-02-23)](#510-2021-02-23)
11
+ - [Added](#added-1)
12
+ - [Deprecated](#deprecated-1)
9
13
  - [5.0.0 (2021-02-22)](#500-2021-02-22)
10
14
  - [Breaking Changes](#breaking-changes)
11
15
  - [Removed](#removed)
12
16
  - [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
17
  - [Added](#added-2)
16
- - [Deprecated](#deprecated-1)
18
+ - [4.0.0 (2021-02-22)](#400-2021-02-22)
19
+ - [Added](#added-3)
20
+ - [Deprecated](#deprecated-2)
17
21
  - [Fixed](#fixed)
18
22
  - [3.1.0 (2020-07-08)](#310-2020-07-08)
19
- - [Added](#added-3)
23
+ - [Added](#added-4)
20
24
  - [3.0.0 (2020-06-25)](#300-2020-06-25)
21
25
  - [Breaking Changes](#breaking-changes-1)
22
- - [Added](#added-4)
23
- - [2.3.0 (2020-06-24)](#230-2020-06-24)
24
26
  - [Added](#added-5)
25
- - [2.2.0 (2020-06-23)](#220-2020-06-23)
27
+ - [2.3.0 (2020-06-24)](#230-2020-06-24)
26
28
  - [Added](#added-6)
27
- - [2.1.0 (2020-05-12)](#210-2020-05-12)
29
+ - [2.2.0 (2020-06-23)](#220-2020-06-23)
28
30
  - [Added](#added-7)
31
+ - [2.1.0 (2020-05-12)](#210-2020-05-12)
32
+ - [Added](#added-8)
29
33
  - [Breaking Changes](#breaking-changes-2)
30
34
  - [2.0.0 (2020-05-07)](#200-2020-05-07)
31
- - [Added](#added-8)
35
+ - [Added](#added-9)
32
36
  - [Breaking Changes](#breaking-changes-3)
33
37
  - [Removed](#removed-1)
34
38
  - [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
39
  - [Added](#added-10)
40
+ - [1.8.0 (2020-05-03)](#180-2020-05-03)
41
+ - [Added](#added-11)
38
42
  - [1.7.0 (2020-05-03)](#170-2020-05-03)
39
43
  - [Fixed](#fixed-1)
40
44
  - [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
45
  - [Added](#added-12)
45
- - [1.4.0 (2020-04-12)](#140-2020-04-12)
46
+ - [Changes](#changes-1)
47
+ - [1.5.0 (2020-04-12)](#150-2020-04-12)
46
48
  - [Added](#added-13)
47
- - [1.3.0 (2020-04-12)](#130-2020-04-12)
49
+ - [1.4.0 (2020-04-12)](#140-2020-04-12)
48
50
  - [Added](#added-14)
49
- - [1.2.0 (2020-04-12)](#120-2020-04-12)
51
+ - [1.3.0 (2020-04-12)](#130-2020-04-12)
50
52
  - [Added](#added-15)
51
- - [1.1.0 (2020-04-09)](#110-2020-04-09)
53
+ - [1.2.0 (2020-04-12)](#120-2020-04-12)
52
54
  - [Added](#added-16)
55
+ - [1.1.0 (2020-04-09)](#110-2020-04-09)
56
+ - [Added](#added-17)
53
57
  - [Fixed](#fixed-2)
54
58
  - [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
59
  - [Added](#added-18)
58
- - [0.5.0 (2020-01-04)](#050-2020-01-04)
60
+ - [0.6.0 (2020-01-06)](#060-2020-01-06)
59
61
  - [Added](#added-19)
60
- - [0.4.0 (2020-01-03)](#040-2020-01-03)
62
+ - [0.5.0 (2020-01-04)](#050-2020-01-04)
61
63
  - [Added](#added-20)
62
- - [0.3.0 (2020-01-03)](#030-2020-01-03)
64
+ - [0.4.0 (2020-01-03)](#040-2020-01-03)
63
65
  - [Added](#added-21)
66
+ - [0.3.0 (2020-01-03)](#030-2020-01-03)
67
+ - [Added](#added-22)
64
68
  - [Breaking Changes](#breaking-changes-4)
65
69
  - [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
70
  - [Added](#added-23)
71
+ - [0.1.0 (2019-12-26)](#010-2019-12-26)
72
+ - [Added](#added-24)
69
73
 
70
74
  ## Unreleased
71
75
 
@@ -77,6 +81,340 @@ This project follows [semver 2.0.0](http://semver.org/spec/v2.0.0.html) and the
77
81
  ### Fixed
78
82
  -->
79
83
 
84
+ 5.2.0 (2021-03-17)
85
+ ------------------
86
+
87
+ ### Added
88
+
89
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind.respond_to?`. This method has two different behaviors, when it receives just one argument it will behave like the native Ruby's
90
+ `respond_to?` method, that is, it will check if the `Kind` method implements some method. But if it receives two arguments, the first one will be the object, and the others (one or more) will be a list of method names that will be used to check if the given object implements them. e.g.
91
+ ```ruby
92
+ Kind.respond_to?(:is?) # true
93
+
94
+ Kind.respond_to?(:foo?) # true
95
+
96
+ # --
97
+
98
+ Kind.respond_to?({}, :fetch, :merge) # true
99
+
100
+ Kind.respond_to?([], :fetch, :merge) # false
101
+ ```
102
+
103
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::UnionType`. This class allows the creation of an object that knows how to compare a value through different kinds of types. e.g.
104
+ ```ruby
105
+ # The method [] can build a union type object that will have the method #|
106
+ # which allows the composition with other object kinds.
107
+ array_or_hash = Kind::UnionType[Array] | Hash
108
+
109
+ # The method === can verify if a given value is one of the kinds that compounds the union type.
110
+ array_or_hash === {} # true
111
+ array_or_hash === [] # true
112
+ array_or_hash === 1 # false
113
+ array_or_hash === nil # false
114
+
115
+ # The method #[] will return the given value if it has one of the expected kinds,
116
+ # but if not, it will raise a Kind::Error.
117
+ array_or_hash[{}] # {}
118
+
119
+ array_or_hash[1] # Kind::Error (1 expected to be a kind of (Array | Hash))
120
+
121
+ # At last, the method #name is an alias to the method #inspect.
122
+ array_or_hash.name # "(Array | Hash)"
123
+ array_or_hash.inspect # "(Array | Hash)"
124
+ ```
125
+
126
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Nil`. This module was added to be used to create union types. e.g.
127
+ ```ruby
128
+ hash_or_nil = Kind::UnionType[Hash] | Kind::Nil
129
+
130
+ hash_or_nil === {} # true
131
+ hash_or_nil === [] # false
132
+ hash_or_nil === 1 # false
133
+ hash_or_nil === nil # true
134
+ ```
135
+
136
+ * [#46](https://github.com/serradura/kind/pull/46), [#47](https://github.com/serradura/kind/pull/47) - Add `Kind::NotNil`. This module was added to perform a strict verification where the given value will be returned if it is not nil, and if not, a `Kind::Error` will be raised. e.g.
137
+ ```ruby
138
+ Kind::NotNil[1] # 1
139
+
140
+ Kind::NotNil[nil] # Kind::Error (expected to not be nil)
141
+
142
+ Kind::NotNil[nil, label: 'Foo#bar'] # Kind::Error (Foo#bar: expected to not be nil)
143
+ ```
144
+
145
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::RespondTo` to create objects that know how to verify if a given object implements one or more expected methods.
146
+ ```ruby
147
+ HashLike = Kind::RespondTo[:fetch, :merge!]
148
+ Fetchable = Kind::RespondTo[:fetch]
149
+
150
+ # Verifying if an object implements the expected interface.
151
+ HashLike === ENV # true
152
+ HashLike === {} # true
153
+ HashLike === [] # false
154
+
155
+ Fetchable === ENV # true
156
+ Fetchable === [] # true
157
+ Fetchable === {} # true
158
+
159
+ # Performing an strict verification
160
+ HashLike[ENV] # true
161
+ HashLike[{}] # true
162
+ HashLike[Array.new] # false Kind::Error ([] expected to be a kind of Kind::RespondTo[:fetch, :merge!])
163
+
164
+ # Creating union types using interfaces
165
+ HashLikeOrArray = HashLike | Array # Kind::RespondTo[:fetch, :merge!] | Array
166
+
167
+ HashLikeOrArray === {} # true
168
+ HashLikeOrArray === [] # true
169
+ HashLikeOrArray === ENV # true
170
+ ```
171
+
172
+ * [#46](https://github.com/serradura/kind/pull/46) - Unfreeze the output of `Kind::Boolean.kind`.
173
+
174
+ * [#46](https://github.com/serradura/kind/pull/46) - Freeze `Kind::UNDEFINED` and define its inspect method.
175
+
176
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::TypeChecker#|` to allow the creation of union types.
177
+ ```ruby
178
+ StatusLabel = Kind::String | Kind::Symbol
179
+
180
+ StatusLabel === :ok # true
181
+ StatusLabel === 'ok' # true
182
+ StatusLabel === true # false
183
+ ```
184
+
185
+ * [#46](https://github.com/serradura/kind/pull/46) - Allow `Kind.of()` and `Kind::TypeChecker#[]` receive a label.
186
+ ```ruby
187
+ # Kind.of(<Type>, value, label:)
188
+ class Person
189
+ attr_reader :name
190
+
191
+ def initialize(name:)
192
+ @name = Kind.of(String, name, label: 'Person#name')
193
+ end
194
+ end
195
+
196
+ Person.new(name: 'Rodrigo') # #<Person:0x0000... @name="Rodrigo">
197
+ Person.new(name: :ok) # Kind::Error (Person#name: :ok expected to be a kind of String)
198
+
199
+ # Kind<Type>[value, label:]
200
+ class User
201
+ attr_reader :name
202
+
203
+ def initialize(name:)
204
+ @name = Kind::String[name, label: 'User#name']
205
+ end
206
+ end
207
+
208
+ User.new(name: 'Rodrigo') # #<User:0x0000... @name="Rodrigo">
209
+ User.new(name: :ok) # Kind::Error (User#name: :ok expected to be a kind of String)
210
+ ```
211
+
212
+ * [#46](https://github.com/serradura/kind/pull/46) - Create `kind/basic` to expose a small set of features to do type handling/verification. This is util if you want to make use only of these features instead of all of the others that are loaded via `require "kind"`. So, use `require "kind/basic"` if you only want these features:
213
+ * `Kind.is?`
214
+ * `Kind.of`
215
+ * `Kind.of?`
216
+ * `Kind.of_class?`
217
+ * `Kind.of_module?`
218
+ * `Kind.of_module_or_class`
219
+ * `Kind.respond_to`
220
+ * `Kind.respond_to?`
221
+ * `Kind.value`
222
+ * `Kind::Error`
223
+ * `Kind::Undefined`
224
+
225
+ * [#46](https://github.com/serradura/kind/pull/46) - Improve `Kind::Maybe`.
226
+ * Improve the `#inspect` output.
227
+ * Make `Kind::Maybe.{new,[],wrap}` return `None` if they receive an exception instance.
228
+ * Add `#accept` as an alias of `#check` method.
229
+ * Add `#reject` as the reverse of the methods `#check` and `#accept`.
230
+ * Allow the methods `#map`, `#map!`, `#then`, `#then!`, `#check`, `#accept`, `#reject` to receive one symbol as an argument, it will be used to perform the correspondent method in the `Maybe` value, so if the object responds to the expected method a `Some` will be returned.
231
+ * Add `Kind::Maybe#on`, this method allows you to use a block where will be possible to define a `Some` or `None` handling. The output of the matched result (some or none) will be the block's output.
232
+ ```ruby
233
+ # Kind::Maybe#accept (an alias of Kind::Maybe#check)
234
+ Kind::Maybe[1].accept(&:odd?) # #<Kind::Some value=1>
235
+ Kind::Maybe[1].accept(&:even?) # #<Kind::None value=nil>
236
+
237
+ # Kind::Maybe#reject (the reverse of Kind::Maybe#check)
238
+ Kind::Maybe[1].reject(&:odd?) # #<Kind::None value=nil>
239
+ Kind::Maybe[1].reject(&:even?) # #<Kind::Some value=1>
240
+
241
+ # Passing one symbol as an argument of the methods: `#map`, `#then`, `#check`, `#accept`, `#reject`
242
+ Kind::Maybe['1'].map(:to_i) # #<Kind::Some value=1>
243
+ Kind::Maybe[' '].then(:strip) # #<Kind::Some value="">
244
+
245
+ Kind::Maybe['1'].map!(:to_i).accept(:odd?) # #<Kind::Some value=1>
246
+ Kind::Maybe[' '].then!(:strip).reject(:empty?) # #<Kind::None value=nil>
247
+
248
+ # `Kind::Maybe#on` making use of a block to handle Some or None results.
249
+ number = Kind::Maybe['2'].then(:to_i).reject(:even?).on do |result|
250
+ result.none { 0 }
251
+ result.some { 1 }
252
+ end
253
+
254
+ p number # 0
255
+ ```
256
+
257
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Either` (either monad). This is basically the same as the `Maybe` monad, but with `Some` called `Right` and `None` called `Left`. But this time, `Left` is also allowed to have an underlying value. This module isn't loaded by default, so you will need to require it.
258
+ ```ruby
259
+ require 'kind/either'
260
+
261
+ # Use the methods Kind::Left() or Kind::Right() to create either monads
262
+ Kind::Left(0) # #<Kind::Left value=0>
263
+ Kind::Right(1) # #<Kind::Right value=1>
264
+
265
+ # The Kind::Either.new() or Kind::Either[] also creates a Kind::Right monad
266
+ Kind::Either.new(2) # #<Kind::Right value=2>
267
+ Kind::Either[3] # #<Kind::Right value=3>
268
+
269
+ # An Either has methods that allow you to know what kind it is.
270
+ monad = Kind::Right(1)
271
+ monad.right? # true
272
+ monad.left? # false
273
+
274
+ # This monad allows you to chain a sequence of operations that will continue while the output
275
+ # of each step is a Right monad. So, if some step return a Left, all of the next steps will be avoided.
276
+ # Let's see an example of how you can use the method #map to define a sequence of operations.
277
+
278
+ def do_some_calculation(arg)
279
+ Kind::Right(arg)
280
+ .map { |value| Kind::Numeric?(value) ? Kind::Right(value + 2) : Kind::Left('value must be numeric') }
281
+ .map { |value| value.odd? ? Kind::Right(value) : Kind::Left('value can\'t be even') }
282
+ .map { |value| Kind::Right(value * 3) }
283
+ end
284
+
285
+ do_some_calculation('1') # #<Kind::Left value="value must be numeric">
286
+ do_some_calculation(2) # #<Kind::Left value="value can't be even">
287
+ do_some_calculation(1) # #<Kind::Right value=9>
288
+
289
+ # You can use procs/lambdas as an alternative of blocks
290
+ Add = ->(a, b) do
291
+ return Kind::Right(a + b) if Kind::Numeric?(a, b)
292
+
293
+ Kind::Left('the arguments must be numerics')
294
+ end
295
+
296
+ Double = ->(number) do
297
+ return Kind::Right(number * 2) if Kind::Numeric?(number)
298
+
299
+ Kind::Left('the argument must be numeric')
300
+ end
301
+
302
+ AsString = ->(value) { Kind::Right(value.to_s) }
303
+
304
+ Add.(1, 2).map(&Double).map(&Double) # #<Kind::Right value=12>
305
+ Add.(1, 2).map(&AsString).map(&Double) # #<Kind::Left value="the argument must be numeric">
306
+
307
+ # The method #then is an alias for #map
308
+ Add.(2, 2).then(&Double).then(&AsString) # #<Kind::Right value="8">
309
+
310
+ # An exception will occur when your block or lambda doesn't return a Kind::Either
311
+ Add.(2, 2).map { |number| number * 2 } # Kind::Monad::Error (8 expected to be a kind of Kind::Right | Kind::Left)
312
+
313
+ # The methods #map, #then auto handle StandardError exceptions,
314
+ # so Left will be returned when an exception occur.
315
+ Add.(0, 0).map { |number| Kind::Right(10 / number) } # #<Kind::Left value=#<ZeroDivisionError: divided by 0>>
316
+
317
+ # You can use #map! or #then! if you don't want this auto exception handling.
318
+ Add.(0, 0).map! { |number| Kind::Right(10 / number) } # ZeroDivisionError (divided by 0)
319
+
320
+ Add.(0, 0).then! { |number| Kind::Right(10 / number) } # ZeroDivisionError (divided by 0)
321
+ ```
322
+
323
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Result` (an Either monad variation)
324
+
325
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Function`.
326
+
327
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Functional`.
328
+
329
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Try.presence` and improve the input/output handling of `Kind::Try.call`.
330
+
331
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Dig.presence` and improve the input/output handling of `Kind::Dig.call`.
332
+
333
+ * [#47](https://github.com/serradura/kind/pull/47) - Add `Kind.is!`
334
+
335
+ * [#47](https://github.com/serradura/kind/pull/47) - Create aliases to the methods `Kind.of` (`Kind.of!`) and `Kind.respond_to` (`Kind.respond_to!`)
336
+
337
+ * [#47](https://github.com/serradura/kind/pull/47) - Add `Kind[]` as the `Kind::Of()` substitute.
338
+
339
+ * [#49](https://github.com/serradura/kind/pull/49) - Add `Kind::Either::Methods` and `Kind::Result::Methods`
340
+
341
+ * [#49](https://github.com/serradura/kind/pull/49) - Add `Kind::Undefined.empty?`
342
+
343
+ * [#50](https://github.com/serradura/kind/pull/50) - Add `Kind::<Type>.empty_or` as an alias of `Kind::<Type>.value_or_empty`
344
+
345
+ * [#46](https://github.com/serradura/kind/pull/46), [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Functional::Action`.
346
+
347
+ * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Action`.
348
+
349
+ * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Maybe::ImmutableAttributes`.
350
+
351
+ * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Maybe::Methods`.
352
+
353
+ * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Enum`.
354
+
355
+ * [#51](https://github.com/serradura/kind/pull/51) - Modularize all the kind components. So now you can require only the modules/features that do you want, `kind/action` is the minimal requirement for all of them.
356
+ * `kind/action`
357
+ * `kind/dig`
358
+ * `kind/either`
359
+ * `kind/empty`
360
+ * `kind/enum`
361
+ * `kind/function`
362
+ * `kind/functional`
363
+ * `kind/functional/action`
364
+ * `kind/immutable_attributes`
365
+ * `kind/maybe`
366
+ * `kind/objects`
367
+ * `kind/presence`
368
+ * `kind/result`
369
+ * `kind/try`
370
+ * `kind/validator`
371
+
372
+ * [#52](https://github.com/serradura/kind/pull/52) - Improve `Kind::Validator`, now will be possible to make use of `lambdas` or objects that responds to `.===` and `.name` to perform a kind validation. e.g.
373
+ ```ruby
374
+ class User
375
+ include ActiveModel::Validations
376
+
377
+ attr_reader :name, :bool
378
+
379
+ FilledString = ->(value) { value.kind_of?(String) && !value.empty? }
380
+
381
+ Bool = Object.new
382
+ def Bool.===(value)
383
+ value == true || value == false
384
+ end
385
+ def Bool.name; 'Bool'; end
386
+
387
+ validates :name, kind: FilledString
388
+ validates :bool, kind: Bool
389
+
390
+ def initialize(name:, bool:)
391
+ @name, @bool = name, bool
392
+ end
393
+ end
394
+
395
+ user = User.new(name: '', bool: 1)
396
+
397
+ user.valid? # true
398
+ user.errors[:name] # ['invalid kind']
399
+ user.errors[:bool] # ['must be a kind of Bool']
400
+
401
+ User.new(name: 'Serradura', bool: true).valid? # true
402
+ ```
403
+
404
+ * [#52](https://github.com/serradura/kind/pull/52) - Add `Kind::Enum.===`.
405
+
406
+ ### Deprecated
407
+
408
+ * [#47](https://github.com/serradura/kind/pull/47) - Deprecate `Kind.is` and `Kind::Of()`.
409
+
410
+ * [#48](https://github.com/serradura/kind/pull/48) - Deprecate `Kind::Maybe()` and `Kind::Optional()`
411
+
412
+ ### Changes
413
+
414
+ * [#48](https://github.com/serradura/kind/pull/48) - Rename `Kind::TypeChecker` to `Kind::Object` and `Kind::TypeChecker::Object` to `Kind::Object::Instance`.
415
+
416
+ [⬆️ &nbsp;Back to Top](#changelog-)
417
+
80
418
  5.1.0 (2021-02-23)
81
419
  ------------------
82
420