kind 5.10.0 → 6.0.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.
data/CHANGELOG.md CHANGED
@@ -1,412 +1,152 @@
1
- # Changelog <!-- omit in toc -->
2
-
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
-
5
- - [Unreleased](#unreleased)
6
- - [5.10.0 (2021-09-23)](#5100-2021-09-23)
7
- - [Added](#added)
8
- - [5.9.0 (2021-09-22)](#590-2021-09-22)
9
- - [Added](#added-1)
10
- - [5.8.1 (2021-09-22)](#581-2021-09-22)
11
- - [Fixed](#fixed)
12
- - [5.8.0 (2021-09-22)](#580-2021-09-22)
13
- - [Added](#added-2)
14
- - [5.7.0 (2021-06-22)](#570-2021-06-22)
15
- - [Added](#added-3)
16
- - [5.6.0 (2021-05-14)](#560-2021-05-14)
17
- - [Added](#added-4)
18
- - [5.5.0 (2021-04-05)](#550-2021-04-05)
19
- - [Added](#added-5)
20
- - [5.4.1 (2021-03-26)](#541-2021-03-26)
21
- - [Fixed](#fixed-1)
22
- - [5.4.0 (2021-03-25)](#540-2021-03-25)
23
- - [Added](#added-6)
24
- - [5.3.0 (2021-03-23)](#530-2021-03-23)
25
- - [Added](#added-7)
26
- - [5.2.0 (2021-03-17)](#520-2021-03-17)
27
- - [Added](#added-8)
28
- - [Deprecated](#deprecated)
29
- - [Changes](#changes)
30
- - [5.1.0 (2021-02-23)](#510-2021-02-23)
31
- - [Added](#added-9)
32
- - [Deprecated](#deprecated-1)
33
- - [5.0.0 (2021-02-22)](#500-2021-02-22)
34
- - [Breaking Changes](#breaking-changes)
35
- - [Removed](#removed)
36
- - [4.1.0 (2021-02-22)](#410-2021-02-22)
37
- - [Added](#added-10)
38
- - [4.0.0 (2021-02-22)](#400-2021-02-22)
39
- - [Added](#added-11)
40
- - [Deprecated](#deprecated-2)
41
- - [Fixed](#fixed-2)
42
- - [3.1.0 (2020-07-08)](#310-2020-07-08)
43
- - [Added](#added-12)
44
- - [3.0.0 (2020-06-25)](#300-2020-06-25)
45
- - [Breaking Changes](#breaking-changes-1)
46
- - [Added](#added-13)
47
- - [2.3.0 (2020-06-24)](#230-2020-06-24)
48
- - [Added](#added-14)
49
- - [2.2.0 (2020-06-23)](#220-2020-06-23)
50
- - [Added](#added-15)
51
- - [2.1.0 (2020-05-12)](#210-2020-05-12)
52
- - [Added](#added-16)
53
- - [Breaking Changes](#breaking-changes-2)
54
- - [2.0.0 (2020-05-07)](#200-2020-05-07)
55
- - [Added](#added-17)
56
- - [Breaking Changes](#breaking-changes-3)
57
- - [Removed](#removed-1)
58
- - [1.9.0 (2020-05-06)](#190-2020-05-06)
59
- - [Added](#added-18)
60
- - [1.8.0 (2020-05-03)](#180-2020-05-03)
61
- - [Added](#added-19)
62
- - [1.7.0 (2020-05-03)](#170-2020-05-03)
63
- - [Fixed](#fixed-3)
64
- - [1.6.0 (2020-04-17)](#160-2020-04-17)
65
- - [Added](#added-20)
66
- - [Changes](#changes-1)
67
- - [1.5.0 (2020-04-12)](#150-2020-04-12)
68
- - [Added](#added-21)
69
- - [1.4.0 (2020-04-12)](#140-2020-04-12)
70
- - [Added](#added-22)
71
- - [1.3.0 (2020-04-12)](#130-2020-04-12)
72
- - [Added](#added-23)
73
- - [1.2.0 (2020-04-12)](#120-2020-04-12)
74
- - [Added](#added-24)
75
- - [1.1.0 (2020-04-09)](#110-2020-04-09)
76
- - [Added](#added-25)
77
- - [Fixed](#fixed-4)
78
- - [1.0.0 (2020-03-16)](#100-2020-03-16)
79
- - [Added](#added-26)
80
- - [0.6.0 (2020-01-06)](#060-2020-01-06)
81
- - [Added](#added-27)
82
- - [0.5.0 (2020-01-04)](#050-2020-01-04)
83
- - [Added](#added-28)
84
- - [0.4.0 (2020-01-03)](#040-2020-01-03)
85
- - [Added](#added-29)
86
- - [0.3.0 (2020-01-03)](#030-2020-01-03)
87
- - [Added](#added-30)
88
- - [Breaking Changes](#breaking-changes-4)
89
- - [0.2.0 (2020-01-02)](#020-2020-01-02)
90
- - [Added](#added-31)
91
- - [0.1.0 (2019-12-26)](#010-2019-12-26)
92
- - [Added](#added-32)
93
-
94
- ## Unreleased
95
-
96
- <!--
97
- ### Added
98
- ### Breaking Changes
99
- ### Deprecated
100
- ### Removed
101
- ### Fixed
102
- -->
103
-
104
- 5.10.0 (2021-09-23)
105
- ------------------
106
-
107
- ### Added
108
-
109
- * [#69](https://github.com/serradura/kind/pull/69) - Make `Kind::Any` works with a `Set`.
110
- ```ruby
111
- require 'kind/any'
1
+ # Changelog
112
2
 
113
- Kind::Any.new(Set[:low, :high]).inspect # Kind::Any{:low, :high}
3
+ All notable changes to this project will be documented in this file.
114
4
 
115
- Kind::Any.new(Array['open', 'close']).inspect # Kind::Any["open", "close"]
116
- ```
117
-
118
- [⬆️ &nbsp;Back to Top](#changelog-)
119
-
120
- 5.9.0 (2021-09-22)
121
- ------------------
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
122
7
 
8
+ ## [6.0.1] - 2026-05-24
123
9
  ### Added
10
+ - This `CHANGELOG.md`, rewritten to follow the [Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/) spec and backfilled to cover every tagged release from `0.1.0` through `6.0.1` (including the previously undocumented `3.0.1` patch and the `6.0.0` major).
11
+ - `bug_tracker_uri` entry in `spec.metadata` so RubyGems.org surfaces a direct link to the issue tracker from the gem page.
124
12
 
125
- * [#68](https://github.com/serradura/kind/pull/68) - Add `Kind.object(name:, &block)` to create `Kind::Objects`.
126
- ```ruby
127
- PositiveInteger = Kind.object(name: 'PositiveInteger') do |value|
128
- value.kind_of?(Integer) && value > 0
129
- end
130
-
131
- # PositiveInteger.name
132
- # PositiveInteger.kind
133
- # The type handler can return its kind and its name
134
- PositiveInteger.name # "PositiveInteger"
135
- PositiveInteger.kind # #<Proc:0x0000.... >
136
-
137
- # PositiveInteger.===
138
- # Can check if a given value is an instance of its kind.
139
- PositiveInteger === 1 # true
140
- PositiveInteger === 0 # false
141
-
142
- # PositiveInteger.value?(value)
143
- # Can check if a given value is an instance of its kind.
144
- PositiveInteger.value?(1) # true
145
- PositiveInteger.value?(-1) # false
146
-
147
- # If it doesn't receive an argument, a lambda will be returned and it will know how to do the type verification.
148
- [1, 2, 0, 3, -1].select(&PositiveInteger.value?) # [1, 2, 3]
149
-
150
- # PositiveInteger.or_nil(value)
151
- # Can return nil if the given value isn't an instance of its kind
152
- PositiveInteger.or_nil(1) # 1
153
- PositiveInteger.or_nil(0) # nil
154
-
155
- # PositiveInteger.or_undefined(value)
156
- # Can return Kind::Undefined if the given value isn't an instance of its kind
157
- PositiveInteger.or_undefined(2) # 2
158
- PositiveInteger.or_undefined(-1) # Kind::Undefined
13
+ ## [6.0.0] - 2026-05-23
14
+ ### Changed
15
+ - **BREAKING:** Bumped minimum Ruby to **2.7.0** (Ruby 2.1 2.6 are EOL and no longer supported).
16
+ - Modernized the CI/test runner via Appraisal (mirroring the `u-case` 5.0 layout): the per-Ruby `ENV`-switched `Gemfile` and `bin/test` / `bin/prepare_coverage` scripts were replaced with an `Appraisals` file gated on `RUBY_VERSION`, the GitHub Actions matrix now covers Ruby 2.7 – 4.0+head with conditional ActiveModel steps, and per-module (`KIND_BASIC`) and `KIND_STRICT` runs are preserved as matrix axes.
17
+ - Switched code coverage reporting from CodeClimate to **Qlty** (token-based upload, badges updated in README).
18
+ - README polish: new header/badge layout, refreshed Ruby × ActiveModel compatibility table, added Ruby × Rails CI support matrix, and installation example pinned to `~> 6.0`. Pre-5.x rows dropped from the Documentation and Compatibility tables (long EOL).
19
+ - Ruby 3.4+/4.0 compatibility: rebuild `Kind::Any`'s brace-list `inspect` from values directly so the name stays `Kind::Any{:low, :high}` across the Ruby 4.0 `Set#inspect` format change; tests updated for the 3.4 quote/hash-literal display changes.
159
20
 
160
- # PositiveInteger.or(fallback, value)
161
- # Can return a fallback if the given value isn't an instance of its kind
162
- PositiveInteger.or(nil, 1) # 1
163
- PositiveInteger.or(nil, 0) # nil
164
-
165
- # If it doesn't receive a second argument (the value), it will return a callable that knows how to expose an instance of the expected type or a fallback if the given value was wrong.
166
- [1, 2, 0, 3, -1].map(&PositiveInteger.or(1)) # [1, 2, 1, 3, 1]
167
- [1, 2, 0, 3, -1].map(&PositiveInteger.or(nil)) # [1, 2, nil, 3, nil]
168
-
169
- # An error will be raised if the fallback didn't have the expected kind or if not nil / Kind::Undefined.
170
- [1, 2, 0, 3, -1].map(&PositiveInteger.or(:foo)) # Kind::Error (:foo expected to be a kind of PositiveInteger)
171
-
172
- # PositiveInteger[value]
173
- # Will raise Kind::Error if the given value isn't an instance of the expected kind
174
- PositiveInteger[1] # 1
175
- PositiveInteger[:foo] # Kind::Error (:foo expected to be a kind of PositiveInteger)
176
-
177
- # PositiveInteger.value(arg, default:)
178
- # This method ensures that you will have a value of the expected kind. But, in the case of the given value be invalid, this method will require a default value (with the expected kind) to be returned.
179
- PositiveInteger.value(2, default: 1) # 2
21
+ ### Added
22
+ - [#71](https://github.com/serradura/kind/pull/71) - Add `Kind::Maybe#to_proc` (thanks @tomascco), so `Kind::Maybe` can be passed where a block-arg is expected.
23
+ ```ruby
24
+ result = operation_that_can_return_nil().then(&Kind::Maybe)
25
+ # => #<Kind::Some value=:result>
26
+ ```
27
+ - Appraisal-generated gemfiles for **Rails 8.1** and **Rails edge**.
28
+ - `bin/matrix` script and `rake matrix` task to run the full local test matrix.
29
+ - `bin/setup` script.
180
30
 
181
- PositiveInteger.value('1', default: 1) # 1
31
+ ### Removed
32
+ - `bin/test` and `bin/prepare_coverage` (replaced by the Appraisal-driven setup).
182
33
 
183
- PositiveInteger.value('1', default: 0) # Kind::Error (0 expected to be a kind of PositiveInteger)
34
+ ### Security
35
+ - Hardened the GitHub Actions workflow: least-privilege `contents: read` permissions on the test job and `persist-credentials: false` on `actions/checkout`.
184
36
 
185
- # PositiveInteger.maybe
186
- # This method returns a typed Kind::Maybe.
187
- PositiveInteger.maybe(0).value_or(1) # 1
37
+ ## [5.10.0] - 2021-09-23
38
+ ### Added
39
+ - [#69](https://github.com/serradura/kind/pull/69) - Make `Kind::Any` work with a `Set`.
40
+ ```ruby
41
+ require 'kind/any'
188
42
 
189
- PositiveInteger.maybe(2).value_or(1) # 2
190
- ```
43
+ Kind::Any.new(Set[:low, :high]).inspect # Kind::Any{:low, :high}
44
+ Kind::Any.new(Array['open', 'close']).inspect # Kind::Any["open", "close"]
45
+ ```
191
46
 
192
- [⬆️ &nbsp;Back to Top](#changelog-)
47
+ ## [5.9.0] - 2021-09-22
48
+ ### Added
49
+ - [#68](https://github.com/serradura/kind/pull/68) - Add `Kind.object(name:, &block)` to create `Kind::Objects` (custom type handlers) with the full handler API: `.name`, `.kind`, `.===`, `.value?`, `.or_nil`, `.or_undefined`, `.or(fallback)`, `.[]`, `.value(arg, default:)`, and `.maybe`.
50
+ ```ruby
51
+ PositiveInteger = Kind.object(name: 'PositiveInteger') do |value|
52
+ value.kind_of?(Integer) && value > 0
53
+ end
193
54
 
194
- 5.8.1 (2021-09-22)
195
- ------------------
55
+ PositiveInteger === 1 # true
56
+ PositiveInteger.or_nil(0) # nil
57
+ PositiveInteger[:foo] # Kind::Error (:foo expected to be a kind of PositiveInteger)
58
+ PositiveInteger.value(2, default: 1) # 2
59
+ PositiveInteger.maybe(0).value_or(1) # 1
60
+ ```
196
61
 
62
+ ## [5.8.1] - 2021-09-22
197
63
  ### Fixed
64
+ - [#67](https://github.com/serradura/kind/pull/67) - Make `Kind.assert_hash!(some_hash, schema:)` work with a `Kind::Any` instance.
65
+ ```ruby
66
+ require 'kind/any'
198
67
 
199
- * [#67](https://github.com/serradura/kind/pull/67) - Make `Kind.assert_hash!(some_hash, schema:)` works with a `Kind::Any` instance.
200
- ```ruby
201
- require 'kind/any'
202
-
203
- Level = Kind::Any[:low, :high]
204
-
205
- Kind.assert_hash!({level: :medium}, schema: {level: Level})
206
- # Kind::Error (The key :status has an invalid value. Expected: Kind::Any[:low, :high])
207
- ```
208
-
209
- [⬆️ &nbsp;Back to Top](#changelog-)
68
+ Level = Kind::Any[:low, :high]
210
69
 
211
- 5.8.0 (2021-09-22)
212
- ------------------
70
+ Kind.assert_hash!({level: :medium}, schema: {level: Level})
71
+ # Kind::Error (The key :status has an invalid value. Expected: Kind::Any[:low, :high])
72
+ ```
213
73
 
74
+ ## [5.8.0] - 2021-09-22
214
75
  ### Added
215
-
216
- * [#66](https://github.com/serradura/kind/pull/66) - Add `Kind::Any` to make easier the verification of a value in a list (array) of expected values.
76
+ - [#66](https://github.com/serradura/kind/pull/66) - Add `Kind::Any` to verify a value belongs to a list of expected values.
217
77
  ```ruby
218
78
  require 'kind/any'
219
79
 
220
80
  Level = Kind::Any[:low, :high] # or Kind::Any.new([:low, :high])
221
81
 
222
- Level === :low # true
223
- Level === :high # true
224
-
225
- Level === :foo # false
226
-
227
- Level[:low] # :low
228
- Level[:high] # :high
229
-
230
- Level[:foo] # Kind::Error (:foo expected to be a kind of Kind::Any[:low, :high])
231
-
232
- level_or_any_symbol = # (Kind::Any[:low, :high] | Symbol)
233
-
234
- Level.name # 'Kind::Any[:low, :high]'
235
- Level.inspect # 'Kind::Any[:low, :high]'
236
-
237
- Level.values # [:low, :high]
82
+ Level === :low # true
83
+ Level === :foo # false
84
+ Level[:low] # :low
85
+ Level[:foo] # Kind::Error (:foo expected to be a kind of Kind::Any[:low, :high])
86
+ Level.values # [:low, :high]
238
87
  ```
239
-
240
- * [#66](https://github.com/serradura/kind/pull/66) - Add `Kind::Enum.from_array(arg, use_index_as_value:)` to allow the creation of enums where its values will be the array values.
88
+ - [#66](https://github.com/serradura/kind/pull/66) - Add `Kind::Enum.from_array(arg, use_index_as_value:)` to allow the creation of enums where the values come from the array (either the values themselves or their indices).
241
89
  ```ruby
242
- require 'kind/enum'
243
-
244
90
  module Level
245
91
  include Kind::Enum.from_array([:low, :medium, :high], use_index_as_value: false)
246
92
  end
247
-
248
- Level.keys # ["low", "medium", "high"]
249
93
  Level.values # [:low, :medium, :high]
250
94
 
251
- # ---
252
-
253
95
  module Status
254
96
  include Kind::Enum.from_array([:open, :closed], use_index_as_value: true)
255
97
  end
256
-
257
- Status.keys # ["open", "closed"]
258
98
  Status.values # [0, 1]
259
99
  ```
100
+ - [#66](https://github.com/serradura/kind/pull/66) - Make `Kind.assert_hash!(hash, schema:)` work with `Kind::Object` instances.
101
+ - [#66](https://github.com/serradura/kind/pull/66) - Improve the exception messages of `Kind.assert_hash!(hash, schema:)`.
102
+ - [#66](https://github.com/serradura/kind/pull/66) - Make `Kind.assert_hash!(hash, **options)` raise `ArgumentError` if the given hash is empty.
260
103
 
261
- * [#66](https://github.com/serradura/kind/pull/66) - Make `Kind.assert_hash!(hash, schema:)` works with a `Kind::Object`.
262
- ```ruby
263
- FilledString = begin
264
- filled_string = ->(value) {value.is_a?(String) && value.present?}
265
-
266
- Kind[filled_string, name: 'FilledString']
267
- end
268
-
269
- Kind.assert_hash!(some_hash, schema: {
270
- string: FilledString,
271
- callable: Kind::Callable,
272
- })
273
- ```
274
-
275
- * [#66](https://github.com/serradura/kind/pull/66) - Improve the exception messages of `Kind.assert_hash!(hash, schema:)`.
276
- ```ruby
277
- Kind.assert_hash!({status: 1}, schema: {status: Kind::String | Symbol})
278
- # Kind::Error (The key :status has an invalid value. Expected: (String | Symbol))
279
-
280
- Kind.assert_hash!({status: 'closed'}, schema: {status: 'active'})
281
- # Kind::Error (The key :status has an invalid value. Expected: active, Given: closed)
282
-
283
- Kind.assert_hash!({callable: 1}, schema: {callable: Kind::Callable})
284
- # Kind::Error (The key :callable has an invalid value. Expected: Callable)
285
- ```
286
-
287
- * [#66](https://github.com/serradura/kind/pull/66) - Make `Kind.assert_hash!(hash, **options)` raises an error if the given hash be empty.
288
- ```ruby
289
- Kind.assert_hash!({}, keys: []) # ArgumentError (hash can't be empty)
290
- Kind.assert_hash!({}, schema: {}) # ArgumentError (hash can't be empty)
291
- ```
292
-
293
- [⬆️ &nbsp;Back to Top](#changelog-)
294
-
295
- 5.7.0 (2021-06-22)
296
- ------------------
297
-
104
+ ## [5.7.0] - 2021-06-22
298
105
  ### Added
299
-
300
- * [#58](https://github.com/serradura/kind/pull/58) - Add `Add Kind.assert_hash!(hash, keys:)`, you can use the `require_all:` option to check if the hashes have the same keys.
106
+ - [#58](https://github.com/serradura/kind/pull/58) - Add `Kind.assert_hash!(hash, keys:)` with an optional `require_all:` to check the hash exposes exactly the expected keys.
301
107
  ```ruby
302
- h1 = {a: 1, b: 1}
303
-
304
- Kind.assert_hash!(h1, keys: [:a, :b])
305
- Kind.assert_hash!(h1, keys: [:a]) # ArgumentError (Unknown key: :b. Valid keys are: :a)
306
-
307
- # --
308
-
309
- h2 = {'a' => 1, 'b' => 2}
310
-
311
- Kind.assert_hash!(h2, keys: ['a', 'b'])
108
+ Kind.assert_hash!({a: 1, b: 1}, keys: [:a, :b])
109
+ Kind.assert_hash!({a: 1, b: 1}, keys: [:a]) # ArgumentError (Unknown key: :b. Valid keys are: :a)
312
110
  ```
313
-
314
- * [#58](https://github.com/serradura/kind/pull/58) - Add `Add Kind.assert_hash!(hash, schema:)`, you can use the `require_all:` option to check if the hashes have the same keys.
111
+ - [#58](https://github.com/serradura/kind/pull/58) - Add `Kind.assert_hash!(hash, schema:)` to validate hash shapes via literal values, classes, regexes or lambdas.
315
112
  ```ruby
316
- hash = {hash: {}, array: [], number: 1, string: 'foo', email: 'bar@bar.com', null: nil}
317
-
318
- Kind.assert_hash!(hash, schema: {
319
- hash: {},
320
- array: [],
321
- email: 'bar@bar.com',
322
- string: 'foo',
323
- number: 1,
324
- null: nil
325
- })
326
-
327
- Kind.assert_hash!(hash, schema: {
328
- hash: Enumerable,
329
- array: Enumerable,
330
- email: /\A.+@.+\..+\z/,
331
- string: String
332
- })
333
-
334
113
  Kind.assert_hash!(hash, schema: {
335
- hash: Hash,
336
- array: Array,
337
- email: String,
114
+ hash: Enumerable,
115
+ array: Enumerable,
116
+ email: /\A.+@.+\..+\z/,
338
117
  string: String
339
118
  })
340
-
341
- Kind.assert_hash!(h1, schema: {
342
- email: ->(value) { value.is_a?(String) && value.include?('@') }
343
- })
344
119
  ```
345
120
 
346
- [⬆️ &nbsp;Back to Top](#changelog-)
347
-
348
- 5.6.0 (2021-05-14)
349
- ------------------
350
-
121
+ ## [5.6.0] - 2021-05-14
351
122
  ### Added
352
-
353
- * [#57](https://github.com/serradura/kind/pull/57) - Allow the usage of `nil` to define union types.
123
+ - [#57](https://github.com/serradura/kind/pull/57) - Allow `nil` in union-type definitions.
354
124
  ```ruby
355
125
  (Kind::String | nil) === '' # true
356
126
  (Kind::String | nil) === nil # true
357
-
358
127
  (Kind::String | nil) === {} # false
359
128
  ```
360
129
 
361
- [⬆️ &nbsp;Back to Top](#changelog-)
362
-
363
- 5.5.0 (2021-04-05)
364
- ------------------
365
-
130
+ ## [5.5.0] - 2021-04-05
366
131
  ### Added
367
-
368
- * [#56](https://github.com/serradura/kind/pull/56) - Add `Kind.or_nil()`.
132
+ - [#56](https://github.com/serradura/kind/pull/56) - Add `Kind.or_nil()`.
369
133
  ```ruby
370
- Kind.or_nil(String, 1) # nil
371
-
134
+ Kind.or_nil(String, 1) # nil
372
135
  Kind.or_nil(String, '') # ""
373
136
 
374
- # --
375
-
376
137
  filled_string = ->(value) { value.is_a?(String) && !value.empty? }
377
-
378
- Kind.or_nil(filled_string, 1) # nil
379
- Kind.or_nil(filled_string, '') # nil
380
-
138
+ Kind.or_nil(filled_string, '') # nil
381
139
  Kind.or_nil(filled_string, '1') # "1"
382
140
  ```
383
141
 
384
- [⬆️ &nbsp;Back to Top](#changelog-)
385
-
386
- 5.4.1 (2021-03-26)
387
- ------------------
388
-
142
+ ## [5.4.1] - 2021-03-26
389
143
  ### Fixed
144
+ - [#55](https://github.com/serradura/kind/pull/55) - Fix `Kind::Either::Left#value_or` and `Kind::Result::Failure#value_or` so a block call receives the underlying value of the monad.
390
145
 
391
- * [#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.
392
-
393
- [⬆️ &nbsp;Back to Top](#changelog-)
394
-
395
- 5.4.0 (2021-03-25)
396
- ------------------
397
-
146
+ ## [5.4.0] - 2021-03-25
398
147
  ### Added
399
-
400
- * [#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.
148
+ - [#54](https://github.com/serradura/kind/pull/54) - Add `Kind::Functional::Steps`, allowing the use of `Step`, `Map`, `Try`, `Tee`, `Check`, `Success` and `Failure` in any object (classes and modules) to chain operations through `>>`.
401
149
  ```ruby
402
- # Usage in classes' instances
403
-
404
- class BaseJob
405
- def self.perform_now(input); new.perform(input); end
406
-
407
- def perform(input); raise NotImplementedError; end
408
- end
409
-
410
150
  class CreateUserJob < BaseJob
411
151
  include Kind::Functional::Steps
412
152
 
@@ -417,1653 +157,323 @@ Kind.assert_hash!({level: :medium}, schema: {level: Level})
417
157
  end
418
158
 
419
159
  private
420
-
421
- def validate(input)
422
- # Success() or Failure()
423
- end
424
-
425
- def create(input)
426
- # Success() or Failure()
427
- end
428
-
429
- def welcome_email(email)
430
- # Success() or Failure()
431
- end
432
- end
433
-
434
- # Usage in modules (singleton methods)
435
-
436
- module CreateUser
437
- extend self, Kind::Functional::Steps
438
-
439
- def perform(input)
440
- Step!(:validate, input) \
441
- >> Step(:create) \
442
- >> Step(:welcome_email)
443
- end
444
-
445
- private
446
-
447
- def validate(input)
448
- # Success() or Failure()
449
- end
450
-
451
- def create(input)
452
- # Success() or Failure()
453
- end
454
-
455
- def welcome_email(email)
456
- # Success() or Failure()
457
- end
160
+ def validate(input); end # Success() or Failure()
161
+ def create(input); end # Success() or Failure()
162
+ def welcome_email(email); end # Success() or Failure()
458
163
  end
459
164
  ```
460
165
 
461
- [⬆️ &nbsp;Back to Top](#changelog-)
462
-
463
- 5.3.0 (2021-03-23)
464
- ------------------
465
-
166
+ ## [5.3.0] - 2021-03-23
466
167
  ### Added
467
-
468
- * [#53](https://github.com/serradura/kind/pull/53) - Allow `Kind::Result#map` and `Kind::Result#map!` receive a callable as an argument.
469
-
470
- * [#53](https://github.com/serradura/kind/pull/53) - Add `|` and `>>` as an alias of `Kind::Result#map!`.
471
-
472
- * [#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`.
168
+ - [#53](https://github.com/serradura/kind/pull/53) - Allow `Kind::Result#map` and `Kind::Result#map!` to receive a callable.
169
+ - [#53](https://github.com/serradura/kind/pull/53) - Add `|` and `>>` as aliases for `Kind::Result#map!`.
170
+ - [#53](https://github.com/serradura/kind/pull/53) - Add step adapters (`Step`, `Map`, `Try`, `Tee`, `Check`) for `Kind::Action` and `Kind::Functional::Action`.
473
171
  ```ruby
474
172
  module CreateUser
475
173
  extend Kind::Functional::Action
476
174
 
477
175
  def call!(input)
478
- Step!(:validate, input) \
479
- | Step(:create)
176
+ Step!(:validate, input) | Step(:create)
480
177
  end
481
178
 
482
179
  private
483
-
484
- def validate(input)
485
- # returns Success(valid_data) or Failure(validation)
486
- end
487
-
488
- def create(input)
489
- # returns Success(user)
490
- end
180
+ def validate(input); end # returns Success(valid_data) or Failure(validation)
181
+ def create(input); end # returns Success(user)
491
182
  end
492
183
  ```
184
+ - [#53](https://github.com/serradura/kind/pull/53) - Add `kind/strict/disabled` to turn off all strict validations (`Kind.of`, `Kind.of_class`, `Kind.of_module`, `Kind.of_module_or_class`, `Kind::<Type>[1]`, `Kind::NotNil[1]`) to optimize the runtime in production while keeping strict validation in development.
185
+
186
+ ## [5.2.0] - 2021-03-17
187
+ ### Added
188
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind.respond_to?(method_name)` — behaves like the native `respond_to?` — and `Kind.respond_to?(object, *method_names)` to check an object implements a given set of methods.
189
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::UnionType` for composing type checks via `|`, with `===`, `[]` and `#name`/`#inspect` returning e.g. `"(Array | Hash)"`.
190
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Nil`, useful when composing union types: `Kind::UnionType[Hash] | Kind::Nil`.
191
+ - [#46](https://github.com/serradura/kind/pull/46), [#47](https://github.com/serradura/kind/pull/47) - Add `Kind::NotNil[value, label:]` for strict not-nil verification.
192
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::RespondTo[*method_names]` for building duck-type checkers and composing them via `|`.
193
+ - [#46](https://github.com/serradura/kind/pull/46) - Unfreeze the output of `Kind::Boolean.kind`.
194
+ - [#46](https://github.com/serradura/kind/pull/46) - Freeze `Kind::UNDEFINED` and define its `inspect` method.
195
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::TypeChecker#|` to compose union types (e.g. `Kind::String | Kind::Symbol`).
196
+ - [#46](https://github.com/serradura/kind/pull/46) - Allow `Kind.of()` and `Kind::TypeChecker#[]` to receive a `label:` for clearer error messages.
197
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `kind/basic`, a minimal entry point exposing just the type-handling essentials: `Kind.is?`, `Kind.of`, `Kind.of?`, `Kind.of_class?`, `Kind.of_module?`, `Kind.of_module_or_class`, `Kind.respond_to`, `Kind.respond_to?`, `Kind.value`, `Kind::Error`, `Kind::Undefined`.
198
+ - [#46](https://github.com/serradura/kind/pull/46) - Improve `Kind::Maybe`: better `#inspect`; `Kind::Maybe.{new,[],wrap}` returns `None` when given an exception; add `#accept` (alias of `#check`) and `#reject` (its reverse); let `#map`, `#map!`, `#then`, `#then!`, `#check`, `#accept`, `#reject` accept a symbol (treated as a method to invoke on the wrapped value); add `Kind::Maybe#on` for block-based `some`/`none` handling.
199
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Either` (either monad). Not loaded by default — `require 'kind/either'`. Provides `Kind::Left()`, `Kind::Right()`, `#right?`/`#left?`, `#map`/`#then` for chaining (auto-handle `StandardError` returning `Left`), and `#map!`/`#then!` variants that let exceptions leak.
200
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Result` (an `Either` variation).
201
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Function`.
202
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Functional`.
203
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Try.presence` and improve the input/output handling of `Kind::Try.call`.
204
+ - [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Dig.presence` and improve the input/output handling of `Kind::Dig.call`.
205
+ - [#47](https://github.com/serradura/kind/pull/47) - Add `Kind.is!`.
206
+ - [#47](https://github.com/serradura/kind/pull/47) - Add aliases `Kind.of!` (for `Kind.of`) and `Kind.respond_to!` (for `Kind.respond_to`).
207
+ - [#47](https://github.com/serradura/kind/pull/47) - Add `Kind[]` as the replacement for `Kind::Of()`.
208
+ - [#49](https://github.com/serradura/kind/pull/49) - Add `Kind::Either::Methods` and `Kind::Result::Methods`.
209
+ - [#49](https://github.com/serradura/kind/pull/49) - Add `Kind::Undefined.empty?`.
210
+ - [#50](https://github.com/serradura/kind/pull/50) - Add `Kind::<Type>.empty_or` as an alias of `Kind::<Type>.value_or_empty`.
211
+ - [#46](https://github.com/serradura/kind/pull/46), [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Functional::Action`.
212
+ - [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Action`, `Kind::Maybe::ImmutableAttributes`, `Kind::Maybe::Methods`, and `Kind::Enum`.
213
+ - [#51](https://github.com/serradura/kind/pull/51) - Modularize all the `kind` components: `kind/action`, `kind/dig`, `kind/either`, `kind/empty`, `kind/enum`, `kind/function`, `kind/functional`, `kind/functional/action`, `kind/immutable_attributes`, `kind/maybe`, `kind/objects`, `kind/presence`, `kind/result`, `kind/try`, `kind/validator`. `kind/action` is the minimal requirement for all of them.
214
+ - [#52](https://github.com/serradura/kind/pull/52) - Improve `Kind::Validator` to accept lambdas or any object responding to `.===` and `.name` for kind validation.
215
+ - [#52](https://github.com/serradura/kind/pull/52) - Add `Kind::Enum.===`.
216
+
217
+ ### Changed
218
+ - [#48](https://github.com/serradura/kind/pull/48) - Rename `Kind::TypeChecker` to `Kind::Object`, and `Kind::TypeChecker::Object` to `Kind::Object::Instance`.
493
219
 
494
- * [#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:
495
- * `Kind.of()`
496
- * `Kind.of_class()`
497
- * `Kind.of_module()`
498
- * `Kind.of_module_or_class()`
499
- * `Kind::<Type>[1]`
500
- * `Kind::NotNil[1]`
501
-
502
- [⬆️ &nbsp;Back to Top](#changelog-)
503
-
504
- 5.2.0 (2021-03-17)
505
- ------------------
220
+ ### Deprecated
221
+ - [#47](https://github.com/serradura/kind/pull/47) - Deprecate `Kind.is` and `Kind::Of()`.
222
+ - [#48](https://github.com/serradura/kind/pull/48) - Deprecate `Kind::Maybe()` and `Kind::Optional()`.
506
223
 
224
+ ## [5.1.0] - 2021-02-23
507
225
  ### Added
226
+ - [#45](https://github.com/serradura/kind/pull/45) - Add support for Ruby `>= 2.1.0`.
508
227
 
509
- * [#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
510
- `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.
511
- ```ruby
512
- Kind.respond_to?(:is?) # true
513
-
514
- Kind.respond_to?(:foo?) # true
515
-
516
- # --
517
-
518
- Kind.respond_to?({}, :fetch, :merge) # true
519
-
520
- Kind.respond_to?([], :fetch, :merge) # false
521
- ```
522
-
523
- * [#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.
524
- ```ruby
525
- # The method [] can build a union type object that will have the method #|
526
- # which allows the composition with other object kinds.
527
- array_or_hash = Kind::UnionType[Array] | Hash
528
-
529
- # The method === can verify if a given value is one of the kinds that compounds the union type.
530
- array_or_hash === {} # true
531
- array_or_hash === [] # true
532
- array_or_hash === 1 # false
533
- array_or_hash === nil # false
534
-
535
- # The method #[] will return the given value if it has one of the expected kinds,
536
- # but if not, it will raise a Kind::Error.
537
- array_or_hash[{}] # {}
228
+ ### Deprecated
229
+ - [#45](https://github.com/serradura/kind/pull/45) - `kind/active_model/validation` is deprecated; use `kind/validator` instead.
538
230
 
539
- array_or_hash[1] # Kind::Error (1 expected to be a kind of (Array | Hash))
231
+ ## [5.0.0] - 2021-02-22
232
+ ### Changed
233
+ - [#44](https://github.com/serradura/kind/pull/44) - **BREAKING:** The top-level `Empty` constant is no longer defined automatically. Require `kind/empty/constant` to opt in to defining `Empty` as a `Kind::Empty` alias.
540
234
 
541
- # At last, the method #name is an alias to the method #inspect.
542
- array_or_hash.name # "(Array | Hash)"
543
- array_or_hash.inspect # "(Array | Hash)"
544
- ```
235
+ ### Removed
236
+ - [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Is.call`.
237
+ - [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Of.call`.
238
+ - [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Types.add`.
239
+ - [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Of::<Type>` and `Kind::Is::<Type>` modules.
240
+ - [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Checker`, `Kind::Checker::Protocol`, `Kind::Checker::Factory`.
241
+ - [#44](https://github.com/serradura/kind/pull/44) - Remove the invocation of `Kind.is` without arguments.
242
+ - [#44](https://github.com/serradura/kind/pull/44) - Remove the invocation of `Kind.of` without arguments.
243
+ - [#44](https://github.com/serradura/kind/pull/44) - Remove the invocation of `Kind.of` with a single argument (the kind).
545
244
 
546
- * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Nil`. This module was added to be used to create union types. e.g.
245
+ ## [4.1.0] - 2021-02-22
246
+ ### Added
247
+ - [#43](https://github.com/serradura/kind/pull/43) - Make `Kind::Maybe::Typed` verify the kind of the value via `===`, enabling type checkers as the typed-`Maybe` kind.
547
248
  ```ruby
548
- hash_or_nil = Kind::UnionType[Hash] | Kind::Nil
549
-
550
- hash_or_nil === {} # true
551
- hash_or_nil === [] # false
552
- hash_or_nil === 1 # false
553
- hash_or_nil === nil # true
249
+ Kind::Maybe(Kind::Boolean).wrap(nil).value_or(false) # false
250
+ Kind::Maybe(Kind::Boolean).wrap(true).value_or(false) # true
554
251
  ```
252
+ - [#43](https://github.com/serradura/kind/pull/43) - Add `Kind::<Type>.maybe` and `Kind::<Type>.optional`. Without arguments, returns a typed `Maybe` with the expected kind; with arguments, behaves like `Kind::Maybe.wrap`.
253
+ - [#43](https://github.com/serradura/kind/pull/43) - Make the `:respond_to` kind validation accept one or many method names: `validates :params, kind: { respond_to: [:[], :values_at] }`.
254
+ - [#43](https://github.com/serradura/kind/pull/43) - Make the `:of` kind validation verify the expected value kind via `===`, allowing type checkers to be used as expected kinds: `validates :alive, kind: Kind::Boolean`.
555
255
 
556
- * [#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.
256
+ ## [4.0.0] - 2021-02-22
257
+ ### Added
258
+ - [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.of_class?`, `Kind.of_module?`, and `Kind.of_module_or_class(value)` (returns the given value if it is a module/class, otherwise raises `Kind::Error`).
259
+ - [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.respond_to(object, *method_names)`: returns the object if it responds to all of the given methods, raises otherwise.
260
+ - [#40](https://github.com/serradura/kind/pull/40) - Add `Kind::Try.call(receiver, method_name, *args)`: like `public_send`, but returns `nil` instead of raising when the receiver doesn't respond to the method.
261
+ - [#40](https://github.com/serradura/kind/pull/40), [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::DEPRECATION` to warn about deprecations. Set `DISABLE_KIND_DEPRECATION` to silence the warnings.
262
+ - [#40](https://github.com/serradura/kind/pull/40), [#41](https://github.com/serradura/kind/pull/41) - Add **type checker modules** (`Kind::String`, `Kind::Integer`, etc.) exposing `.name`, `.kind`, `===`, `.value?`, `.or_nil`, `.or_undefined`, `.or(fallback)`, and `[value]`. The full list covers Core (`Array`, `Class`, `Comparable`, `Enumerable`, `Enumerator`, `File`, `Float`, `Hash`, `Integer`, `IO`, `Method`, `Module`, `Numeric`, `Proc`, `Queue`, `Range`, `Regexp`, `String`, `Struct`, `Symbol`, `Time`), Custom (`Boolean`, `Callable`, `Lambda`) and Stdlib (`OpenStruct`, `Set`).
263
+ - [#40](https://github.com/serradura/kind/pull/40) - Add `Kind::Of(kind, name: ...)` to create type checkers in runtime from any object responding to `.===`.
557
264
  ```ruby
558
- Kind::NotNil[1] # 1
559
-
560
- Kind::NotNil[nil] # Kind::Error (expected to not be nil)
561
-
562
- Kind::NotNil[nil, label: 'Foo#bar'] # Kind::Error (Foo#bar: expected to not be nil)
265
+ PositiveInteger = Kind::Of(-> value { value.is_a?(Integer) && value > 0 }, name: 'PositiveInteger')
266
+ PositiveInteger[1] # 1
267
+ PositiveInteger[:foo] # Kind::Error (:foo expected to be a kind of PositiveInteger)
563
268
  ```
269
+ - [#40](https://github.com/serradura/kind/pull/40), [#41](https://github.com/serradura/kind/pull/41) - Add **type checker methods** (`Kind::String?`, `Kind::Integer?`, etc.) that accept one or many values and return a lambda when called without arguments.
270
+ - [#41](https://github.com/serradura/kind/pull/41) - Make `Kind::Dig.call` extract values from regular objects (not just `Hash`/`Array`/`Struct`/`OpenStruct`).
271
+ - [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::Presence.call`. Returns the given value if it is present, otherwise `nil`. Honors `#blank?` if defined on the object.
272
+ - [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::Maybe#presence` returning `None` if the wrapped value is not present.
273
+ - [#41](https://github.com/serradura/kind/pull/41) - Make `Kind::Maybe#wrap` accept a block and intercept `StandardError` (returns `None` with the exception as its value).
274
+ - [#41](https://github.com/serradura/kind/pull/41) - Make `Kind::Maybe#map`/`#then` intercept `StandardError` and return `None`. Add `#map!`/`#then!` for the leaking variants.
275
+ - [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::TypeCheckers#value(arg, default:)`, which ensures the returned value is of the expected kind (the default must also be of the kind).
276
+ - [#41](https://github.com/serradura/kind/pull/41) - Add `value_or_empty` for `Kind::Array`, `Kind::Hash`, `Kind::String`, `Kind::Set` (returns an empty frozen value when the input has the wrong kind).
277
+ - [#42](https://github.com/serradura/kind/pull/42) - Add `Kind.value(kind, arg, default:)`.
278
+ - [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Presence.to_proc` (e.g. `[...].map(&Kind::Presence)`).
279
+ - [#42](https://github.com/serradura/kind/pull/42) - Make `Kind::Maybe(<Type>).{new,[],wrap}` understand other `Maybe` monads as inputs (unwrapping their value).
280
+ - [#42](https://github.com/serradura/kind/pull/42) - Make `Kind::Maybe(<Type>).wrap(arg) { |arg_value| }` verify the argument kind when the block declares it.
281
+ - [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Maybe#check { ... }` returning the current `Some` if the block result is truthy, otherwise `None`.
282
+ - [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Dig[]` and `Kind::Try[]` for building lambdas that perform the dig/try strategies.
564
283
 
565
- * [#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.
566
- ```ruby
567
- HashLike = Kind::RespondTo[:fetch, :merge!]
568
- Fetchable = Kind::RespondTo[:fetch]
569
-
570
- # Verifying if an object implements the expected interface.
571
- HashLike === ENV # true
572
- HashLike === {} # true
573
- HashLike === [] # false
574
-
575
- Fetchable === ENV # true
576
- Fetchable === [] # true
577
- Fetchable === {} # true
578
-
579
- # Performing an strict verification
580
- HashLike[ENV] # true
581
- HashLike[{}] # true
582
- HashLike[Array.new] # false Kind::Error ([] expected to be a kind of Kind::RespondTo[:fetch, :merge!])
583
-
584
- # Creating union types using interfaces
585
- HashLikeOrArray = HashLike | Array # Kind::RespondTo[:fetch, :merge!] | Array
284
+ ### Deprecated
285
+ - [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Is.call`, `Kind::Of.call`, `Kind::Types.add`, the `Kind::Of::<Type>` / `Kind::Is::<Type>` modules, `Kind::Checker` (+ `Protocol` / `Factory`), and the bare-argument invocations of `Kind.is`/`Kind.of`.
586
286
 
587
- HashLikeOrArray === {} # true
588
- HashLikeOrArray === [] # true
589
- HashLikeOrArray === ENV # true
590
- ```
287
+ ### Fixed
288
+ - [#40](https://github.com/serradura/kind/pull/40) - Make `Kind::Maybe.try!()` raise when called without a block or arguments.
591
289
 
592
- * [#46](https://github.com/serradura/kind/pull/46) - Unfreeze the output of `Kind::Boolean.kind`.
290
+ ## [3.1.0] - 2020-07-08
291
+ ### Added
292
+ - [#33](https://github.com/serradura/kind/pull/33) - Add `Kind::Of::OpenStruct` / `Kind::Is::OpenStruct`.
293
+ - [#33](https://github.com/serradura/kind/pull/33) - Add `Kind::Maybe::Result#dig`. Extracts nested values; if any step returns `nil`, returns `None`, otherwise `Some(final_value)`.
294
+ - [#33](https://github.com/serradura/kind/pull/33) - Add `Kind::Dig.call` utility. Same behavior as Ruby's `dig` (`Hash`, `Array`, `Struct`, `OpenStruct`) but returns `nil` instead of raising when a step cannot be digged.
593
295
 
594
- * [#46](https://github.com/serradura/kind/pull/46) - Freeze `Kind::UNDEFINED` and define its inspect method.
296
+ ## [3.0.1] - 2020-06-25
297
+ ### Fixed
298
+ - [#32](https://github.com/serradura/kind/pull/32) - Fix the `Kind::Maybe::None#try` methods.
595
299
 
596
- * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::TypeChecker#|` to allow the creation of union types.
300
+ ## [3.0.0] - 2020-06-25
301
+ ### Changed
302
+ - [#31](https://github.com/serradura/kind/pull/31) - **BREAKING:** Change the behavior of `Kind::Maybe::Result#try()`. It now mirrors `public_send` semantics — returning `nil` when the receiver does not respond to the method — and wraps the result in `Some` when the value isn't `nil` / `Kind::Undefined`.
597
303
  ```ruby
598
- StatusLabel = Kind::String | Kind::Symbol
599
-
600
- StatusLabel === :ok # true
601
- StatusLabel === 'ok' # true
602
- StatusLabel === true # false
304
+ Kind::Maybe['foo'].try(:upcase).value # "FOO"
305
+ Kind::Maybe[{}].try(:fetch, :number, 0).value # 0
306
+ Kind::Optional[' Rodrigo '].try(:strip).value_or('') # "Rodrigo"
603
307
  ```
604
308
 
605
- * [#46](https://github.com/serradura/kind/pull/46) - Allow `Kind.of()` and `Kind::TypeChecker#[]` receive a label.
606
- ```ruby
607
- # Kind.of(<Type>, value, label:)
608
- class Person
609
- attr_reader :name
610
-
611
- def initialize(name:)
612
- @name = Kind.of(String, name, label: 'Person#name')
613
- end
614
- end
615
-
616
- Person.new(name: 'Rodrigo') # #<Person:0x0000... @name="Rodrigo">
617
- Person.new(name: :ok) # Kind::Error (Person#name: :ok expected to be a kind of String)
618
-
619
- # Kind<Type>[value, label:]
620
- class User
621
- attr_reader :name
622
-
623
- def initialize(name:)
624
- @name = Kind::String[name, label: 'User#name']
625
- end
626
- end
627
-
628
- User.new(name: 'Rodrigo') # #<User:0x0000... @name="Rodrigo">
629
- User.new(name: :ok) # Kind::Error (User#name: :ok expected to be a kind of String)
630
- ```
309
+ ### Added
310
+ - [#31](https://github.com/serradura/kind/pull/31) - Add `Kind::Maybe::Result#try!()` — like `#try`, but raises when the wrapped value does not respond to the method.
631
311
 
632
- * [#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:
633
- * `Kind.is?`
634
- * `Kind.of`
635
- * `Kind.of?`
636
- * `Kind.of_class?`
637
- * `Kind.of_module?`
638
- * `Kind.of_module_or_class`
639
- * `Kind.respond_to`
640
- * `Kind.respond_to?`
641
- * `Kind.value`
642
- * `Kind::Error`
643
- * `Kind::Undefined`
644
-
645
- * [#46](https://github.com/serradura/kind/pull/46) - Improve `Kind::Maybe`.
646
- * Improve the `#inspect` output.
647
- * Make `Kind::Maybe.{new,[],wrap}` return `None` if they receive an exception instance.
648
- * Add `#accept` as an alias of `#check` method.
649
- * Add `#reject` as the reverse of the methods `#check` and `#accept`.
650
- * 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.
651
- * 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.
652
- ```ruby
653
- # Kind::Maybe#accept (an alias of Kind::Maybe#check)
654
- Kind::Maybe[1].accept(&:odd?) # #<Kind::Some value=1>
655
- Kind::Maybe[1].accept(&:even?) # #<Kind::None value=nil>
312
+ ## [2.3.0] - 2020-06-24
313
+ ### Added
314
+ - [#30](https://github.com/serradura/kind/pull/30) - Add `Kind::Maybe.wrap()` as an alias for `Kind::Maybe.new()`.
315
+ - [#30](https://github.com/serradura/kind/pull/30) - Add `Kind::Maybe::Typed` and the helpers `Kind::Maybe()` / `Kind::Optional()` for typed monads. They return `Some` only if the value has the expected kind.
656
316
 
657
- # Kind::Maybe#reject (the reverse of Kind::Maybe#check)
658
- Kind::Maybe[1].reject(&:odd?) # #<Kind::None value=nil>
659
- Kind::Maybe[1].reject(&:even?) # #<Kind::Some value=1>
317
+ ## [2.2.0] - 2020-06-23
318
+ ### Changed
319
+ - [#29](https://github.com/serradura/kind/pull/29) - Invert the comparison with `Kind::Undefined` to avoid unexpected callbacks (e.g. `ActiveRecord::AssociationRelation#==` always performing a query).
660
320
 
661
- # Passing one symbol as an argument of the methods: `#map`, `#then`, `#check`, `#accept`, `#reject`
662
- Kind::Maybe['1'].map(:to_i) # #<Kind::Some value=1>
663
- Kind::Maybe[' '].then(:strip) # #<Kind::Some value="">
321
+ ## [2.1.0] - 2020-05-12
322
+ ### Added
323
+ - [#28](https://github.com/serradura/kind/pull/28) - Allow passing multiple arguments to `Kind.of.<Type>.instance?(*args)` and `Kind.of.<Type>?(*args)`.
324
+ - [#28](https://github.com/serradura/kind/pull/28) - Add `Kind::Some()` and `Kind::None()` helpers.
325
+ - [#28](https://github.com/serradura/kind/pull/28) - Add `Kind.of?(<Type>, *args)` to check if one or many values have the expected kind. With a single `<Type>` argument it returns a lambda usable as a block.
664
326
 
665
- Kind::Maybe['1'].map!(:to_i).accept(:odd?) # #<Kind::Some value=1>
666
- Kind::Maybe[' '].then!(:strip).reject(:empty?) # #<Kind::None value=nil>
327
+ ### Changed
328
+ - [#28](https://github.com/serradura/kind/pull/28) - **BREAKING:** `Kind.of.<Type>.to_proc` now behaves like `Kind.of.<Type>.instance(value)` (returns the value or raises `Kind::Error`). For the predicate behavior, use the new `Kind.of.<Type>?` instead.
667
329
 
668
- # `Kind::Maybe#on` making use of a block to handle Some or None results.
669
- number = Kind::Maybe['2'].then(:to_i).reject(:even?).on do |result|
670
- result.none { 0 }
671
- result.some { 1 }
672
- end
330
+ ## [2.0.0] - 2020-05-07
331
+ ### Added
332
+ - [#24](https://github.com/serradura/kind/pull/24) - Improve `kind: { is: }` validation to check class/module inheritance.
673
333
 
674
- p number # 0
675
- ```
334
+ ### Changed
335
+ - [#24](https://github.com/serradura/kind/pull/24) - **BREAKING:** `Kind.{of,is}.Callable` now only checks that the given object `respond_to?(:call)`.
676
336
 
677
- [⬆️ &nbsp;Back to Top](#changelog-)
337
+ ### Removed
338
+ - [#24](https://github.com/serradura/kind/pull/24) - Remove `kind: { is_a: }` from `Kind::Validator`.
339
+ - [#24](https://github.com/serradura/kind/pull/24) - Remove `kind: { klass: }` from `Kind::Validator`.
678
340
 
679
- * [#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.
341
+ ## [1.9.0] - 2020-05-06
342
+ ### Added
343
+ - [#23](https://github.com/serradura/kind/pull/23) - Add `Kind.of.<Type>.to_proc` as an alias for `Kind.of.<Type>.instance?`.
344
+ - [#23](https://github.com/serradura/kind/pull/23) - Add `Kind::Validator` (`ActiveModel` validator) as an alternative to [`type_validator`](https://github.com/serradura/type_validator).
680
345
  ```ruby
681
- require 'kind/either'
682
-
683
- # Use the methods Kind::Left() or Kind::Right() to create either monads
684
- Kind::Left(0) # #<Kind::Left value=0>
685
- Kind::Right(1) # #<Kind::Right value=1>
686
-
687
- # The Kind::Either.new() or Kind::Either[] also creates a Kind::Right monad
688
- Kind::Either.new(2) # #<Kind::Right value=2>
689
- Kind::Either[3] # #<Kind::Right value=3>
690
-
691
- # An Either has methods that allow you to know what kind it is.
692
- monad = Kind::Right(1)
693
- monad.right? # true
694
- monad.left? # false
695
-
696
- # This monad allows you to chain a sequence of operations that will continue while the output
697
- # of each step is a Right monad. So, if some step return a Left, all of the next steps will be avoided.
698
- # Let's see an example of how you can use the method #map to define a sequence of operations.
699
-
700
- def do_some_calculation(arg)
701
- Kind::Right(arg)
702
- .map { |value| Kind::Numeric?(value) ? Kind::Right(value + 2) : Kind::Left('value must be numeric') }
703
- .map { |value| value.odd? ? Kind::Right(value) : Kind::Left('value can\'t be even') }
704
- .map { |value| Kind::Right(value * 3) }
705
- end
706
-
707
- do_some_calculation('1') # #<Kind::Left value="value must be numeric">
708
- do_some_calculation(2) # #<Kind::Left value="value can't be even">
709
- do_some_calculation(1) # #<Kind::Right value=9>
710
-
711
- # You can use procs/lambdas as an alternative of blocks
712
- Add = ->(a, b) do
713
- return Kind::Right(a + b) if Kind::Numeric?(a, b)
714
-
715
- Kind::Left('the arguments must be numerics')
716
- end
717
-
718
- Double = ->(number) do
719
- return Kind::Right(number * 2) if Kind::Numeric?(number)
720
-
721
- Kind::Left('the argument must be numeric')
722
- end
723
-
724
- AsString = ->(value) { Kind::Right(value.to_s) }
725
-
726
- Add.(1, 2).map(&Double).map(&Double) # #<Kind::Right value=12>
727
- Add.(1, 2).map(&AsString).map(&Double) # #<Kind::Left value="the argument must be numeric">
728
-
729
- # The method #then is an alias for #map
730
- Add.(2, 2).then(&Double).then(&AsString) # #<Kind::Right value="8">
731
-
732
- # An exception will occur when your block or lambda doesn't return a Kind::Either
733
- Add.(2, 2).map { |number| number * 2 } # Kind::Monad::Error (8 expected to be a kind of Kind::Right | Kind::Left)
734
-
735
- # The methods #map, #then auto handle StandardError exceptions,
736
- # so Left will be returned when an exception occur.
737
- Add.(0, 0).map { |number| Kind::Right(10 / number) } # #<Kind::Left value=#<ZeroDivisionError: divided by 0>>
738
-
739
- # You can use #map! or #then! if you don't want this auto exception handling.
740
- Add.(0, 0).map! { |number| Kind::Right(10 / number) } # ZeroDivisionError (divided by 0)
741
-
742
- Add.(0, 0).then! { |number| Kind::Right(10 / number) } # ZeroDivisionError (divided by 0)
743
- ```
744
-
745
- * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Result` (an Either monad variation)
746
-
747
- * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Function`.
748
-
749
- * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Functional`.
750
-
751
- * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Try.presence` and improve the input/output handling of `Kind::Try.call`.
752
-
753
- * [#46](https://github.com/serradura/kind/pull/46) - Add `Kind::Dig.presence` and improve the input/output handling of `Kind::Dig.call`.
754
-
755
- * [#47](https://github.com/serradura/kind/pull/47) - Add `Kind.is!`
756
-
757
- * [#47](https://github.com/serradura/kind/pull/47) - Create aliases to the methods `Kind.of` (`Kind.of!`) and `Kind.respond_to` (`Kind.respond_to!`)
758
-
759
- * [#47](https://github.com/serradura/kind/pull/47) - Add `Kind[]` as the `Kind::Of()` substitute.
760
-
761
- * [#49](https://github.com/serradura/kind/pull/49) - Add `Kind::Either::Methods` and `Kind::Result::Methods`
762
-
763
- * [#49](https://github.com/serradura/kind/pull/49) - Add `Kind::Undefined.empty?`
764
-
765
- * [#50](https://github.com/serradura/kind/pull/50) - Add `Kind::<Type>.empty_or` as an alias of `Kind::<Type>.value_or_empty`
766
-
767
- * [#46](https://github.com/serradura/kind/pull/46), [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Functional::Action`.
768
-
769
- * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Action`.
770
-
771
- * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Maybe::ImmutableAttributes`.
772
-
773
- * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Maybe::Methods`.
774
-
775
- * [#51](https://github.com/serradura/kind/pull/51) - Add `Kind::Enum`.
776
-
777
- * [#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.
778
- * `kind/action`
779
- * `kind/dig`
780
- * `kind/either`
781
- * `kind/empty`
782
- * `kind/enum`
783
- * `kind/function`
784
- * `kind/functional`
785
- * `kind/functional/action`
786
- * `kind/immutable_attributes`
787
- * `kind/maybe`
788
- * `kind/objects`
789
- * `kind/presence`
790
- * `kind/result`
791
- * `kind/try`
792
- * `kind/validator`
346
+ require 'kind/active_model/validation'
793
347
 
794
- * [#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.
795
- ```ruby
796
- class User
348
+ class Person
797
349
  include ActiveModel::Validations
798
-
799
- attr_reader :name, :bool
800
-
801
- FilledString = ->(value) { value.kind_of?(String) && !value.empty? }
802
-
803
- Bool = Object.new
804
- def Bool.===(value)
805
- value == true || value == false
806
- end
807
- def Bool.name; 'Bool'; end
808
-
809
- validates :name, kind: FilledString
810
- validates :bool, kind: Bool
811
-
812
- def initialize(name:, bool:)
813
- @name, @bool = name, bool
814
- end
350
+ attr_reader :name, :age
351
+ validates :name, kind: { of: String }
352
+ validates :age, kind: { of: Integer }
353
+ def initialize(name:, age:); @name, @age = name, age; end
815
354
  end
816
-
817
- user = User.new(name: '', bool: 1)
818
-
819
- user.valid? # true
820
- user.errors[:name] # ['invalid kind']
821
- user.errors[:bool] # ['must be a kind of Bool']
822
-
823
- User.new(name: 'Serradura', bool: true).valid? # true
824
355
  ```
825
356
 
826
- * [#52](https://github.com/serradura/kind/pull/52) - Add `Kind::Enum.===`.
827
-
828
- ### Deprecated
829
-
830
- * [#47](https://github.com/serradura/kind/pull/47) - Deprecate `Kind.is` and `Kind::Of()`.
831
-
832
- * [#48](https://github.com/serradura/kind/pull/48) - Deprecate `Kind::Maybe()` and `Kind::Optional()`
833
-
834
- ### Changes
835
-
836
- * [#48](https://github.com/serradura/kind/pull/48) - Rename `Kind::TypeChecker` to `Kind::Object` and `Kind::TypeChecker::Object` to `Kind::Object::Instance`.
837
-
838
- [⬆️ &nbsp;Back to Top](#changelog-)
839
-
840
- 5.1.0 (2021-02-23)
841
- ------------------
842
-
357
+ ## [1.8.0] - 2020-05-03
843
358
  ### Added
359
+ - [#22](https://github.com/serradura/kind/pull/22) - `Kind.of.<Type>.instance?` returns a lambda when called without an argument (block-friendly).
360
+ - [#22](https://github.com/serradura/kind/pull/22) - Add `.as_optional` / `.as_maybe` on type checkers (returns a typed `Maybe`; lambda when called without arguments).
844
361
 
845
- * [#45](https://github.com/serradura/kind/pull/45) - Add support to Ruby `>= 2.1.0`.
846
-
847
- ### Deprecated
848
-
849
- * [#45](https://github.com/serradura/kind/pull/45) - `kind/active_model/validation` is deprecated; use `kind/validator` instead.
850
-
851
- 5.0.0 (2021-02-22)
852
- ------------------
853
-
854
- ### Breaking Changes
362
+ ## [1.7.0] - 2020-05-03
363
+ ### Fixed
364
+ - [#20](https://github.com/serradura/kind/pull/20) - Fix the verification of modules using `Kind.is()`.
855
365
 
856
- * [#44](https://github.com/serradura/kind/pull/44) - Now, do you need to require `"kind/empty/constant"` to define the constant `Empty` as a `Kind::Empty` alias.
366
+ ## [1.6.0] - 2020-04-17
367
+ ### Added
368
+ - [#19](https://github.com/serradura/kind/pull/19) - Add aliases to perform strict type verification on registered type checkers: `Kind.of.<Type>[value, or: ...]` and `Kind.of.<Type>.instance(value, or: ...)`.
369
+ - [#19](https://github.com/serradura/kind/pull/19) - Add `.or_undefined` for any type checker (returns `Kind::Undefined` instead of raising).
370
+ - [#19](https://github.com/serradura/kind/pull/19) - Allow dynamic verification of types with `Kind.of(<Type>, value)` and dynamic checker creation with `Kind.of(<Type>)` (no registration required), exposing the full type-checker API (`[]`, `instance`, `instance?`, `class?`, `or_nil`, `or_undefined`).
371
+ - [#19](https://github.com/serradura/kind/pull/19) - Add new type checkers: `Kind::Of::Set`, `Kind::Of::Maybe`, `Kind::Of::Optional`.
372
+ - [#19](https://github.com/serradura/kind/pull/19) - Add `Kind::Empty` with constants for frozen empty values: `Kind::Empty::SET`, `Kind::Empty::HASH`, `Kind::Empty::ARRAY`, `Kind::Empty::STRING`. When the top-level `Empty` constant is undefined, it is aliased to `Kind::Empty`.
857
373
 
858
- ### Removed
374
+ ### Changed
375
+ - [#19](https://github.com/serradura/kind/pull/19) - Change the output of `Kind::Undefined.to_s` / `Kind::Undefined.inspect` from `"Undefined"` to `"Kind::Undefined"`.
859
376
 
860
- * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Is.call`
377
+ ## [1.5.0] - 2020-04-12
378
+ ### Added
379
+ - [#18](https://github.com/serradura/kind/pull/18) - Refactor `Kind::Maybe`.
380
+ - [#18](https://github.com/serradura/kind/pull/18) - Add `Kind::Maybe::Value` module with `.some?` / `.none?` predicates for raw values.
861
381
 
862
- * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Of.call`
382
+ ## [1.4.0] - 2020-04-12
383
+ ### Changed
384
+ - [#17](https://github.com/serradura/kind/pull/17) - Rename `Kind::Optional` to `Kind::Maybe`. `Kind::Optional` remains available as an alias.
863
385
 
864
- * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Types.add`.
386
+ ## [1.3.0] - 2020-04-12
387
+ ### Added
388
+ - [#16](https://github.com/serradura/kind/pull/16) - Add the special type checkers `Kind::Of::Callable` (object responds to `:call`) and `Kind::Is::Callable` (class whose `public_instance_methods.include?(:call)`).
865
389
 
866
- * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Of::<Type>` and `Kind::Is::<Type>` modules.
390
+ ## [1.2.0] - 2020-04-12
391
+ ### Added
392
+ - [#15](https://github.com/serradura/kind/pull/15) - Add `Kind::Optional`, the Maybe monad: encapsulates an optional value (`Some` / `None`) and short-circuits chained operations when a `nil` / `Kind::Undefined` is produced. Exposes `#map`/`#then`, `#value`, `#some?`/`#none?`, `#value_or(default | { ... })`, `#try(method, *args)`, and the `Kind::Optional[value]` constructor.
393
+ - [#15](https://github.com/serradura/kind/pull/15) - Add `Kind::Undefined.to_s`, `Kind::Undefined.inspect`, `Kind::Undefined.clone`, `Kind::Undefined.dup`, and `Kind::Undefined.default(value, fallback)`.
867
394
 
868
- * [#44](https://github.com/serradura/kind/pull/44) - Remove `Kind::Checker`, `Kind::Checker::Protocol`, `Kind::Checker::Factory`.
869
-
870
- * [#44](https://github.com/serradura/kind/pull/44) - Remove the invocation of `Kind.is` without arguments.
871
-
872
- * [#44](https://github.com/serradura/kind/pull/44) - Remove the invocation of `Kind.of` without arguments.
873
-
874
- * [#44](https://github.com/serradura/kind/pull/44) - Remove the invocation of `Kind.of` with a single argument (the kind).
875
-
876
- 4.1.0 (2021-02-22)
877
- ------------------
878
-
879
- ### Added
880
-
881
- * [#43](https://github.com/serradura/kind/pull/43) - Make `Kind::Maybe::Typed` verify the kind of the value via `===`, because of this, now is possible to use type checkers in typed Maybes.
882
- ```ruby
883
- Kind::Maybe(Kind::Boolean).wrap(nil).value_or(false) # false
884
-
885
- Kind::Maybe(Kind::Boolean).wrap(true).value_or(false) # true
886
- ```
887
-
888
- * [#43](https://github.com/serradura/kind/pull/43) - Add `Kind::<Type>.maybe` and `Kind::<Type>.optional`. This method returns a typed Maybe with the expected kind when it is invoked without arguments. But, if it receives arguments, it will behave like the `Kind::Maybe.wrap` method. e.g.
889
- ```ruby
890
- Kind::Integer.maybe #<Kind::Maybe::Typed:0x0000... @kind=Kind::Integer>
891
-
892
- Kind::Integer.maybe(0).some? # true
893
- Kind::Integer.maybe { 1 }.some? # true
894
- Kind::Integer.maybe(2) { |n| n * 2 }.some? # true
895
-
896
- Kind::Integer.maybe { 2 / 0 }.none? # true
897
- Kind::Integer.maybe(2) { |n| n / 0 }.none? # true
898
- Kind::Integer.maybe('2') { |n| n * n }.none? # true
899
- ```
900
-
901
- * [#43](https://github.com/serradura/kind/pull/43) - Make the `:respond_to` kind validation verify by one or multiple methods. e.g.
902
- ```ruby
903
- validates :params, kind: { respond_to: [:[], :values_at] }
904
- ```
905
-
906
- * [#43](https://github.com/serradura/kind/pull/43) - Make the `:of` kind validation verify the expected value kind using `===`, because of this, now is possible to use type checkers as expected kinds. e.g.
907
- ```ruby
908
- validates :alive, kind: Kind::Boolean
909
- ```
910
-
911
- 4.0.0 (2021-02-22)
912
- ------------------
913
-
914
- ### Added
915
-
916
- * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.of_class?` to verify if a given value is a `Class`.
917
-
918
- * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.of_module?` to verify if a given value is a `Module`.
919
-
920
- * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.of_module_or_class()` that returns the given value if it is a module or a class. If not, a `Kind::Error` will be raised.
921
- ```ruby
922
- Kind.of_module_or_class(String) # String
923
- Kind.of_module_or_class(1) # Kind::Error (1 expected to be a kind of Module/Class)
924
- ```
925
-
926
- * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind.respond_to(object, *method_names)`, this method returns the given object if it responds to all of the method names. But if the object does not respond to some of the expected methods, an error will be raised.
927
- ```ruby
928
- Kind.respond_to('', :upcase) # ""
929
- Kind.respond_to('', :upcase, :strip) # ""
930
-
931
- Kind.respond_to(1, :upcase) # expected 1 to respond to :upcase
932
- Kind.respond_to(2, :to_s, :upcase) # expected 2 to respond to :upcase
933
- ```
934
-
935
- * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind::Try.call()`. This method invokes a public method with or without arguments like public_send does, except that if the receiver does not respond to it the call returns `nil` rather than raising an exception.
936
- ```ruby
937
- Kind::Try.(' foo ', :strip) # "foo"
938
- Kind::Try.({a: 1}, :[], :a) # 1
939
- Kind::Try.({a: 1}, :[], :b) # nil
940
- Kind::Try.({a: 1}, :fetch, :b, 2) # 2
941
-
942
- Kind::Try.(:symbol, :strip) # nil
943
- Kind::Try.(:symbol, :fetch, :b, 2) # nil
944
-
945
- # It raises an exception if the method name isn't a string or a symbol
946
- Kind::Try.({a: 1}, 1, :a) # TypeError (1 is not a symbol nor a string)
947
- ```
948
-
949
- * [#40](https://github.com/serradura/kind/pull/40), [#41](https://github.com/serradura/kind/pull/40) - Add `Kind::DEPRECATION` module to be used to warn about all of the deprecations. You can use the `DISABLE_KIND_DEPRECATION` environment variable to disable the warning messages.
950
-
951
- * [#40](https://github.com/serradura/kind/pull/40), [#41](https://github.com/serradura/kind/pull/40) - Add type checkers modules that have several utility methods related to type checking/handling.
952
- ```ruby
953
- # All of the methods used with the Kind::String can be used with any other type checker module.
954
-
955
- # Kind::<Type>.name
956
- # Kind::<Type>.kind
957
- # The type checker can return its kind and its name
958
- Kind::String.name # "String"
959
- Kind::String.kind # ::String
960
-
961
- # Kind::<Type>.===
962
- # Can check if a given value is an instance of its kind.
963
- Kind::String === 'foo' # true
964
- Kind::String === :foo # false
965
-
966
- # Kind::<Type>.value?(value)
967
- # Can check if a given value is an instance of its kind.
968
- Kind::String.value?('foo') # true
969
- Kind::String.value?(:foo) # false
970
-
971
- # If it doesn't receive an argument, a lambda will be returned and it will know how to do the type verification.
972
- [1, 2, 'foo', 3, 'Bar'].select?(&Kind::String.value?) # ["foo", "bar"]
973
-
974
- # Kind::<Type>.or_nil(value)
975
- # Can return nil if the given value isn't an instance of its kind
976
- Kind::String.or_nil('foo') # "foo"
977
- Kind::String.or_nil(:foo) # nil
978
-
979
- # Kind::<Type>.or_undefined(value)
980
- # Can return Kind::Undefined if the given value isn't an instance of its kind
981
- Kind::String.or_undefined('foo') # "foo"
982
- Kind::String.or_undefined(:foo) # Kind::Undefined
983
-
984
- # Kind::<Type>.or(fallback, value)
985
- # Can return a fallback if the given value isn't an instance of its kind
986
- Kind::String.or(nil, 'foo') # "foo"
987
- Kind::String.or(nil, :foo) # nil
988
-
989
- # If it doesn't receive a second argument (the value), it will return a callable that knows how to expose an instance of the expected type or a fallback if the given value is wrong.
990
- [1, 2, 'foo', 3, 'Bar'].map(&Kind::String.or('')) # ["", "", "foo", "", "Bar"]
991
- [1, 2, 'foo', 3, 'Bar'].map(&Kind::String.or(nil)) # [nil, nil, "foo", nil, "Bar"]
992
-
993
- # An error will be raised if the fallback didn't have the expected kind or if not nil / Kind::Undefined.
994
- [1, 2, 'foo', 3, 'Bar'].map(&Kind::String.or(:foo)) # Kind::Error (:foo expected to be a kind of String)
995
-
996
- # Kind::<Type>[value]
997
- # Will raise Kind::Error if the given value isn't an instance of the expected kind
998
- Kind::String['foo'] # "foo"
999
- Kind::String[:foo ] # Kind::Error (:foo expected to be a kind of String)
1000
- ```
1001
- * List of all type checkers:
1002
- * **Core:**
1003
- * `Kind::Array`
1004
- * `Kind::Class`
1005
- * `Kind::Comparable`
1006
- * `Kind::Enumerable`
1007
- * `Kind::Enumerator`
1008
- * `Kind::File`
1009
- * `Kind::Float`
1010
- * `Kind::Hash`
1011
- * `Kind::Integer`
1012
- * `Kind::IO`
1013
- * `Kind::Method`
1014
- * `Kind::Module`
1015
- * `Kind::Numeric`
1016
- * `Kind::Proc`
1017
- * `Kind::Queue`
1018
- * `Kind::Range`
1019
- * `Kind::Regexp`
1020
- * `Kind::String`
1021
- * `Kind::Struct`
1022
- * `Kind::Symbol`
1023
- * `Kind::Time`
1024
- * **Custom:**
1025
- * `Kind::Boolean`
1026
- * `Kind::Callable`
1027
- * `Kind::Lambda`
1028
- * **Stdlib:**
1029
- * `Kind::OpenStruct`
1030
- * `Kind::Set`
1031
-
1032
- * [#40](https://github.com/serradura/kind/pull/40) - Add `Kind::Of()`. This method allows the creation of type checkers in runtime. To do this, the kind must respond to the method `.===`, and if doesn't have the `.name` method (which needs to return a string), a hash must be provided with a filled `:name` property.
1033
- ```ruby
1034
- # Example using a class (an object which responds to .=== and has the .name method):
1035
- # This object will have all of the default methods that a standard type checker (e.g: Kind::String) has.
1036
- kind_of_string = Kind::Of(String)
1037
-
1038
- kind_of_string[''] # ""
1039
- kind_of_string[{}] # Kind::Error ({} expected to be a kind of String)
1040
-
1041
- # Example using a lambda (an object which responds to .===) and a hash with the kind name.
1042
-
1043
- PositiveInteger = Kind::Of(-> value { value.kind_of?(Integer) && value > 0 }, name: 'PositiveInteger')
1044
-
1045
- # PositiveInteger.name
1046
- # PositiveInteger.kind
1047
- # The type checker can return its kind and its name
1048
- PositiveInteger.name # "PositiveInteger"
1049
- PositiveInteger.kind # #<Proc:0x0000.... >
1050
-
1051
- # PositiveInteger.===
1052
- # Can check if a given value is an instance of its kind.
1053
- PositiveInteger === 1 # true
1054
- PositiveInteger === 0 # false
1055
-
1056
- # PositiveInteger.value?(value)
1057
- # Can check if a given value is an instance of its kind.
1058
- PositiveInteger.value?(1) # true
1059
- PositiveInteger.value?(-1) # false
1060
-
1061
- # If it doesn't receive an argument, a lambda will be returned and it will know how to do the type verification.
1062
- [1, 2, 0, 3, -1].select?(&PositiveInteger.value?) # [1, 2, 3]
1063
-
1064
- # PositiveInteger.or_nil(value)
1065
- # Can return nil if the given value isn't an instance of its kind
1066
- PositiveInteger.or_nil(1) # 1
1067
- PositiveInteger.or_nil(0) # nil
1068
-
1069
- # PositiveInteger.or_undefined(value)
1070
- # Can return Kind::Undefined if the given value isn't an instance of its kind
1071
- PositiveInteger.or_undefined(2) # 2
1072
- PositiveInteger.or_undefined(-1) # Kind::Undefined
1073
-
1074
- # PositiveInteger.or(fallback, value)
1075
- # Can return a fallback if the given value isn't an instance of its kind
1076
- PositiveInteger.or(nil, 1) # 1
1077
- PositiveInteger.or(nil, 0) # nil
1078
-
1079
- # If it doesn't receive a second argument (the value), it will return a callable that knows how to expose an instance of the expected type or a fallback if the given value is wrong.
1080
- [1, 2, 0, 3, -1].map(&PositiveInteger.or(1)) # [1, 2, 1, 3, 1]
1081
- [1, 2, 0, 3, -1].map(&PositiveInteger.or(nil)) # [1, 2, nil, 3, nil]
1082
-
1083
- # An error will be raised if the fallback didn't have the expected kind or if not nil / Kind::Undefined.
1084
- [1, 2, 0, 3, -1].map(&PositiveInteger.or(:foo)) # Kind::Error (:foo expected to be a kind of PositiveInteger)
1085
-
1086
- # PositiveInteger[value]
1087
- # Will raise Kind::Error if the given value isn't an instance of the expected kind
1088
- PositiveInteger[1] # 1
1089
- PositiveInteger[:foo] # Kind::Error (:foo expected to be a kind of PositiveInteger)
1090
- ```
1091
- * [#40](https://github.com/serradura/kind/pull/40), [#41](https://github.com/serradura/kind/pull/40) - Add type checkers methods.
1092
- ```ruby
1093
- # All of the methods used with the Kind::String? can be used with any other type checker method.
1094
-
1095
- # Kind::<Type>?(*values)
1096
- # Can check if a given value (one or many) is an instance of its kind.
1097
- Kind::String?('foo') # true
1098
- Kind::String?('foo', 'bar') # true
1099
- Kind::String?('foo', :bar) # false
1100
-
1101
- # If it doesn't receive an argument, a lambda will be returned and it will know how to do the type verification.
1102
- [1, 2, 'foo', 3, 'Bar'].select?(&Kind::String?) # ["foo", "bar"]
1103
- ```
1104
- * List of all type checkers:
1105
- * **Core:**
1106
- * `Kind::Array?`
1107
- * `Kind::Class?`
1108
- * `Kind::Comparable?`
1109
- * `Kind::Enumerable?`
1110
- * `Kind::Enumerator?`
1111
- * `Kind::File?`
1112
- * `Kind::Float?`
1113
- * `Kind::Hash?`
1114
- * `Kind::Integer?`
1115
- * `Kind::IO?`
1116
- * `Kind::Method?`
1117
- * `Kind::Module?`
1118
- * `Kind::Numeric?`
1119
- * `Kind::Proc?`
1120
- * `Kind::Queue?`
1121
- * `Kind::Range?`
1122
- * `Kind::Regexp?`
1123
- * `Kind::String?`
1124
- * `Kind::Struct?`
1125
- * `Kind::Symbol?`
1126
- * `Kind::Time?`
1127
- * **Custom:**
1128
- * `Kind::Boolean?`
1129
- * `Kind::Callable?`
1130
- * `Kind::Lambda?`
1131
- * **Stdlib:**
1132
- * `Kind::OpenStruct?`
1133
- * `Kind::Set?`
1134
-
1135
- * [#41](https://github.com/serradura/kind/pull/41) - Make `Kind::Dig.call` extract values from regular objects.
1136
- ```ruby
1137
- class Person
1138
- attr_reader :name
1139
-
1140
- def initialize(name)
1141
- @name = name
1142
- end
1143
- end
1144
-
1145
- person = Person.new('Rodrigo')
1146
-
1147
- Kind::Dig.(person, [:name]) # "Rodrigo"
1148
-
1149
- Kind::Dig.({people: [person]}, [:people, 0, :name]) # "Rodrigo"
1150
- ```
1151
-
1152
- * [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::Presence.call`. Returns the given value if it's present otherwise it will return `nil`.
1153
- ```ruby
1154
- Kind::Presence.(true) # true
1155
- Kind::Presence.('foo') # "foo"
1156
- Kind::Presence.([1, 2]) # [1, 2]
1157
- Kind::Presence.({a: 3}) # {a: 3}
1158
- Kind::Presence.(Set.new([4])) # #<Set: {4}>
1159
-
1160
- Kind::Presence.('') # nil
1161
- Kind::Presence.(' ') # nil
1162
- Kind::Presence.("\t\n\r") # nil
1163
- Kind::Presence.("\u00a0") # nil
1164
-
1165
- Kind::Presence.([]) # nil
1166
- Kind::Presence.({}) # nil
1167
- Kind::Presence.(Set.new) # nil
1168
-
1169
- Kind::Presence.(nil) # nil
1170
- Kind::Presence.(false) # nil
1171
-
1172
- # nil will be returned if the given object responds to the method blank? and this method result is true.
1173
- MyObject = Struct.new(:is_blank) do
1174
- def blank?
1175
- is_blank
1176
- end
1177
- end
1178
-
1179
- my_object = MyObject.new
1180
-
1181
- my_object.is_blank = true
1182
-
1183
- Kind::Presence.(my_object) # nil
1184
-
1185
- my_object.is_blank = false
1186
-
1187
- Kind::Presence.(my_object) # #<struct MyObject is_blank=false>
1188
- ```
1189
-
1190
- * [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::Maybe#presence`, this method will return None if the wrapped value wasn't present.
1191
- ```ruby
1192
- result1 = Kind::Maybe(Hash).wrap(foo: '').dig(:foo).presence
1193
- result1.none? # true
1194
- result1.value # nil
1195
-
1196
- result2 = Kind::Maybe(Hash).wrap(foo: 'bar').dig(:foo).presence
1197
- result2.none? # false
1198
- result2.value # "bar"
1199
- ```
1200
-
1201
- * [#41](https://github.com/serradura/kind/pull/41) - Make `Kind::Maybe#wrap` receive a block and intercept StandardError exceptions. And a None will be returned if some exception happening.
1202
- ```ruby
1203
- Kind::Maybe.wrap { 2 / 0 } # #<Kind::Maybe::None:0x0000... @value=#<ZeroDivisionError: divided by 0>>
1204
-
1205
- Kind::Maybe(Numeric).wrap(2) { |number| number / 0 } # #<Kind::Maybe::None:0x0000... @value=#<ZeroDivisionError: divided by 0>>
1206
- ```
1207
-
1208
- * [#41](https://github.com/serradura/kind/pull/41) - Make `Kind::Maybe#map` intercept StandardError exceptions.
1209
- * Now the `#map` and `#then` methods will intercept any StandardError and return None with the exception or their values.
1210
- * Add `#map!` and `#then!` that allows the exception leak, so, the user must handle the exception by himself or use this method when he wants to see the error be raised.
1211
- * If an exception (StandardError) is returned by the methods `#then`, `#map` it will be resolved as None.
1212
- ```ruby
1213
- # Handling StandardError exceptions
1214
- result1 = Kind::Maybe[2].map { |number| number / 0 }
1215
- result1.none? # true
1216
- result1.value # #<ZeroDivisionError: divided by 0>
1217
-
1218
- result2 = Kind::Maybe[3].then { |number| number / 0 }
1219
- result2.none? # true
1220
- result2.value # #<ZeroDivisionError: divided by 0>
1221
-
1222
- # Leaking StandardError exceptions
1223
- Kind::Maybe[2].map! { |number| number / 0 } # ZeroDivisionError (divided by 0)
1224
-
1225
- Kind::Maybe[2].then! { |number| number / 0 } # ZeroDivisionError (divided by 0)
1226
- ```
1227
-
1228
- * [#41](https://github.com/serradura/kind/pull/41) - Add `Kind::TypeCheckers#value`. This method ensures that you will have a value of the expected kind. But, in the case of the given value be invalid, this method will require a default value (with the expected kind) to be returned.
1229
- ```ruby
1230
- # Using built-in type checkers
1231
- Kind::String.value(1, default: '') # ""
1232
- Kind::String.value('1', default: '') # "1"
1233
-
1234
- Kind::String.value('1', default: 1) # Kind::Error (1 expected to be a kind of String)
1235
-
1236
- # Using custom type checkers
1237
- PositiveInteger = Kind::Of(-> value { value.kind_of?(Integer) && value > 0 }, name: 'PositiveInteger')
1238
-
1239
- PositiveInteger.value(0, default: 1) # 1
1240
- PositiveInteger.value(2, default: 1) # 2
1241
-
1242
- PositiveInteger.value(-1, default: 0) # Kind::Error (0 expected to be a kind of PositiveInteger)
1243
- ```
1244
-
1245
- * [#41](https://github.com/serradura/kind/pull/41) - Add the method `value_or_empty` for some type checkers. This method is available for some type checkers (`Kind::Array`, `Kind::Hash`, `Kind::String`, `Kind::Set`), and it will return an empty frozen value if the given value hasn't the expected kind.
1246
- ```ruby
1247
- Kind::Array.value_or_empty({}) # []
1248
- Kind::Array.value_or_empty({}).frozen? # true
1249
- ```
1250
-
1251
- * [#42](https://github.com/serradura/kind/pull/42) - Add the method `Kind.value`. This method ensures that you will have a value of the expected kind. But, in the case of the given value be invalid, this method will require a default value (with the expected kind) to be returned.
1252
- ```ruby
1253
- Kind.value(String, '1', default: '') # "1"
1254
-
1255
- Kind.value(String, 1, default: '') # ""
1256
-
1257
- Kind.value(String, 1, default: 2) # Kind::Error (2 expected to be a kind of String)
1258
- ```
1259
-
1260
- * [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Presence.to_proc`. This method allow you to make use of the `Kind::Presence` in methods that receive a block as an argument. e.g:
1261
- ```ruby
1262
- ['', [], {}, '1', [2]].map(&Kind::Presence) # [nil, nil, nil, "1", [2]]
1263
- ```
1264
-
1265
- * [#42](https://github.com/serradura/kind/pull/42) - `Kind::Maybe(<Type>).{new,[],wrap}` Now, these methods know how to get the value of another Maybe monad.
1266
- ```ruby
1267
- some_number = Kind::Some(2)
1268
-
1269
- Kind::Maybe(Numeric)[some_number] # #<Kind::Maybe::Some:0x0000... @value=2>
1270
-
1271
- Kind::Maybe(Numeric).new(some_number) # #<Kind::Maybe::Some:0x0000... @value=2>
1272
-
1273
- Kind::Maybe(Numeric).wrap(some_number) # #<Kind::Maybe::Some:0x0000... @value=2>
1274
-
1275
- Kind::Maybe(Numeric).wrap { some_number } # #<Kind::Maybe::Some:0x0000... @value=2>
1276
-
1277
- Kind::Maybe(Numeric).wrap(some_number) { |number| number / 2 } # #<Kind::Maybe::Some:0x0000... @value=1>
1278
- ```
1279
-
1280
- * [#42](https://github.com/serradura/kind/pull/42) - `Kind::Maybe(<Type>).wrap(arg) { |arg_value| }` if the block receives an argument, the typed Maybe monad will verify if the argument is from the expected kind.
1281
- ```ruby
1282
- Kind::Maybe(Numeric).wrap('2') { |number| number / 0 } # #<Kind::Maybe::None:0x0000... @value=nil>
1283
-
1284
- Kind::Maybe(Numeric).wrap(2) { |number| number / 0 } # #<Kind::Maybe::None:0x0000... @value=#<ZeroDivisionError: divided by 0>>
1285
- ```
1286
-
1287
- * [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Maybe#check`. This method returns the current Some after verifies if the block output was truthy.
1288
- ```ruby
1289
- person_name = ->(params) do
1290
- Kind::Maybe(Hash)
1291
- .wrap(params)
1292
- .then { |hash| hash.values_at(:first_name, :last_name) }
1293
- .then { |names| names.map(&Kind::Presence).tap(&:compact!) }
1294
- .check { |names| names.size == 2 }
1295
- .then { |(first_name, last_name)| "#{first_name} #{last_name}" }
1296
- .value_or { 'John Doe' }
1297
- end
1298
-
1299
- person_name.('') # "John Doe"
1300
- person_name.(nil) # "John Doe"
1301
- person_name.(last_name: 'Serradura') # "John Doe"
1302
- person_name.(first_name: 'Rodrigo') # "John Doe"
1303
-
1304
- person_name.(first_name: 'Rodrigo', last_name: 'Serradura') # "Rodrigo Serradura"
1305
- ```
1306
-
1307
- * [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Dig[]`. This method knows how to create a lambda that will know how to perform the dig strategy.
1308
- ```ruby
1309
- results = [
1310
- { person: {} },
1311
- { person: { name: 'Foo Bar'} },
1312
- { person: { name: 'Rodrigo Serradura'} },
1313
- ].map(&Kind::Dig[:person, :name])
1314
-
1315
- p results # [nil, "Foo Bar", "Rodrigo Serradura"],
1316
- ```
1317
-
1318
- * [#42](https://github.com/serradura/kind/pull/42) - Add `Kind::Try[]`. This method knows how to create a lambda that will know how to perform the try strategy.
1319
- ```ruby
1320
- results =
1321
- [
1322
- {},
1323
- {name: 'Foo Bar'},
1324
- {name: 'Rodrigo Serradura'},
1325
- ].map(&Kind::Try[:fetch, :name, 'John Doe'])
1326
-
1327
- p results # ["John Doe", "Foo Bar", "Rodrigo Serradura"]
1328
- ```
1329
-
1330
- ### Deprecated
1331
-
1332
- * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Is.call`
1333
-
1334
- * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Of.call`
1335
-
1336
- * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Types.add`.
1337
-
1338
- * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Of::<Type>` and `Kind::Is::<Type>` modules.
1339
-
1340
- * [#40](https://github.com/serradura/kind/pull/40) - Deprecate `Kind::Checker`, `Kind::Checker::Protocol`, `Kind::Checker::Factory`.
1341
-
1342
- * [#40](https://github.com/serradura/kind/pull/40) - Deprecate the invocation of `Kind.is` without arguments.
1343
-
1344
- * [#40](https://github.com/serradura/kind/pull/40) - Deprecate the invocation of `Kind.of` without arguments.
1345
-
1346
- * [#40](https://github.com/serradura/kind/pull/40) - Deprecate the invocation of `Kind.of` with a single argument (the kind).
1347
-
1348
- ### Fixed
1349
-
1350
- * [#40](https://github.com/serradura/kind/pull/40) - Make `Kind::Maybe.try!()` raises an error if it was called without a block or arguments.
1351
-
1352
- [⬆️ &nbsp;Back to Top](#changelog-)
1353
-
1354
- 3.1.0 (2020-07-08)
1355
- ------------------
1356
-
1357
- ### Added
1358
-
1359
- * [#33](https://github.com/serradura/kind/pull/33) - Add new type checker.
1360
- - `Kind::Of::OpenStruct`, `Kind::Is::OpenStruct`
1361
-
1362
- * [#33](https://github.com/serradura/kind/pull/33) - Add `Kind::Maybe::Result#dig`. It extracts the nested value in a sequence of objects, if any step returns `nil` the operation will stop and `None` will be returned, otherwise a `Some` will be returned with the final value.
1363
- ```ruby
1364
- class User
1365
- def self.find_by(id:)
1366
- return :user_1 if id == 1
1367
- end
1368
- end
1369
-
1370
- Kind::Optional(Hash).wrap(user: { id: 2 }).dig(:user).value # {:id=>2}
1371
-
1372
- # --
1373
-
1374
- user_id = Kind::Optional(Hash).wrap(user: { id: 1 }).dig(:user, :id)
1375
-
1376
- user_id.then { |id| User.find_by(id: id) }.value # :user_id
1377
- ```
1378
-
1379
- * [#33](https://github.com/serradura/kind/pull/33) - Add the utility module `Kind::Dig`. It has the same behavior of Ruby dig methods ([Hash](https://ruby-doc.org/core-2.3.0/Hash.html#method-i-dig), [Array](https://ruby-doc.org/core-2.3.0/Array.html#method-i-dig), [Struct](https://ruby-doc.org/core-2.3.0/Struct.html#method-i-dig), [OpenStruct](https://ruby-doc.org/stdlib-2.3.0/libdoc/ostruct/rdoc/OpenStruct.html#method-i-dig)), but it will not raise an error if some step can't be digged.
1380
- ```ruby
1381
- s = Struct.new(:a, :b).new(101, 102)
1382
- o = OpenStruct.new(c: 103, d: 104)
1383
- d = { struct: s, ostruct: o, data: [s, o]}
1384
-
1385
- Kind::Dig.(s, [:a]) # 101
1386
- Kind::Dig.(o, [:c]) # 103
1387
-
1388
- Kind::Dig.(d, [:struct, :b]) # 102
1389
- Kind::Dig.(d, [:data, 0, :b]) # 102
1390
- Kind::Dig.(d, [:data, 0, 'b']) # 102
1391
-
1392
- Kind::Dig.(d, [:ostruct, :d]) # 104
1393
- Kind::Dig.(d, [:data, 1, :d]) # 104
1394
- Kind::Dig.(d, [:data, 1, 'd']) # 104
1395
-
1396
- Kind::Dig.(d, [:struct, :f]) # nil
1397
- Kind::Dig.(d, [:ostruct, :f]) # nil
1398
- Kind::Dig.(d, [:data, 0, :f]) # nil
1399
- Kind::Dig.(d, [:data, 1, :f]) # nil
1400
- ```
1401
-
1402
- [⬆️ &nbsp;Back to Top](#changelog-)
1403
-
1404
- 3.0.0 (2020-06-25)
1405
- ------------------
1406
-
1407
- ### Breaking Changes
1408
-
1409
- * [#31](https://github.com/serradura/kind/pull/31) - Change the `Kind::Maybe::Result#try()` behavior.
1410
- - If you don't want to use the methods `#map`/`#then` to access some value inside of the monad, you could use the `#try` method to do this. It invokes a public method with or without arguments like public_send does, except that if the receiver does not respond to it the call returns `nil` rather than raising an exception. So, if the value wasn't `nil` or `Kind::Undefined` a `Some` will be returned.
1411
- ```ruby
1412
- # Examples using Kind::Maybe
1413
-
1414
- Kind::Maybe['foo'].try(:upcase).value # "FOO"
1415
-
1416
- Kind::Maybe[{}].try(:fetch, :number, 0).value # 0
1417
-
1418
- Kind::Maybe[{number: 1}].try(:fetch, :number).value # 1
1419
-
1420
- Kind::Maybe[' foo '].try { |value| value.strip }.value # "foo"
1421
-
1422
- # Examples using Kind::Optional
1423
-
1424
- Kind::Optional[1].try(:strip).value_or('') # ""
1425
-
1426
- Kind::Optional[' Rodrigo '].try(:strip).value_or("") # 'Rodrigo'
1427
- ```
1428
-
1429
- ### Added
1430
-
1431
- * [#31](https://github.com/serradura/kind/pull/31) - Add `Kind::Maybe::Result#try!()` that have almost of the same behavior of `Kind::Maybe::Result#try()`, the difference is because it will raise an error when the monad value doesn't respond to the expected method.
1432
- ```ruby
1433
- Kind::Maybe[{}].try(:upcase) # => #<Kind::Maybe::None:0x0000... @value=nil>
1434
-
1435
- Kind::Maybe[{}].try!(:upcase) # => NoMethodError (undefined method `upcase' for {}:Hash)
1436
- ```
1437
-
1438
- [⬆️ &nbsp;Back to Top](#changelog-)
1439
-
1440
- 2.3.0 (2020-06-24)
1441
- ------------------
1442
-
1443
- ### Added
1444
-
1445
- * [#30](https://github.com/serradura/kind/pull/30) - Add `Kind::Maybe.wrap()` as an alias for `Kind::Maybe.new()`.
1446
-
1447
- * [#30](https://github.com/serradura/kind/pull/30) - Add `Kind::Maybe::Typed` and the methods `Kind::Maybe()`, `Kind::Optional()` to create typed monads. It will return `Some` if the given value has the expected kind or `None` if it hasn't.
1448
- ```ruby
1449
- Double = ->(arg) do
1450
- Kind::Optional(Numeric)
1451
- .wrap(arg)
1452
- .then { |number| number * 2 }
1453
- end
1454
- ```
1455
-
1456
- [⬆️ &nbsp;Back to Top](#changelog-)
1457
-
1458
- 2.2.0 (2020-06-23)
1459
- ------------------
1460
-
1461
- ### Added
1462
-
1463
- * [#29](https://github.com/serradura/kind/pull/29) - Improve the comparison of values with `Kind::Undefined`.
1464
- - I've been using `Kind.of(ActiveRecord::Relation, some_ar_relation)` in one of my apps and I found an unexpected behavior, the relations were always been executed. The reason is `ActiveRecord::AssociationRelation#==` behavior, which always performs a query (`to_a`). So, to avoid this and other unexpected behaviors, I decided to invert the comparison with `Kind::Undefined` to ensure a regular equality checking.
1465
-
1466
- [⬆️ &nbsp;Back to Top](#changelog-)
1467
-
1468
- 2.1.0 (2020-05-12)
1469
- ------------------
1470
-
1471
- ### Added
1472
-
1473
- * [#28](https://github.com/serradura/kind/pull/28) - Allow passing multiple arguments to `Kind.of.<Type>.instance?(*args)`
1474
-
1475
- * [#28](https://github.com/serradura/kind/pull/28) - Allow passing multiple arguments to `Kind.of.<Type>?(*args)`
1476
-
1477
- * [#28](https://github.com/serradura/kind/pull/28) - Add `Kind::Some()` and `Kind::None()`. e.g:
1478
- ```ruby
1479
- Double = ->(arg) do
1480
- number = Kind::Of::Numeric.or_nil(arg)
1481
-
1482
- Kind::Optional[number].then { |number| number * 2 }
1483
- end
1484
-
1485
- Add = -> params do
1486
- a, b = Kind::Of::Hash(params, or: Empty::HASH).values_at(:a, :b)
1487
-
1488
- return Kind::None unless Kind::Of::Numeric?(a, b)
1489
-
1490
- Kind::Some(a + b)
1491
- end
1492
-
1493
- Kind::Optional[a: 1, b: 2].then(&Add).value_or(0) # 3
1494
-
1495
- Add.({}).some? # false
1496
-
1497
- Add.(a: 1, b: '2').some? # false
1498
-
1499
- Add.(a: 2, b: 2).then(&Double).value # 8
1500
- ```
1501
-
1502
- * [#28](https://github.com/serradura/kind/pull/28) - Add `Kind.of?(<Type>, *args)` to check if one or many values are the expected kind.
1503
- ```ruby
1504
- Kind.of?(Numeric, 1, 2.0, 3) # true
1505
- Kind.of?(Numeric, 1, '2', 3) # false
1506
- ```
1507
-
1508
- * [#28](https://github.com/serradura/kind/pull/28) - Make the `Kind.of?(<Type>)` returns a lambda that knows how to do the type verification.
1509
- ```ruby
1510
- [1, '2', 3].select(&Kind.of?(Numeric)) # [1, 3]
1511
- ```
1512
-
1513
- ### Breaking Changes
1514
-
1515
- * [#28](https://github.com/serradura/kind/pull/28) - Make `Kind.of.<Type>.to_proc` have the same behavior of `Kind.of.<Type>.instance(value)` (returns the value if it has the expected kind or raise `Kind::Error` if it haven't). This change is because now we have a method to verify if the given value is an instance of the expected kind (`Kind.of.<Type>?`), and this new method has a `to_proc` behavior when is called without arguments.
1516
- ```ruby
1517
- [1, 2, 3].map(&Kind::Of::Numeric) # [1, 2, 3]
1518
-
1519
- [1, '2', 3].map(&Kind::Of::Numeric) # Kind::Error ("2" expected to be a kind of Numeric)
1520
-
1521
- [1, '2', 3].select(&Kind::Of::Numeric?) # [1, 3]
1522
- ```
1523
-
1524
- [⬆️ &nbsp;Back to Top](#changelog-)
1525
-
1526
- 2.0.0 (2020-05-07)
1527
- ------------------
1528
-
1529
- ### Added
1530
-
1531
- * [#24](https://github.com/serradura/kind/pull/24) - Improve the `kind: { is: }` validation to check the inheritance of *classes*/*modules*.
1532
-
1533
- ### Breaking Changes
1534
-
1535
- * [#24](https://github.com/serradura/kind/pull/24) - Change the `Kind.{of,is}.Callable` verification. Now, it only verifies if the given object `respond_to?(:call)`.
1536
-
1537
- ### Removed
1538
-
1539
- * [#24](https://github.com/serradura/kind/pull/24) - Remove `kind: { is_a: }` from `Kind::Validator`.
1540
- * [#24](https://github.com/serradura/kind/pull/24) - Remove `kind: { klass: }` from `Kind::Validator`.
1541
-
1542
- [⬆️ &nbsp;Back to Top](#changelog-)
1543
-
1544
- 1.9.0 (2020-05-06)
1545
- ------------------
1546
-
1547
- ### Added
1548
-
1549
- * [#23](https://github.com/serradura/kind/pull/23) - Add `Kind.of.<Type>.to_proc` as an alias for `Kind.of.<Type>.instance?`.
1550
- ```ruby
1551
- collection = [
1552
- {number: 1},
1553
- 'number 0',
1554
- {number: 2},
1555
- [0],
1556
- ]
1557
-
1558
- collection
1559
- .select(&Kind.of.Hash)
1560
- .reduce(0) { |total, item| total + item[:number] }
1561
- ```
1562
-
1563
- * [#23](https://github.com/serradura/kind/pull/23) - Add `Kind::Validator` (`ActiveModel` validator) as an alternative (substitute) of [`type_validator`](https://github.com/serradura/type_validator).
1564
- ```ruby
1565
- require 'kind/active_model/validation'
1566
-
1567
- class Person
1568
- include ActiveModel::Validations
1569
-
1570
- attr_reader :name, :age
1571
-
1572
- validates :name, kind: { of: String }
1573
- validates :age, kind: { of: Integer }
1574
-
1575
- def initialize(name:, age:)
1576
- @name, @age = name, age
1577
- end
1578
- end
1579
-
1580
- person = Person.new(name: 'John', age: '21')
1581
-
1582
- person.valid? # false
1583
-
1584
- person.errors[:age] # ['must be a kind of: Integer']
1585
- ```
1586
-
1587
- [⬆️ &nbsp;Back to Top](#changelog-)
1588
-
1589
- 1.8.0 (2020-05-03)
1590
- ------------------
1591
-
1592
- ### Added
1593
-
1594
- * [#22](https://github.com/serradura/kind/pull/22) - `Kind.of.<Type>.instance?`returns a lambda when called without an argument.
1595
- ```ruby
1596
- collection = [
1597
- {number: 1},
1598
- 'number 0',
1599
- {number: 2},
1600
- [0],
1601
- ]
1602
-
1603
- collection
1604
- .select(&Kind::Of::Hash.instance?)
1605
- .reduce(0) { |total, item| total + item[:number] }
1606
- ```
1607
-
1608
- * [#22](https://github.com/serradura/kind/pull/22) - Add new methods `.as_optional`, `.as_maybe` in the type checkers.
1609
- ```ruby
1610
- def person_name(params)
1611
- Kind::Of::Hash
1612
- .as_optional(params)
1613
- .map { |data| data.values_at(:first_name, :last_name).compact }
1614
- .map { |first, last| "#{first} #{last}" if first && last }
1615
- .value_or { 'John Doe' }
1616
- end
1617
-
1618
- person_name('') # "John Doe"
1619
- person_name(nil) # "John Doe"
1620
- person_name(first_name: 'Rodrigo') # "John Doe"
1621
- person_name(last_name: 'Serradura') # "John Doe"
1622
- person_name(first_name: 'Rodrigo', last_name: 'Serradura') # "Rodrigo Serradura"
1623
-
1624
- # A lambda will be returned if these methods receive only one argument
1625
-
1626
- collection = [
1627
- {number: 1},
1628
- 'number 0',
1629
- {number: 2},
1630
- [0],
1631
- ]
1632
-
1633
- collection
1634
- .map(&Kind.of.Hash.as_optional)
1635
- .select(&:some?)
1636
- .reduce(0) { |total, item| total + item.value[:number] }
1637
- ```
1638
-
1639
- [⬆️ &nbsp;Back to Top](#changelog-)
1640
-
1641
- 1.7.0 (2020-05-03)
1642
- ------------------
395
+ ## [1.1.0] - 2020-04-09
396
+ ### Added
397
+ - [#14](https://github.com/serradura/kind/pull/14) - Add `Kind::Undefined`, representing an undefined value distinct from `nil`.
1643
398
 
1644
399
  ### Fixed
1645
-
1646
- * [#20](https://github.com/serradura/kind/pull/20) - Fix the verification of modules using `Kind.is()`.
1647
-
1648
- [⬆️ &nbsp;Back to Top](#changelog-)
1649
-
1650
- 1.6.0 (2020-04-17)
1651
- ------------------
1652
-
1653
- ### Added
1654
-
1655
- * [#19](https://github.com/serradura/kind/pull/19) - Add aliases to perform the strict type verification (in registered type checkers).
1656
- ```ruby
1657
- # Kind.of.<Type>[]
1658
-
1659
- Kind.of.Hash[nil] # raise Kind::Error, "nil expected to be a kind of Hash"
1660
- Kind.of.Hash[''] # raise Kind::Error, "'' expected to be a kind of Hash"
1661
- Kind.of.Hash[a: 1] # {a: 1}
1662
- Kind.of.Hash['', or: {}] # {}
1663
-
1664
- # Kind.of.<Type>.instance()
1665
-
1666
- Kind.of.Array.instance(nil) # raise Kind::Error, "nil expected to be a kind of Array"
1667
- Kind.of.Array.instance('') # raise Kind::Error, "'' expected to be a kind of Array"
1668
- Kind.of.Array.instance([]) # []
1669
- Kind.of.Array.instance('', or: []) # []
1670
- ```
1671
-
1672
- * [#19](https://github.com/serradura/kind/pull/19) - Add `.or_undefined` method for any type checker.
1673
- ```ruby
1674
- Kind.of.String.or_undefined(nil) # Kind::Undefined
1675
- Kind.of.String.or_undefined("something") # "something"
1676
- ```
1677
-
1678
- * [#19](https://github.com/serradura/kind/pull/19) - Allow a dynamical verification of types.
1679
- ```ruby
1680
- class User
1681
- end
1682
-
1683
- class AdminUser < User
1684
- end
1685
-
1686
- Kind.of(User, User.new) # #<User:0x0000...>
1687
- Kind.of(User, {}) # Kind::Error ({} expected to be a kind of User)
1688
- ```
1689
-
1690
- * [#19](https://github.com/serradura/kind/pull/19) - Allow the creation of type checkers dynamically (without register one).
1691
- ```ruby
1692
- class User
1693
- end
1694
-
1695
- kind_of_user = Kind.of(User)
1696
-
1697
- kind_of_user[{}] # Kind::Error ({} expected to be a kind of User)
1698
- kind_of_user[User.new] # #<User:0x0000...>
1699
-
1700
- kind_of_user.instance({}) # Kind::Error ({} expected to be a kind of User)
1701
- kind_of_user.instance(User.new) # #<User:0x0000...>
1702
-
1703
- kind_of_user.instance?({}) # false
1704
- kind_of_user.instance?(User.new) # true
1705
-
1706
- kind_of_user.class?(Hash) # false
1707
- kind_of_user.class?(User) # true
1708
-
1709
- kind_of_user.or_undefined({}) # Kind::Undefined
1710
- kind_of_user.or_undefined(User.new) # #<User:0x0000...>
1711
- ```
1712
-
1713
- * [#19](https://github.com/serradura/kind/pull/19) - Add a new type checkers.
1714
- - `Kind::Of::Set`
1715
- - `Kind::Of::Maybe`, `Kind::Of::Optional`
1716
-
1717
- * [#19](https://github.com/serradura/kind/pull/19) - Add `Kind::Empty` with several constants having empty frozen objects.
1718
- ```ruby
1719
- Kind::Empty::SET
1720
- Kind::Empty::HASH
1721
- Kind::Empty::ARRAY
1722
- Kind::Empty::STRING
1723
-
1724
- # If there isn't any constant named as Empty, the gem will use it to create an alias for Kind::Empty.
1725
-
1726
- Empty::SET == Kind::Empty::SET
1727
- Empty::HASH == Kind::Empty::HASH
1728
- Empty::ARRAY == Kind::Empty::ARRAY
1729
- Empty::STRING == Kind::Empty::STRING
1730
- ```
1731
-
1732
- ### Changes
1733
-
1734
- * [#19](https://github.com/serradura/kind/pull/19) - Change the output of `Kind::Undefined.to_s`, `Kind::Undefined.inspect`, the previous output was `"Undefined"` and the new is `"Kind::Undefined"`
1735
- ```ruby
1736
- Kind::Undefined.to_s # "Kind::Undefined"
1737
- Kind::Undefined.inspect # "Kind::Undefined"
1738
- ```
1739
-
1740
- [⬆️ &nbsp;Back to Top](#changelog-)
1741
-
1742
- 1.5.0 (2020-04-12)
1743
- ------------------
1744
-
1745
- ### Added
1746
-
1747
- * [#18](https://github.com/serradura/kind/pull/18) - Refactor `Kind::Maybe`.
1748
-
1749
- * [#18](https://github.com/serradura/kind/pull/18) - Add `Kind::Maybe::Value` module, that has the `.some?` and `.none?` methods. Available to check if the given value is `Some` or `None`.
1750
- ```ruby
1751
- Kind::Maybe::Value.some?(1) # true
1752
- Kind::Maybe::Value.some?(nil) # false
1753
- Kind::Maybe::Value.some?(Kind::Undefined) # false
1754
-
1755
- Kind::Maybe::Value.none?(1) # false
1756
- Kind::Maybe::Value.none?(nil) # true
1757
- Kind::Maybe::Value.none?(Kind::Undefined) # true
1758
- ```
1759
-
1760
- [⬆️ &nbsp;Back to Top](#changelog-)
1761
-
1762
- 1.4.0 (2020-04-12)
1763
- ------------------
1764
-
1765
- ### Added
1766
-
1767
- * [#17](https://github.com/serradura/kind/pull/17) - Transform `Kind::Optional` into `Kind::Maybe`. `Kind::Optional` still is available but as an alias for `Kind::Maybe`.
1768
-
1769
- [⬆️ &nbsp;Back to Top](#changelog-)
1770
-
1771
- 1.3.0 (2020-04-12)
1772
- ------------------
1773
-
1774
- ### Added
1775
-
1776
- * [#16](https://github.com/serradura/kind/pull/16) - Add a new special type checkers.
1777
- - `Kind::Of::Callable` for check if the given object respond to `call`.
1778
- - `Kind::Is::Callable` if the given value is a `class`, it will verifies if its `public_instance_methods.include?(:call)`.
1779
-
1780
- [⬆️ &nbsp;Back to Top](#changelog-)
1781
-
1782
- 1.2.0 (2020-04-12)
1783
- ------------------
1784
-
1785
- ### Added
1786
-
1787
- * [#15](https://github.com/serradura/kind/pull/15) - Add `Kind::Optional` the maybe monad, it encapsulates an optional value. A `Kind::Optional` either contains a value (represented as `Some`), or it is empty (represented as `None`). This data structure is helpful to transform a value through several operations, but if any of them returns `nil` or `Kind::Undefined` as its result, the next operations will be avoided.
1788
- ```ruby
1789
- # Some value
1790
-
1791
- optional =
1792
- Kind::Optional.new(2)
1793
- .map { |value| value * 2 }
1794
- .map { |value| value * 2 }
1795
-
1796
- puts optional.value # 8
1797
- puts optional.some? # true
1798
- puts optional.none? # false
1799
-
1800
- puts optional.value_or(0) # 8
1801
- puts optional.value_or { 0 } # 8
1802
-
1803
- # None value
1804
-
1805
- even_number = Kind::Optional.new(3).map { |n| n if n.even? }
1806
-
1807
- even_number.none? # true
1808
-
1809
- even_number.value_or(0) # 0
1810
-
1811
- # Utility method
1812
-
1813
- # Kind::Optional#try
1814
- # You could use the `#try` method to perform a method of the wrapped object and return its value.
1815
-
1816
- Kind::Optional.new(' Rodrigo ').try(:strip) # "Rodrigo"
1817
-
1818
- # Method aliases
1819
-
1820
- # Kind::Optional[] is an alias for Kind::Optional.new
1821
- Kind::Optional[2].map { |n| n if n.even? }.value_or(0) # 2
1822
-
1823
- # Kind::Optional::Result#then is an alias for Kind::Optional::Result#map
1824
- Kind::Optional[1].then { |n| n if n.even? }.value_or(0) # 0
1825
- ```
1826
-
1827
- * [#15](https://github.com/serradura/kind/pull/15) - Add new methods to `Kind::Undefined`.
1828
- ```ruby
1829
- Kind::Undefined.to_s # 'Undefined'
1830
- Kind::Undefined.inspect # 'Undefined'
1831
-
1832
- Kind::Undefined.clone # #<Kind::Undefined:0x0000...>
1833
- Kind::Undefined.dup # #<Kind::Undefined:0x0000...>
1834
-
1835
- Kind::Undefined.clone == Kind::Undefined # true
1836
- Kind::Undefined.clone === Kind::Undefined # true
1837
-
1838
- Kind::Undefined.dup == Kind::Undefined # true
1839
- Kind::Undefined.dup === Kind::Undefined # true
1840
-
1841
- value = Kind::Undefined
1842
-
1843
- Kind::Undefined.default(value, 1) # 1
1844
- ```
1845
-
1846
- [⬆️ &nbsp;Back to Top](#changelog-)
1847
-
1848
- 1.1.0 (2020-04-09)
1849
- ------------------
1850
-
1851
- ### Added
1852
-
1853
- * [#14](https://github.com/serradura/kind/pull/14) - Add `Kind::Undefined` representing an undefined value to contrast with `nil`.
1854
-
1855
- ### Fixed
1856
-
1857
- * [#14](https://github.com/serradura/kind/pull/14) - Raise a `Kind::Error` if `nil` is the argument of any strict type checker.
1858
- ```ruby
1859
- Kind.of.Hash(nil) # raise Kind::Error, "nil expected to be a kind of Hash"
1860
- ```
1861
-
1862
- [⬆️ &nbsp;Back to Top](#changelog-)
1863
-
1864
- 1.0.0 (2020-03-16)
1865
- ------------------
1866
-
1867
- ### Added
1868
-
1869
- * [#12](https://github.com/serradura/kind/pull/12) - Register type checkers respecting their namespaces.
1870
- ```ruby
1871
- module Account
1872
- class User
1873
- Kind::Types.add(self)
1874
- end
1875
- end
1876
-
1877
- module Account
1878
- class User
1879
- class Membership
1880
- Kind::Types.add(self)
1881
- end
1882
- end
1883
- end
1884
-
1885
- account_user = Account::User.new
1886
-
1887
- Kind.of.Account::User(account_user) # #<Account::User:0x0000...>
1888
- Kind.of.Account::User({}) # Kind::Error ({} expected to be a kind of Account::User)
1889
-
1890
- Kind.of.Account::User.or_nil({}) # nil
1891
-
1892
- Kind.of.Account::User.instance?({}) # false
1893
- Kind.of.Account::User.instance?(account_user) # true
1894
-
1895
- Kind.of.Account::User.class?(Hash) # false
1896
- Kind.of.Account::User.class?(Account::User) # true
1897
-
1898
- # ---
1899
-
1900
- membership = Account::User::Membership.new
1901
-
1902
- Kind.of.Account::User::Membership(membership) # #<Account::User::Membership:0x0000...>
1903
- Kind.of.Account::User::Membership({}) # Kind::Error ({} expected to be a kind of Account::User::Membership)
1904
-
1905
- Kind.of.Account::User::Membership.or_nil({}) # nil
1906
-
1907
- Kind.of.Account::User::Membership.instance?({}) # false
1908
- Kind.of.Account::User::Membership.instance?(membership) # true
1909
-
1910
- Kind.of.Account::User::Membership.class?(Hash) # false
1911
- Kind.of.Account::User::Membership.class?(Account::User::Membership) # true
1912
- ```
1913
-
1914
- [⬆️ &nbsp;Back to Top](#changelog-)
1915
-
1916
- 0.6.0 (2020-01-06)
1917
- ------------------
1918
-
1919
- ### Added
1920
-
1921
- * [#11](https://github.com/serradura/kind/pull/11) - Register the `Queue` (`Thread::Queue`) type checker. This registering creates:
1922
- - `Kind::Of::Queue`, `Kind::Is::Queue`
1923
-
1924
- [⬆️ &nbsp;Back to Top](#changelog-)
1925
-
1926
- 0.5.0 (2020-01-04)
1927
- ------------------
1928
-
1929
- ### Added
1930
-
1931
- * [#4](https://github.com/serradura/kind/pull/4) - Allow defining a default value when the verified object is `nil`.
1932
- ```ruby
1933
- Kind.of.Hash(nil, or: {}) # {}
1934
- ```
1935
-
1936
- [⬆️ &nbsp;Back to Top](#changelog-)
1937
-
1938
- 0.4.0 (2020-01-03)
1939
- ------------------
1940
-
1941
- ### Added
1942
-
1943
- * [#3](https://github.com/serradura/kind/pull/3) - Require `2.2.0` as the minimum Ruby version.
1944
-
1945
- [⬆️ &nbsp;Back to Top](#changelog-)
1946
-
1947
- 0.3.0 (2020-01-03)
1948
- ------------------
1949
-
1950
- ### Added
1951
-
1952
- * [#2](https://github.com/serradura/kind/pull/2) - Add `Kind::Checker` to create an object which knows how to do a type checking. (PR: #2)
1953
- ```ruby
1954
- class User
1955
- end
1956
-
1957
- user = User.new
1958
-
1959
- UserKind = Kind::Checker.new(User)
1960
-
1961
- UserKind.class?(User) # true
1962
- UserKind.class?(String) # false
1963
-
1964
- UserKind.instance?(user) # true
1965
- UserKind.instance?(1) # false
1966
-
1967
- UserKind.or_nil(user) # #<User:0x0000...>
1968
- UserKind.or_nil(1) # nil
1969
- ```
1970
-
1971
- ### Breaking Changes
1972
-
1973
- * [#2](https://github.com/serradura/kind/pull/2) - Replace `instance_eval` in modules by singleton objects to define the type checkers (via `Kind::Types.add()`). The behavior still the same, but the constants become a `Kind::Checker` object instead of a module.
1974
-
1975
- [⬆️ &nbsp;Back to Top](#changelog-)
1976
-
1977
- 0.2.0 (2020-01-02)
1978
- ------------------
1979
-
1980
- ### Added
1981
-
1982
- * [#1](https://github.com/serradura/kind/pull/1) - Register type checkers for several Ruby classes/modules. (PR: #1)
1983
- - **Classes:**
1984
- - `Kind::Of::Symbol` , `Kind::Is::Symbol`
1985
- - `Kind::Of::Numeric` , `Kind::Is::Numeric`
1986
- - `Kind::Of::Integer` , `Kind::Is::Integer`
1987
- - `Kind::Of::Float` , `Kind::Is::Float`
1988
- - `Kind::Of::Regexp` , `Kind::Is::Regexp`
1989
- - `Kind::Of::Time` , `Kind::Is::Time`
1990
- - `Kind::Of::Array` , `Kind::Is::Array`
1991
- - `Kind::Of::Range` , `Kind::Is::Range`
1992
- - `Kind::Of::Hash` , `Kind::Is::Hash`
1993
- - `Kind::Of::Struct` , `Kind::Is::Struct`
1994
- - `Kind::Of::Enumerator`, `Kind::Is::Enumerator`
1995
- - `Kind::Of::Method` , `Kind::Is::Method`
1996
- - `Kind::Of::Proc` , `Kind::Is::Proc`
1997
- - `Kind::Of::IO` , `Kind::Is::IO`
1998
- - `Kind::Of::File` , `Kind::Is::File`
1999
- - **Modules:**
2000
- - `Kind::Of::Enumerable`, `Kind::Is::Enumerable`
2001
- - `Kind::Of::Comparable`, `Kind::Is::Comparable`
2002
-
2003
- * [#1](https://github.com/serradura/kind/pull/1) - Create special type checkers.
2004
- - `Kind::Of::Boolean` for check if the given object is `true` or `false`.
2005
- - `Kind::Of::Lambda` for check if the given object is a `lambda`.
2006
- - `Kind::Of::Module` for check if the given object is a *module*.
2007
-
2008
- [⬆️ &nbsp;Back to Top](#changelog-)
2009
-
2010
- 0.1.0 (2019-12-26)
2011
- ------------------
2012
-
2013
- ### Added
2014
-
2015
- * Require `2.3.0` as the minimum Ruby version.
2016
-
2017
- * `Kind::Error` for defining type checkers errors.
2018
-
2019
- * `Kind::Of.call()` for check if the given *class* is the *class/superclass* of object, or if the given *module* is included in the object. `Kind::Error` will be raised, If the object hasn't the expected kind.
2020
- ```ruby
2021
- Kind::Of.(String, '') # ''
2022
- Kind::Of.(String, 1) # Kind::Error (1 expected to be a kind of String)
2023
- ```
2024
-
2025
- * `Kind::Of::Class()` for check if the given object is a *class*.
2026
-
2027
- * `Kind::Is.call()` for check if the first kind is equal or a parent class/module of the second one.
2028
- ```ruby
2029
- Kind::Is.(String, String) # true
2030
- Kind::Is.(Symbol, String) # false
2031
- ```
2032
-
2033
- * `Kind.of` is a shortcut for `Kind::Of`.
2034
-
2035
- * `Kind.is` is a shortcut for `Kind::Is`.
2036
-
2037
- * `Kind::Types.add` allows the registering of new type checkers.
2038
- ```ruby
2039
- # Registering Symbol
2040
-
2041
- Kind::Type.add(Symbol)
2042
-
2043
- # Adds a method in the Kind::Is module
2044
-
2045
- class MySymbol < Symbol
2046
- end
2047
-
2048
- Kind.is.Symbol(Symbol) # true
2049
- Kind.is.Symbol(MySymbol) # true
2050
- Kind.is.Symbol(String) # false
2051
-
2052
- # Adds a method in the Kind::Of module
2053
-
2054
- Kind.of.Symbol(:a) # :a
2055
- Kind.of.Symbol(1) # Kind::Error (1 expected to be a kind of Symbol)
2056
-
2057
- # Creates a module in Kind::Of with type checking methods related to the given kind.
2058
-
2059
- Kind::Of::Symbol.class?(Symbol) # true
2060
- Kind::Of::Symbol.instance?(:a) # true
2061
- Kind::Of::Symbol.or_nil(:b) # :b
2062
- Kind::Of::Symbol.or_nil(1) # nil
2063
- ```
2064
-
2065
- * Register the `String` and `Hash` type checkers. This registering creates:
2066
- - `Kind::Of::Hash`, `Kind::Is::Hash`
2067
- - `Kind::Of::String`, `Kind::Is::String`
2068
-
2069
- [⬆️ &nbsp;Back to Top](#changelog-)
400
+ - [#14](https://github.com/serradura/kind/pull/14) - Raise `Kind::Error` if `nil` is the argument of any strict type checker.
401
+
402
+ ## [1.0.0] - 2020-03-16
403
+ ### Added
404
+ - [#12](https://github.com/serradura/kind/pull/12) - Register type checkers respecting their namespaces, so nested classes like `Account::User::Membership` get the full `Kind.of.Account::User::Membership` API (`[]`, `instance?`, `class?`, `or_nil`, …).
405
+
406
+ ## [0.6.0] - 2020-01-06
407
+ ### Added
408
+ - [#11](https://github.com/serradura/kind/pull/11) - Register the `Queue` (`Thread::Queue`) type checker: `Kind::Of::Queue`, `Kind::Is::Queue`.
409
+
410
+ ## [0.5.0] - 2020-01-04
411
+ ### Added
412
+ - [#4](https://github.com/serradura/kind/pull/4) - Allow defining a default value when the verified object is `nil`: `Kind.of.Hash(nil, or: {})`.
413
+
414
+ ## [0.4.0] - 2020-01-03
415
+ ### Changed
416
+ - [#3](https://github.com/serradura/kind/pull/3) - Require Ruby `>= 2.2.0` as the minimum supported version.
417
+
418
+ ## [0.3.0] - 2020-01-03
419
+ ### Added
420
+ - [#2](https://github.com/serradura/kind/pull/2) - Add `Kind::Checker.new(<Type>)` for building reusable type-checker objects with `class?`, `instance?`, `or_nil`, …
421
+
422
+ ### Changed
423
+ - [#2](https://github.com/serradura/kind/pull/2) - **BREAKING:** Replace `instance_eval`-on-modules with singleton objects when defining type checkers via `Kind::Types.add()`. The behavior is unchanged, but `Kind::Of::<Type>` constants are now `Kind::Checker` objects instead of modules.
424
+
425
+ ## [0.2.0] - 2020-01-02
426
+ ### Added
427
+ - [#1](https://github.com/serradura/kind/pull/1) - Register type checkers for Ruby core classes (`Symbol`, `Numeric`, `Integer`, `Float`, `Regexp`, `Time`, `Array`, `Range`, `Hash`, `Struct`, `Enumerator`, `Method`, `Proc`, `IO`, `File`) and modules (`Enumerable`, `Comparable`).
428
+ - [#1](https://github.com/serradura/kind/pull/1) - Add the special type checkers `Kind::Of::Boolean` (`true`/`false`), `Kind::Of::Lambda`, and `Kind::Of::Module`.
429
+
430
+ ## [0.1.0] - 2019-12-26
431
+ ### Added
432
+ - Require Ruby `>= 2.3.0` as the minimum supported version.
433
+ - `Kind::Error` for type-checker errors.
434
+ - `Kind::Of.call(<Type>, value)` — returns the value if it is a kind of `<Type>`, raises `Kind::Error` otherwise. `Kind::Of::Class()` checks the given object is a class.
435
+ - `Kind::Is.call(<Type>, other)` — checks the first kind is equal to or a parent of the second.
436
+ - Shortcuts `Kind.of` (→ `Kind::Of`) and `Kind.is` (→ `Kind::Is`).
437
+ - `Kind::Types.add(<Type>)` for registering new type checkers. Registration adds `Kind.of.<Type>(value)` / `Kind.is.<Type>(other)` methods and a `Kind::Of::<Type>` module exposing `class?`, `instance?`, `or_nil`.
438
+ - Register the `String` and `Hash` type checkers: `Kind::Of::Hash` / `Kind::Is::Hash`, `Kind::Of::String` / `Kind::Is::String`.
439
+
440
+ [6.0.1]: https://github.com/serradura/kind/compare/v6.0.0...v6.0.1
441
+ [6.0.0]: https://github.com/serradura/kind/compare/v5.10.0...v6.0.0
442
+ [5.10.0]: https://github.com/serradura/kind/compare/v5.9.0...v5.10.0
443
+ [5.9.0]: https://github.com/serradura/kind/compare/v5.8.1...v5.9.0
444
+ [5.8.1]: https://github.com/serradura/kind/compare/v5.8.0...v5.8.1
445
+ [5.8.0]: https://github.com/serradura/kind/compare/v5.7.0...v5.8.0
446
+ [5.7.0]: https://github.com/serradura/kind/compare/v5.6.0...v5.7.0
447
+ [5.6.0]: https://github.com/serradura/kind/compare/v5.5.0...v5.6.0
448
+ [5.5.0]: https://github.com/serradura/kind/compare/v5.4.1...v5.5.0
449
+ [5.4.1]: https://github.com/serradura/kind/compare/v5.4.0...v5.4.1
450
+ [5.4.0]: https://github.com/serradura/kind/compare/v5.3.0...v5.4.0
451
+ [5.3.0]: https://github.com/serradura/kind/compare/v5.2.0...v5.3.0
452
+ [5.2.0]: https://github.com/serradura/kind/compare/v5.1.0...v5.2.0
453
+ [5.1.0]: https://github.com/serradura/kind/compare/v5.0.0...v5.1.0
454
+ [5.0.0]: https://github.com/serradura/kind/compare/v4.1.0...v5.0.0
455
+ [4.1.0]: https://github.com/serradura/kind/compare/v4.0.0...v4.1.0
456
+ [4.0.0]: https://github.com/serradura/kind/compare/v3.1.0...v4.0.0
457
+ [3.1.0]: https://github.com/serradura/kind/compare/v3.0.1...v3.1.0
458
+ [3.0.1]: https://github.com/serradura/kind/compare/v3.0.0...v3.0.1
459
+ [3.0.0]: https://github.com/serradura/kind/compare/v2.3.0...v3.0.0
460
+ [2.3.0]: https://github.com/serradura/kind/compare/v2.2.0...v2.3.0
461
+ [2.2.0]: https://github.com/serradura/kind/compare/v2.1.0...v2.2.0
462
+ [2.1.0]: https://github.com/serradura/kind/compare/v2.0.0...v2.1.0
463
+ [2.0.0]: https://github.com/serradura/kind/compare/v1.9.0...v2.0.0
464
+ [1.9.0]: https://github.com/serradura/kind/compare/v1.8.0...v1.9.0
465
+ [1.8.0]: https://github.com/serradura/kind/compare/v1.7.0...v1.8.0
466
+ [1.7.0]: https://github.com/serradura/kind/compare/v1.6.0...v1.7.0
467
+ [1.6.0]: https://github.com/serradura/kind/compare/v1.5.0...v1.6.0
468
+ [1.5.0]: https://github.com/serradura/kind/compare/v1.4.0...v1.5.0
469
+ [1.4.0]: https://github.com/serradura/kind/compare/v1.3.0...v1.4.0
470
+ [1.3.0]: https://github.com/serradura/kind/compare/v1.2.0...v1.3.0
471
+ [1.2.0]: https://github.com/serradura/kind/compare/v1.1.0...v1.2.0
472
+ [1.1.0]: https://github.com/serradura/kind/compare/v1.0.0...v1.1.0
473
+ [1.0.0]: https://github.com/serradura/kind/compare/v0.6.0...v1.0.0
474
+ [0.6.0]: https://github.com/serradura/kind/compare/v0.5.0...v0.6.0
475
+ [0.5.0]: https://github.com/serradura/kind/compare/v0.4.0...v0.5.0
476
+ [0.4.0]: https://github.com/serradura/kind/compare/v0.3.0...v0.4.0
477
+ [0.3.0]: https://github.com/serradura/kind/compare/v0.2.0...v0.3.0
478
+ [0.2.0]: https://github.com/serradura/kind/compare/v0.1.0...v0.2.0
479
+ [0.1.0]: https://github.com/serradura/kind/releases/tag/v0.1.0