kind 5.0.0 → 5.4.1

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 (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