kind 5.0.0 → 5.4.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.tool-versions +1 -1
  3. data/.travis.sh +39 -7
  4. data/.travis.yml +1 -0
  5. data/CHANGELOG.md +506 -28
  6. data/Gemfile +13 -6
  7. data/README.md +50 -42
  8. data/kind.gemspec +3 -3
  9. data/lib/kind.rb +2 -60
  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 -0
  29. data/lib/kind/enum.rb +63 -0
  30. data/lib/kind/enum/item.rb +40 -0
  31. data/lib/kind/enum/methods.rb +72 -0
  32. data/lib/kind/function.rb +45 -0
  33. data/lib/kind/functional.rb +89 -0
  34. data/lib/kind/functional/action.rb +87 -0
  35. data/lib/kind/functional/steps.rb +22 -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} +8 -4
  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 +22 -10
  93. data/lib/kind/validator.rb +111 -0
  94. data/lib/kind/version.rb +1 -1
  95. metadata +83 -42
  96. data/lib/kind/active_model/kind_validator.rb +0 -103
  97. data/lib/kind/core.rb +0 -8
  98. data/lib/kind/core/kind.rb +0 -61
  99. data/lib/kind/core/undefined.rb +0 -7
  100. data/lib/kind/error.rb +0 -15
  101. data/lib/kind/maybe/result.rb +0 -51
  102. data/lib/kind/type_checker.rb +0 -87
  103. data/lib/kind/type_checkers.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8a58bdad80758ce4b68dd663984a2b505dc5bcc346861c8aa0da7826e458d71b
4
- data.tar.gz: 4de72ab2b437c0743e28440ddf7a637a03ee290d03d484157202f2d967b4863c
3
+ metadata.gz: 4b29ece70180bb5064e2d1c598ce81d09dabfe11492a14e4f97efe4f47154565
4
+ data.tar.gz: 927a414846defd4e53430fbb6d5a36b26dbc51b1de6bb81b8bb797f266dca8c8
5
5
  SHA512:
