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