6
- metadata.gz: 8ab61cb4339b6e979e505cf623b391ce9b946b853893b7e32ea734b6ff325ca007b8509b4c66669a90cfbdade64830843ed7ac0a2aeb30eb4324dca11d056c79
7
- data.tar.gz: 04cc0c6f36ab19167de1b13cd484ccd00b576c13f1703ec42017c334e5c270b02e9d77d20f14346b74d2564837cf97024cc3bafc0dd7b7675c4ac8c0b42c5398
6
+ metadata.gz: '018246a93c971ba79591b6a6f6e18417d5c67f8574865a38fa617782ce2419a3941851303b99a90ad31ab5e4362a0465c8b13222096cc17521693a775248b8ae'
7
+ data.tar.gz: dcd4c0ac25fe19b63039d92cd40d006b133cbc662b662933b5ec6b3d95b3fcbbd5767f842a2402a1e28e4f2c831a3c058aa69cac7614964a03df0da2d8a9ba3f
data/.tool-versions CHANGED
@@ -1 +1 @@
1
- ruby 2.7.2
1
+ ruby 3.0.0
data/.travis.sh CHANGED
@@ -2,6 +2,29 @@
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
+ eval "KIND_STRICT=t $bundle_cmd exec rake test TEST='test/kind/strict_disabled_test.rb'"
26
+ }
27
+
5
28
  function run_with_bundler {
6
29
  rm Gemfile.lock
7
30
 
@@ -19,12 +42,17 @@ function run_with_am_version_and_bundler {
19
42
  run_with_bundler "$2" "ACTIVEMODEL_VERSION=$1"
20
43
  }
21
44
 
45
+ RUBY_2_12="ruby 2.[12]."
22
46
  RUBY_2_2345="ruby 2.[2345]."
47
+ RUBY_2_12345="ruby 2.[12345]."
48
+ RUBY_2_567="ruby 2.[567]."
49
+ RUBY_3_0="ruby 3.0."
23
50
 
24
- if [[ $RUBY_V =~ $RUBY_2_2345 ]]; then
25
- run_with_bundler "$BUNDLER_V1"
26
-
51
+ if [[ $RUBY_V =~ $RUBY_2_12 ]]; then
27
52
  run_with_am_version_and_bundler "3.2" "$BUNDLER_V1"
53
+ fi
54
+
55
+ if [[ $RUBY_V =~ $RUBY_2_2345 ]]; then
28
56
  run_with_am_version_and_bundler "4.0" "$BUNDLER_V1"
29
57
  run_with_am_version_and_bundler "4.1" "$BUNDLER_V1"
30
58
  run_with_am_version_and_bundler "4.2" "$BUNDLER_V1"
@@ -33,13 +61,17 @@ if [[ $RUBY_V =~ $RUBY_2_2345 ]]; then
33
61
  run_with_am_version_and_bundler "5.2" "$BUNDLER_V1"
34
62
  fi
35
63
 
36
- RUBY_2_567="ruby 2.[567]."
37
- RUBY_3_x_x="ruby 3.0."
64
+ if [[ $RUBY_V =~ $RUBY_2_12345 ]]; then
65
+ run_basic_tests "$BUNDLER_V1"
66
+ run_with_bundler "$BUNDLER_V1"
67
+ fi
38
68
 
39
- if [[ $RUBY_V =~ $RUBY_2_567 ]] || [[ $RUBY_V =~ $RUBY_3_x_x ]]; then
69
+ if [[ $RUBY_V =~ $RUBY_2_567 ]] || [[ $RUBY_V =~ $RUBY_3_0 ]]; then
40
70
  gem install bundler -v ">= 2" --no-doc
41
71
 
42
- run_with_bundler
43
72
  run_with_am_version_and_bundler "6.0"
44
73
  run_with_am_version_and_bundler "6.1"
74
+
75
+ run_basic_tests
76
+ run_with_bundler
45
77
  fi
data/.travis.yml CHANGED
@@ -7,6 +7,7 @@ cache:
7
7
  - /home/travis/.rvm/
8
8
 
9
9
  rvm:
10
+ - 2.1.10
10
11
  - 2.2.2
11
12
  - 2.3.0
12
13
  - 2.4.0
data/CHANGELOG.md CHANGED
@@ -3,66 +3,79 @@
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.4.1 (2021-03-26)](#541-2021-03-26)
7
+ - [Fixed](#fixed)
8
+ - [5.4.0 (2021-03-25)](#540-2021-03-25)
9
+ - [Added](#added)
10
+ - [5.3.0 (2021-03-23)](#530-2021-03-23)
11
+ - [Added](#added-1)
12
+ - [5.2.0 (2021-03-17)](#520-2021-03-17)
13
+ - [Added](#added-2)
14
+ - [Deprecated](#deprecated)
15
+ - [Changes](#changes)
16
+ - [5.1.0 (2021-02-23)](#510-2021-02-23)
17
+ - [Added](#added-3)
18
+ - [Deprecated](#deprecated-1)
6
19
  - [5.0.0 (2021-02-22)](#500-2021-02-22)
7
20
  - [Breaking Changes](#breaking-changes)
8
21
  - [Removed](#removed)
9
22
  - [4.1.0 (2021-02-22)](#410-2021-02-22)
10
- - [Added](#added)
23
+ - [Added](#added-4)
11
24
  - [4.0.0 (2021-02-22)](#400-2021-02-22)
12
- - [Added](#added-1)
13
- - [Deprecated](#deprecated)
14
- - [Fixed](#fixed)
25
+ - [Added](#added-5)
26
+ - [Deprecated](#deprecated-2)
27
+ - [Fixed](#fixed-1)
15
28
  - [3.1.0 (2020-07-08)](#310-2020-07-08)
16
- - [Added](#added-2)
29
+ - [Added](#added-6)
17
30
  - [3.0.0 (2020-06-25)](#300-2020-06-25)
18
31
  - [Breaking Changes](#breaking-changes-1)
19
- - [Added](#added-3)
32
+ - [Added](#added-7)
20
33
  - [2.3.0 (2020-06-24)](#230-2020-06-24)
21
- - [Added](#added-4)
34
+ - [Added](#added-8)
22
35
  - [2.2.0 (2020-06-23)](#220-2020-06-23)
23
- - [Added](#added-5)
36
+ - [Added](#added-9)
24
37
  - [2.1.0 (2020-05-12)](#210-2020-05-12)
25
- - [Added](#added-6)
38
+ - [Added](#added-10)
26
39
  - [Breaking Changes](#breaking-changes-2)
27
40
  - [2.0.0 (2020-05-07)](#200-2020-05-07)
28
- - [Added](#added-7)
41
+ - [Added](#added-11)
29
42
  - [Breaking Changes](#breaking-changes-3)
30
43
  - [Removed](#removed-1)
31
44
  - [1.9.0 (2020-05-06)](#190-2020-05-06)
32
- - [Added](#added-8)
45
+ - [Added](#added-12)
33
46
  - [1.8.0 (2020-05-03)](#180-2020-05-03)
34
- - [Added](#added-9)
47
+ - [Added](#added-13)
35
48
  - [1.7.0 (2020-05-03)](#170-2020-05-03)
36
- - [Fixed](#fixed-1)
49
+ - [Fixed](#fixed-2)
37
50
  - [1.6.0 (2020-04-17)](#160-2020-04-17)
38
- - [Added](#added-10)
39
- - [Changes](#changes)
51
+ - [Added](#added-14)
52
+ - [Changes](#changes-1)
40
53
  - [1.5.0 (2020-04-12)](#150-2020-04-12)
41
- - [Added](#added-11)
54
+ - [Added](#added-15)
42
55
  - [1.4.0 (2020-04-12)](#140-2020-04-12)
43
- - [Added](#added-12)
56
+ - [Added](#added-16)
44
57
  - [1.3.0 (2020-04-12)](#130-2020-04-12)
45
- - [Added](#added-13)
58
+ - [Added](#added-17)
46
59
  - [1.2.0 (2020-04-12)](#120-2020-04-12)
47
- - [Added](#added-14)
60
+ - [Added](#added-18)
48
61
  - [1.1.0 (2020-04-09)](#110-2020-04-09)
49
- - [Added](#added-15)
50
- - [Fixed](#fixed-2)
62
+ - [Added](#added-19)
63
+ - [Fixed](#fixed-3)
51
64
  - [1.0.0 (2020-03-16)](#100-2020-03-16)
52
- - [Added](#added-16)
65
+ - [Added](#added-20)
53
66
  - [0.6.0 (2020-01-06)](#060-2020-01-06)
54
- - [Added](#added-17)
67
+ - [Added](#added-21)
55
68
  - [0.5.0 (2020-01-04)](#050-2020-01-04)
56
- - [Added](#added-18)
69
+ - [Added](#added-22)
57
70
  - [0.4.0 (2020-01-03)](#040-2020-01-03)
58
- - [Added](#added-19)
71
+ - [Added](#added-23)
59
72
  - [0.3.0 (2020-01-03)](#030-2020-01-03)
60
- - [Added](#added-20)
73
+ - [Added](#added-24)
61
74
  - [Breaking Changes](#breaking-changes-4)
62
75
  - [0.2.0 (2020-01-02)](#020-2020-01-02)
63
- - [Added](#added-21)
76
+ - [Added](#added-25)
64
77
  - [0.1.0 (2019-12-26)](#010-2019-12-26)
65
- - [Added](#added-22)
78
+ - [Added](#added-26)
66
79
 
67
80
  ## Unreleased
68
81
 
@@ -74,6 +87,471 @@ This project follows [semver 2.0.0](http://semver.org/spec/v2.0.0.html) and the
74
87
  ### Fixed
75
88
  -->
76
89
 
90
+ 5.4.1 (2021-03-26)
91
+ ------------------
92
+
93
+ ### Fixed
94
+
95
+ * [#55](https://github.com/serradura/kind/pull/55) - Fix `Kind::Either::Left#value_or` and `Kind::Result::Failure#value_or` by allowing them to receive the value of the monad in a call using a block.
96
+
97
+ [⬆️  Back to Top](#changelog-)
98
+
99
+ 5.4.0 (2021-03-25)
100
+ ------------------
101
+
102
+ ### Added
103
+
104
+ * [#54](https://github.com/serradura/kind/pull/54) - Add `Kind::Functional::Steps` to allow the usage of `Step`, `Map`, `Try`, `Tee`, `Check`, `Success` and `Failure` in any kind of object.
105
+ ```ruby
106
+ # Usage in classes' instances
107
+
108
+ class BaseJob
109
+ def self.perform_now(input); new.perform(input); end
110
+
111
+ def perform(input); raise NotImplementedError; end
112
+ end
113
+
114
+ class CreateUserJob < BaseJob
115
+ include Kind::Functional::Steps
116
+
117
+ def perform(input)
118
+ validate(input) \
119
+ >> Step(:create) \
120
+ >> Step(:welcome_email)
121
+ end
122
+
123
+ private
124
+
125
+ def validate(input)
126
+ # Success() or Failure()
127
+ end
128
+
129
+ def create(input)
130
+ # Success() or Failure()
131
+ end
132
+
133
+ def welcome_email(email)
134
+ # Success() or Failure()
135
+ end
136
+ end
137
+
138
+ # Usage in modules (singleton methods)
139
+
140
+ module CreateUser
141
+ extend self, Kind::Functional::Steps
142
+
143
+ def perform(input)
144
+ Step!(:validate, input) \
145
+ >> Step(:create) \
146
+ >> Step(:welcome_email)
147
+ end
148
+
149
+ private
150
+
151
+ def validate(input)
152
+ # Success() or Failure()
153
+ end
154
+
155
+ def create(input)
156
+ # Success() or Failure()
157
+ end
158
+
159
+ def welcome_email(email)
160
+ # Success() or Failure()
161
+ end
162
+ end
163
+ ```
164
+
165
+ [⬆️ &nbsp;Back to Top](#changelog-)
166
+
167
+ 5.3.0 (2021-03-23)
168
+ ------------------
169
+
170
+ ### Added
171
+
172
+ * [#53](https://github.com/serradura/kind/pull/53) - Allow `Kind::Result#map` and `Kind::Result#map!` receive a callable as an argument.
173
+
174
+ * [#53](https://github.com/serradura/kind/pull/53) - Add `|` and `>>` as an alias of `Kind::Result#map!`.
175
+
176
+ * [#53](https://github.com/serradura/kind/pull/53) - Add step adapters for `Kind::Action` and `Kind::Functional::Action`. This is the list of methods: `Step`, `Map`, `Try`, `Tee`, `Check`.
177
+ ```ruby
178
+ module CreateUser
179
+ extend Kind::Functional::Action
180
+
181
+ def call!(input)
182
+ Step!(:validate, input) \
183
+ | Step(:create)
184
+ end
185
+
186
+ private
187
+
188
+ def validate(input)
189
+ # returns Success(valid_data) or Failure(validation)
190
+ end
191
+
192
+ def create(input)
193
+ # returns Success(user)
194
+ end
195
+ end
196
+ ```
197
+
198
+ * [#53](https://github.com/serradura/kind/pull/53) - Add `kind/strict/disabled` to turn off all of the strict validations and optimize the runtime. Use case: As strict validation is useful in development, this mechanism could be used to optimize the runtime in production. List of methods that will be disabled:
199
+ * `Kind.of()`
200
+ * `Kind.of_class()`
201
+ * `Kind.of_module()`
202
+ * `Kind.of_module_or_class()`
203
+ * `Kind::<Type>[1]`
204
+ * `Kind::NotNil[1]`
205
+
206
+ [⬆️ &nbsp;Back to Top](#changelog-)
207
+
208
+ 5.2.0 (2021-03-17)
209
+ ------------------
210
+
211
+ ### Added
212
+
213
+ * [#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
214
+ `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.
215
+ ```ruby
216
+ Kind.respond_to?(:is?) # true
217
+
218
+ Kind.respond_to?(:foo?) # true
219
+
220
+ # --
221
+
222
+ Kind.respond_to?({}, :fetch, :merge) # true
223
+
224
+ Kind.respond_to?([], :fetch, :merge) # false
225
+ ```
226
+
227
+ * [#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.
228
+ ```ruby
229
+ # The method [] can build a union type object that will have the method #|
230
+ # which allows the composition with other object kinds.
231
+ array_or_hash = Kind::UnionType[Array] | Hash
232
+
233
+ # The method === can verify if a given value is one of the kinds that compounds the union type.
234
+ array_or_hash === {} # true
235
+ array_or_hash === [] # true
236
+ array_or_hash === 1 # false
237
+ array_or_hash === nil # false
238
+
239
+ # The method #[] will return the given value if it has one of the expected kinds,
240
+ # but if not, it will raise a Kind::Error.
241
+ array_or_hash[{}] # {}
242
+
243
+ array_or_hash[1] # Kind::Error (1 expected to be a kind of (Array | Hash))
244
+
245
+ # At last, the method #name is an alias to the method #inspect.
246
+ array_or_hash.name # "(Array | Hash)"
247
+ array_or_hash.inspect # "(Array | Hash)"
248
+ ```
249
+
250
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Nil`. This module was added to be used to create union types. e.g.
251
+ ```ruby
252
+ hash_or_nil = Kind::UnionType[Hash] | Kind::Nil
253
+
254
+ hash_or_nil === {} # true
255
+ hash_or_nil === [] # false
256
+ hash_or_nil === 1 # false
257
+ hash_or_nil === nil # true
258
+ ```
259
+
260
+ * [#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.
261
+ ```ruby
262
+ Kind::NotNil[1] # 1
263
+
264
+ Kind::NotNil[nil] # Kind::Error (expected to not be nil)
265
+
266
+ Kind::NotNil[nil, label: 'Foo#bar'] # Kind::Error (Foo#bar: expected to not be nil)
267
+ ```
268
+
269
+ * [#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.
270
+ ```ruby
271
+ HashLike = Kind::RespondTo[:fetch, :merge!]
272
+ Fetchable = Kind::RespondTo[:fetch]
273
+
274
+ # Verifying if an object implements the expected interface.
275
+ HashLike === ENV # true
276
+ HashLike === {} # true
277
+ HashLike === [] # false
278
+
279
+ Fetchable === ENV # true
280
+ Fetchable === [] # true
281
+ Fetchable === {} # true
282
+
283
+ # Performing an strict verification
284
+ HashLike[ENV] # true
285
+ HashLike[{}] # true
286
+ HashLike[Array.new] # false Kind::Error ([] expected to be a kind of Kind::RespondTo[:fetch, :merge!])
287
+
288
+ # Creating union types using interfaces
289
+ HashLikeOrArray = HashLike | Array # Kind::RespondTo[:fetch, :merge!] | Array
290
+
291
+ HashLikeOrArray === {} # true
292
+ HashLikeOrArray === [] # true
293
+ HashLikeOrArray === ENV # true
294
+ ```
295
+
296
+ * [#46](https://github.com/serradura/kind/pull/46) - Unfreeze the output of `Kind::Boolean.kind`.
297
+
298
+ * [#46](https://github.com/serradura/kind/pull/46) - Freeze `Kind::UNDEFINED` and define its inspect method.
299
+
300
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::TypeChecker#|` to allow the creation of union types.
301
+ ```ruby
302
+ StatusLabel = Kind::String | Kind::Symbol
303
+
304
+ StatusLabel === :ok # true
305
+ StatusLabel === 'ok' # true
306
+ StatusLabel === true # false
307
+ ```
308
+
309
+ * [#46](https://github.com/serradura/kind/pull/46) - Allow `Kind.of()` and `Kind::TypeChecker#[]` receive a label.
310
+ ```ruby
311
+ # Kind.of(<Type>, value, label:)
312
+ class Person
313
+ attr_reader :name
314
+
315
+ def initialize(name:)
316
+ @name = Kind.of(String, name, label: 'Person#name')
317
+ end
318
+ end
319
+
320
+ Person.new(name: 'Rodrigo') # #<Person:0x0000... @name="Rodrigo">
321
+ Person.new(name: :ok) # Kind::Error (Person#name: :ok expected to be a kind of String)
322
+
323
+ # Kind<Type>[value, label:]
324
+ class User
325
+ attr_reader :name
326
+
327
+ def initialize(name:)
328
+ @name = Kind::String[name, label: 'User#name']
329
+ end
330
+ end
331
+
332
+ User.new(name: 'Rodrigo') # #<User:0x0000... @name="Rodrigo">
333
+ User.new(name: :ok) # Kind::Error (User#name: :ok expected to be a kind of String)
334
+ ```
335
+
336
+ * [#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:
337
+ * `Kind.is?`
338
+ * `Kind.of`
339
+ * `Kind.of?`
340
+ * `Kind.of_class?`
341
+ * `Kind.of_module?`
342
+ * `Kind.of_module_or_class`
343
+ * `Kind.respond_to`
344
+ * `Kind.respond_to?`
345
+ * `Kind.value`
346
+ * `Kind::Error`
347
+ * `Kind::Undefined`
348
+
349
+ * [#46](https://github.com/serradura/kind/pull/46) - Improve `Kind::Maybe`.
350
+ * Improve the `#inspect` output.
351
+ * Make `Kind::Maybe.{new,[],wrap}` return `None` if they receive an exception instance.
352
+ * Add `#accept` as an alias of `#check` method.
353
+ * Add `#reject` as the reverse of the methods `#check` and `#accept`.
354
+ * 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.
355
+ * 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.
356
+ ```ruby
357
+ # Kind::Maybe#accept (an alias of Kind::Maybe#check)
358
+ Kind::Maybe[1].accept(&:odd?) # #<Kind::Some value=1>
359
+ Kind::Maybe[1].accept(&:even?) # #<Kind::None value=nil>
360
+
361
+ # Kind::Maybe#reject (the reverse of Kind::Maybe#check)
362
+ Kind::Maybe[1].reject(&:odd?) # #<Kind::None value=nil>
363
+ Kind::Maybe[1].reject(&:even?) # #<Kind::Some value=1>
364
+
365
+ # Passing one symbol as an argument of the methods: `#map`, `#then`, `#check`, `#accept`, `#reject`
366
+ Kind::Maybe['1'].map(:to_i) # #<Kind::Some value=1>
367
+ Kind::Maybe[' '].then(:strip) # #<Kind::Some value="">
368
+
369
+ Kind::Maybe['1'].map!(:to_i).accept(:odd?) # #<Kind::Some value=1>
370
+ Kind::Maybe[' '].then!(:strip).reject(:empty?) # #<Kind::None value=nil>
371
+
372
+ # `Kind::Maybe#on` making use of a block to handle Some or None results.
373
+ number = Kind::Maybe['2'].then(:to_i).reject(:even?).on do |result|
374
+ result.none { 0 }
375
+ result.some { 1 }
376
+ end
377
+
378
+ p number # 0
379
+ ```
380
+
381
+ [⬆️ &nbsp;Back to Top](#changelog-)
382
+
383
+ * [#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.
384
+ ```ruby
385
+ require 'kind/either'
386
+
387
+ # Use the methods Kind::Left() or Kind::Right() to create either monads
388
+ Kind::Left(0) # #<Kind::Left value=0>
389
+ Kind::Right(1) # #<Kind::Right value=1>
390
+
391
+ # The Kind::Either.new() or Kind::Either[] also creates a Kind::Right monad
392
+ Kind::Either.new(2) # #<Kind::Right value=2>
393
+ Kind::Either[3] # #<Kind::Right value=3>
394
+
395
+ # An Either has methods that allow you to know what kind it is.
396
+ monad = Kind::Right(1)
397
+ monad.right? # true
398
+ monad.left? # false
399
+
400
+ # This monad allows you to chain a sequence of operations that will continue while the output
401
+ # of each step is a Right monad. So, if some step return a Left, all of the next steps will be avoided.
402
+ # Let's see an example of how you can use the method #map to define a sequence of operations.
403
+
404
+ def do_some_calculation(arg)
405
+ Kind::Right(arg)
406
+ .map { |value| Kind::Numeric?(value) ? Kind::Right(value + 2) : Kind::Left('value must be numeric') }
407
+ .map { |value| value.odd? ? Kind::Right(value) : Kind::Left('value can\'t be even') }
408
+ .map { |value| Kind::Right(value * 3) }
409
+ end
410
+
411
+ do_some_calculation('1') # #<Kind::Left value="value must be numeric">
412
+ do_some_calculation(2) # #<Kind::Left value="value can't be even">
413
+ do_some_calculation(1) # #<Kind::Right value=9>
414
+
415
+ # You can use procs/lambdas as an alternative of blocks
416
+ Add = ->(a, b) do
417
+ return Kind::Right(a + b) if Kind::Numeric?(a, b)
418
+
419
+ Kind::Left('the arguments must be numerics')
420
+ end
421
+
422
+ Double = ->(number) do
423
+ return Kind::Right(number * 2) if Kind::Numeric?(number)
424
+
425
+ Kind::Left('the argument must be numeric')
426
+ end
427
+
428
+ AsString = ->(value) { Kind::Right(value.to_s) }
429
+
430
+ Add.(1, 2).map(&Double).map(&Double) # #<Kind::Right value=12>
431
+ Add.(1, 2).map(&AsString).map(&Double) # #<Kind::Left value="the argument must be numeric">
432
+
433
+ # The method #then is an alias for #map
434
+ Add.(2, 2).then(&Double).then(&AsString) # #<Kind::Right value="8">
435
+
436
+ # An exception will occur when your block or lambda doesn't return a Kind::Either
437
+ Add.(2, 2).map { |number| number * 2 } # Kind::Monad::Error (8 expected to be a kind of Kind::Right | Kind::Left)
438
+
439
+ # The methods #map, #then auto handle StandardError exceptions,
440
+ # so Left will be returned when an exception occur.
441
+ Add.(0, 0).map { |number| Kind::Right(10 / number) } # #<Kind::Left value=#<ZeroDivisionError: divided by 0>>
442
+
443
+ # You can use #map! or #then! if you don't want this auto exception handling.
444
+ Add.(0, 0).map! { |number| Kind::Right(10 / number) } # ZeroDivisionError (divided by 0)
445
+
446
+ Add.(0, 0).then! { |number| Kind::Right(10 / number) } # ZeroDivisionError (divided by 0)
447
+ ```
448
+
449
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Result` (an Either monad variation)
450
+
451
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Function`.
452
+
453
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Functional`.
454
+
455
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Try.presence` and improve the input/output handling of `Kind::Try.call`.
456
+
457
+ * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Dig.presence` and improve the input/output handling of `Kind::Dig.call`.
458
+
459
+ * [#47](https://github.com/serradura/kind/pull/47) - Add `Kind.is!`
460
+
461
+ * [#47](https://github.com/serradura/kind/pull/47) - Create aliases to the methods `Kind.of` (`Kind.of!`) and `Kind.respond_to` (`Kind.respond_to!`)
462
+
463
+ * [#47](https://github.com/serradura/kind/pull/47) - Add `Kind[]` as the `Kind::Of()` substitute.
464
+
465
+ * [#49](https://github.com/serradura/kind/pull/49) - Add `Kind::Either::Methods` and `Kind::Result::Methods`
466
+
467
+ * [#49](https://github.com/serradura/kind/pull/49) - Add `Kind::Undefined.empty?`
468
+
469
+ * [#50](https://github.com/serradura/kind/pull/50) - Add `Kind::<Type>.empty_or` as an alias of `Kind::<Type>.value_or_empty`
470
+
471
+ * [#46](https://github.com/serradura/kind/pull/46), [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Functional::Action`.
472
+
473
+ * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Action`.
474
+
475
+ * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Maybe::ImmutableAttributes`.
476
+
477
+ * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Maybe::Methods`.
478
+
479
+ * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Enum`.
480
+
481
+ * [#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.
482
+ * `kind/action`
483
+ * `kind/dig`
484
+ * `kind/either`
485
+ * `kind/empty`
486
+ * `kind/enum`
487
+ * `kind/function`
488
+ * `kind/functional`
489
+ * `kind/functional/action`
490
+ * `kind/immutable_attributes`
491
+ * `kind/maybe`
492
+ * `kind/objects`
493
+ * `kind/presence`
494
+ * `kind/result`
495
+ * `kind/try`
496
+ * `kind/validator`
497
+
498
+ * [#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.
499
+ ```ruby
500
+ class User
501
+ include ActiveModel::Validations
502
+
503
+ attr_reader :name, :bool
504
+
505
+ FilledString = ->(value) { value.kind_of?(String) && !value.empty? }
506
+
507
+ Bool = Object.new
508
+ def Bool.===(value)
509
+ value == true || value == false
510
+ end
511
+ def Bool.name; 'Bool'; end
512
+
513
+ validates :name, kind: FilledString
514
+ validates :bool, kind: Bool
515
+
516
+ def initialize(name:, bool:)
517
+ @name, @bool = name, bool
518
+ end
519
+ end
520
+
521
+ user = User.new(name: '', bool: 1)
522
+
523
+ user.valid? # true
524
+ user.errors[:name] # ['invalid kind']
525
+ user.errors[:bool] # ['must be a kind of Bool']
526
+
527
+ User.new(name: 'Serradura', bool: true).valid? # true
528
+ ```
529
+
530
+ * [#52](https://github.com/serradura/kind/pull/52) - Add `Kind::Enum.===`.
531
+
532
+ ### Deprecated
533
+
534
+ * [#47](https://github.com/serradura/kind/pull/47) - Deprecate `Kind.is` and `Kind::Of()`.
535
+
536
+ * [#48](https://github.com/serradura/kind/pull/48) - Deprecate `Kind::Maybe()` and `Kind::Optional()`
537
+
538
+ ### Changes
539
+
540
+ * [#48](https://github.com/serradura/kind/pull/48) - Rename `Kind::TypeChecker` to `Kind::Object` and `Kind::TypeChecker::Object` to `Kind::Object::Instance`.
541
+
542
+ [⬆️ &nbsp;Back to Top](#changelog-)
543
+
544
+ 5.1.0 (2021-02-23)
545
+ ------------------
546
+
547
+ ### Added
548
+
549
+ * [#45](https://github.com/serradura/kind/pull/45) - Add support to Ruby `>= 2.1.0`.
550
+
551
+ ### Deprecated
552
+
553
+ * [#45](https://github.com/serradura/kind/pull/45) - `kind/active_model/validation` is deprecated; use `kind/validator` instead.
554
+
77
555
  5.0.0 (2021-02-22)
78
556
  ------------------
79
557