kind 4.0.0 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 62e657cbbdd2af4aebab8cde9f010744a0321c7fceff24f3574a2f9ac4c2a9ad
4
- data.tar.gz: c0f5690cef9d736b703ac2f1f75c23b30fccc309ad58c18972060074c8946d3b
3
+ metadata.gz: ffb9807682a295f94cb8e4076d32fc3217da97268e943e7d6b028b6de95ed765
4
+ data.tar.gz: 7b61164996c0d96853ad5a0cde9269ecd18bb489b483b46956a7fa2e9b9f2cd6
5
5
  SHA512:
6
- metadata.gz: 15281701426737bbf5c5cd4fa669ecb7c245fb520c1feb79d344d271f6552388111f75245babeffd4eadb3cd98120a3041a4d65959c78f0983ad167ce7060104
7
- data.tar.gz: 6bd17ee29bcbf1bda1273eebf7ef2999a74a0e55935622330b19a07efac4f0e448436eb26115042e828c1e7ed9e00c1435207ddbcb84bbd11dcb15a1371a2a3a
6
+ metadata.gz: 0f23b38b9f63d03638ded172c037b6ba9e048c397e9a31907850beca5151822c4983129e5726b777ccbdb30db18c8bcdfb9392c813c3e05546dfd33f97db9660
7
+ data.tar.gz: 3d7e663d65a591bff7bfeb152dd4e605948df7e95de15bb3632be0f52c747fd522041fc1be7678c8385cd9c0606a688abd203348e376ce264f3088d62ecb5f88
data/CHANGELOG.md CHANGED
@@ -3,61 +3,63 @@
3
3
  This project follows [semver 2.0.0](http://semver.org/spec/v2.0.0.html) and the recommendations of [keepachangelog.com](http://keepachangelog.com/).
4
4
 
5
5
  - [Unreleased](#unreleased)
6
- - [4.0.0 (2021-02-22)](#400-2021-02-22)
6
+ - [4.1.0 (2021-02-22)](#410-2021-02-22)
7
7
  - [Added](#added)
8
+ - [4.0.0 (2021-02-22)](#400-2021-02-22)
9
+ - [Added](#added-1)
8
10
  - [Deprecated](#deprecated)
9
11
  - [Fixed](#fixed)
10
12
  - [3.1.0 (2020-07-08)](#310-2020-07-08)
11
- - [Added](#added-1)
13
+ - [Added](#added-2)
12
14
  - [3.0.0 (2020-06-25)](#300-2020-06-25)
13
15
  - [Breaking Changes](#breaking-changes)
14
- - [Added](#added-2)
15
- - [2.3.0 (2020-06-24)](#230-2020-06-24)
16
16
  - [Added](#added-3)
17
- - [2.2.0 (2020-06-23)](#220-2020-06-23)
17
+ - [2.3.0 (2020-06-24)](#230-2020-06-24)
18
18
  - [Added](#added-4)
19
- - [2.1.0 (2020-05-12)](#210-2020-05-12)
19
+ - [2.2.0 (2020-06-23)](#220-2020-06-23)
20
20
  - [Added](#added-5)
21
+ - [2.1.0 (2020-05-12)](#210-2020-05-12)
22
+ - [Added](#added-6)
21
23
  - [Breaking Changes](#breaking-changes-1)
22
24
  - [2.0.0 (2020-05-07)](#200-2020-05-07)
23
- - [Added](#added-6)
25
+ - [Added](#added-7)
24
26
  - [Breaking Changes](#breaking-changes-2)
25
27
  - [Removed](#removed)
26
28
  - [1.9.0 (2020-05-06)](#190-2020-05-06)
27
- - [Added](#added-7)
28
- - [1.8.0 (2020-05-03)](#180-2020-05-03)
29
29
  - [Added](#added-8)
30
+ - [1.8.0 (2020-05-03)](#180-2020-05-03)
31
+ - [Added](#added-9)
30
32
  - [1.7.0 (2020-05-03)](#170-2020-05-03)
31
33
  - [Fixed](#fixed-1)
32
34
  - [1.6.0 (2020-04-17)](#160-2020-04-17)
33
- - [Added](#added-9)
35
+ - [Added](#added-10)
34
36
  - [Changes](#changes)
35
37
  - [1.5.0 (2020-04-12)](#150-2020-04-12)
36
- - [Added](#added-10)
37
- - [1.4.0 (2020-04-12)](#140-2020-04-12)
38
38
  - [Added](#added-11)
39
- - [1.3.0 (2020-04-12)](#130-2020-04-12)
39
+ - [1.4.0 (2020-04-12)](#140-2020-04-12)
40
40
  - [Added](#added-12)
41
- - [1.2.0 (2020-04-12)](#120-2020-04-12)
41
+ - [1.3.0 (2020-04-12)](#130-2020-04-12)
42
42
  - [Added](#added-13)
43
- - [1.1.0 (2020-04-09)](#110-2020-04-09)
43
+ - [1.2.0 (2020-04-12)](#120-2020-04-12)
44
44
  - [Added](#added-14)
45
+ - [1.1.0 (2020-04-09)](#110-2020-04-09)
46
+ - [Added](#added-15)
45
47
  - [Fixed](#fixed-2)
46
48
  - [1.0.0 (2020-03-16)](#100-2020-03-16)
47
- - [Added](#added-15)
48
- - [0.6.0 (2020-01-06)](#060-2020-01-06)
49
49
  - [Added](#added-16)
50
- - [0.5.0 (2020-01-04)](#050-2020-01-04)
50
+ - [0.6.0 (2020-01-06)](#060-2020-01-06)
51
51
  - [Added](#added-17)
52
- - [0.4.0 (2020-01-03)](#040-2020-01-03)
52
+ - [0.5.0 (2020-01-04)](#050-2020-01-04)
53
53
  - [Added](#added-18)
54
- - [0.3.0 (2020-01-03)](#030-2020-01-03)
54
+ - [0.4.0 (2020-01-03)](#040-2020-01-03)
55
55
  - [Added](#added-19)
56
+ - [0.3.0 (2020-01-03)](#030-2020-01-03)
57
+ - [Added](#added-20)
56
58
  - [Breaking Changes](#breaking-changes-3)
57
59
  - [0.2.0 (2020-01-02)](#020-2020-01-02)
58
- - [Added](#added-20)
59
- - [0.1.0 (2019-12-26)](#010-2019-12-26)
60
60
  - [Added](#added-21)
61
+ - [0.1.0 (2019-12-26)](#010-2019-12-26)
62
+ - [Added](#added-22)
61
63
 
62
64
  ## Unreleased
63
65
 
@@ -69,6 +71,41 @@ This project follows [semver 2.0.0](http://semver.org/spec/v2.0.0.html) and the
69
71
  ### Fixed
70
72
  -->
71
73
 
74
+ 4.1.0 (2021-02-22)
75
+ ------------------
76
+
77
+ ### Added
78
+
79
+ * [#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.
80
+ ```ruby
81
+ Kind::Maybe(Kind::Boolean).wrap(nil).value_or(false) # false
82
+
83
+ Kind::Maybe(Kind::Boolean).wrap(true).value_or(false) # true
84
+ ```
85
+
86
+ * [#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.
87
+ ```ruby
88
+ Kind::Integer.maybe #<Kind::Maybe::Typed:0x0000... @kind=Kind::Integer>
89
+
90
+ Kind::Integer.maybe(0).some? # true
91
+ Kind::Integer.maybe { 1 }.some? # true
92
+ Kind::Integer.maybe(2) { |n| n * 2 }.some? # true
93
+
94
+ Kind::Integer.maybe { 2 / 0 }.none? # true
95
+ Kind::Integer.maybe(2) { |n| n / 0 }.none? # true
96
+ Kind::Integer.maybe('2') { |n| n * n }.none? # true
97
+ ```
98
+
99
+ * [#43](https://github.com/serradura/kind/pull/43) - Make the `:respond_to` kind validation verify by one or multiple methods. e.g.
100
+ ```ruby
101
+ validates :params, kind: { respond_to: [:[], :values_at] }
102
+ ```
103
+
104
+ * [#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.
105
+ ```ruby
106
+ validates :alive, kind: Kind::Boolean
107
+ ```
108
+
72
109
  4.0.0 (2021-02-22)
73
110
  ------------------
74
111
 
data/README.md CHANGED
@@ -35,7 +35,7 @@ One of the goals of this project is to do simple type checking like `"some strin
35
35
  Version | Documentation
36
36
  ---------- | -------------
37
37
  unreleased | https://github.com/serradura/u-case/blob/main/README.md
38
- 4.0.0 | https://github.com/serradura/u-case/blob/v4.x/README.md
38
+ 4.1.0 | https://github.com/serradura/u-case/blob/v4.x/README.md
39
39
  3.1.0 | https://github.com/serradura/u-case/blob/v3.x/README.md
40
40
  2.3.0 | https://github.com/serradura/u-case/blob/v2.x/README.md
41
41
  1.9.0 | https://github.com/serradura/u-case/blob/v1.x/README.md
@@ -51,9 +51,10 @@ unreleased | https://github.com/serradura/u-case/blob/main/README.md
51
51
  - [Kind::\<Type\>.or_undefined()](#kindtypeor_undefined)
52
52
  - [Kind::\<Type\>.or()](#kindtypeor)
53
53
  - [Kind::\<Type\>.value()](#kindtypevalue-1)
54
+ - [Kind::\<Type\>.maybe](#kindtypemaybe)
54
55
  - [Kind::\<Type\>?](#kindtype-2)
55
56
  - [Kind::{Array,Hash,String,Set}.value_or_empty()](#kindarrayhashstringsetvalue_or_empty)
56
- - [List of all type checkers (Kind::<Type>)](#list-of-all-type-checkers-kindtype)
57
+ - [List of all type checkers](#list-of-all-type-checkers)
57
58
  - [Core](#core)
58
59
  - [Stdlib](#stdlib)
59
60
  - [Custom](#custom)
@@ -92,11 +93,18 @@ unreleased | https://github.com/serradura/u-case/blob/main/README.md
92
93
  - [Kind::Maybe#try!](#kindmaybetry-1)
93
94
  - [Kind::Maybe#dig](#kindmaybedig)
94
95
  - [Kind::Maybe#check](#kindmaybecheck)
96
+ - [Kind::Maybe#presence](#kindmaybepresence)
95
97
  - [Kind::Empty](#kindempty)
96
98
  - [Kind::Validator (ActiveModel::Validations)](#kindvalidator-activemodelvalidations)
97
99
  - [Usage](#usage-1)
98
- - [Defining the default validation strategy](#defining-the-default-validation-strategy)
99
- - [Using the `allow_nil` and `strict` options](#using-the-allow_nil-and-strict-options)
100
+ - [Object#===](#object)
101
+ - [Kind.is](#kindis-1)
102
+ - [Object#instance_of?](#objectinstance_of)
103
+ - [Object#respond_to?](#objectrespond_to)
104
+ - [Array.new.all? { |item| item.kind_of?(Class) }](#arraynewall--item-itemkind_ofclass-)
105
+ - [Array.new.all? { |item| expected_values.include?(item) }](#arraynewall--item-expected_valuesincludeitem-)
106
+ - [Defining the default validation strategy](#defining-the-default-validation-strategy)
107
+ - [Using the `allow_nil` and `strict` options](#using-the-allow_nil-and-strict-options)
100
108
  - [Similar Projects](#similar-projects)
101
109
  - [Development](#development)
102
110
  - [Contributing](#contributing)
@@ -108,7 +116,7 @@ unreleased | https://github.com/serradura/u-case/blob/main/README.md
108
116
  | u-case | branch | ruby | activemodel |
109
117
  | -------------- | ------- | -------- | -------------- |
110
118
  | unreleased | main | >= 2.2.0 | >= 3.2, <= 6.1 |
111
- | 4.0.0 | v4.x | >= 2.2.0 | >= 3.2, <= 6.1 |
119
+ | 4.1.0 | v4.x | >= 2.2.0 | >= 3.2, <= 6.1 |
112
120
  | 3.1.0 | v3.x | >= 2.2.0 | >= 3.2, <= 6.1 |
113
121
  | 2.3.0 | v2.x | >= 2.2.0 | >= 3.2, <= 6.0 |
114
122
  | 1.9.0 | v1.x | >= 2.2.0 | >= 3.2, <= 6.0 |
@@ -257,6 +265,39 @@ Kind::String.value('1', default: 1) # Kind::Error (1 expected to be a kind of S
257
265
 
258
266
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
259
267
 
268
+ ### Kind::\<Type\>.maybe
269
+
270
+ This method exposes a [typed `Kind::Maybe`](#kindmaybetype) and using it will be possible to apply a sequence of operations in the case of the wrapped value has the expected kind.
271
+
272
+ ```ruby
273
+ Double = ->(value) do
274
+ Kind::Numeric.maybe(value)
275
+ .then { |number| number * 2 }
276
+ .value_or(0)
277
+ end
278
+
279
+ Double.('2') # 0
280
+ Double.(2) # 4
281
+ ```
282
+
283
+ If it is invoked without arguments, it returns the typed Maybe. But, if it receives arguments, it will behave like the `Kind::Maybe.wrap` method. e.g.
284
+
285
+ ```ruby
286
+ Kind::Integer.maybe #<Kind::Maybe::Typed:0x0000... @kind=Kind::Integer>
287
+
288
+ Kind::Integer.maybe(0).some? # true
289
+ Kind::Integer.maybe { 1 }.some? # true
290
+ Kind::Integer.maybe(2) { |n| n * 2 }.some? # true
291
+
292
+ Kind::Integer.maybe { 2 / 0 }.none? # true
293
+ Kind::Integer.maybe(2) { |n| n / 0 }.none? # true
294
+ Kind::Integer.maybe('2') { |n| n * n }.none? # true
295
+ ```
296
+
297
+ > **Note:** You can use `Kind::\<Type\>.optional` as an alias for `Kind::\<Type\>.maybe`.
298
+
299
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
300
+
260
301
  ### Kind::\<Type\>?
261
302
 
262
303
  There is a second way to do a type verification and know if one or multiple values has the expected type. You can use the predicate kind methods (`Kind::Hash?`). e.g:
@@ -289,7 +330,7 @@ Kind::Array.value_or_empty({}).frozen? # true
289
330
 
290
331
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
291
332
 
292
- ### List of all type checkers (Kind::<Type>)
333
+ ### List of all type checkers
293
334
 
294
335
  #### Core
295
336
 
@@ -396,6 +437,10 @@ kind_of_user.value(User.new, default: User.new) # #<User:0x0000...>
396
437
  kind_of_user.value('1', default: User.new) # #<User:0x0000...>
397
438
 
398
439
  kind_of_user.value('1', default: 1) # Kind::Error (1 expected to be a kind of User)
440
+
441
+ # kind_of_user.maybe
442
+ # This method returns a typed Kind::Maybe.
443
+ kind_of_user.maybe('1').value_or(User.new) # #<User:0x0000...>
399
444
  ```
400
445
 
401
446
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
@@ -463,6 +508,12 @@ PositiveInteger.value(2, default: 1) # 2
463
508
  PositiveInteger.value('1', default: 1) # 1
464
509
 
465
510
  PositiveInteger.value('1', default: 0) # Kind::Error (0 expected to be a kind of PositiveInteger)
511
+
512
+ # PositiveInteger.maybe
513
+ # This method returns a typed Kind::Maybe.
514
+ PositiveInteger.maybe(0).value_or(1) # 1
515
+
516
+ PositiveInteger.maybe(2).value_or(1) # 2
466
517
  ```
467
518
 
468
519
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
@@ -1099,7 +1150,7 @@ def person_name(params)
1099
1150
 
1100
1151
  return default if names.size != 2
1101
1152
 
1102
- first_name, last_name = default
1153
+ first_name, last_name = names
1103
1154
 
1104
1155
  "#{first_name} #{last_name}"
1105
1156
  end
@@ -1126,7 +1177,7 @@ module PersonIntroduction1
1126
1177
  end
1127
1178
 
1128
1179
  def age(optional)
1129
- optional.map { |hash| hash[:age] }.value_or(0)
1180
+ optional.dig(:age).value_or(0)
1130
1181
  end
1131
1182
  end
1132
1183
 
@@ -1336,6 +1387,18 @@ Kind::Maybe(Array)
1336
1387
 
1337
1388
  [⬆️ &nbsp;Back to Top](#table-of-contents-)
1338
1389
 
1390
+ ### Kind::Maybe#presence
1391
+
1392
+ This method will return None if the wrapped value wasn't present.
1393
+
1394
+ ```ruby
1395
+ result = Kind::Maybe(Hash).wrap(foo: '').dig(:foo).presence
1396
+ result.none? # true
1397
+ result.value # nil
1398
+ ```
1399
+
1400
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1401
+
1339
1402
  ## Kind::Empty
1340
1403
 
1341
1404
  When you define a method that has default arguments, for certain data types, you will always create a new object in memory. e.g:
@@ -1407,20 +1470,31 @@ gem 'kind', require: 'kind/active_model/validation'
1407
1470
  require 'kind/active_model/validation'
1408
1471
  ```
1409
1472
 
1473
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1474
+
1410
1475
  ### Usage
1411
1476
 
1412
- **[Object#kind_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-kind_of-3F)**
1477
+ #### [Object#===](https://ruby-doc.org/core-3.0.0/Object.html#method-i-3D-3D-3D)
1413
1478
 
1414
1479
  ```ruby
1415
1480
  validates :name, kind: { of: String }
1481
+ ```
1416
1482
 
1417
- # Use an array to verify if the attribute
1418
- # is an instance of one of the classes/modules.
1483
+ Use an array to verify if the attribute is an instance of one of the classes/modules.
1419
1484
 
1485
+ ```ruby
1420
1486
  validates :status, kind: { of: [String, Symbol]}
1421
1487
  ```
1422
1488
 
1423
- **[Kind.is](#verifying-the-kind-of-some-classmodule)**
1489
+ Because of kind verification be made via `===` you can use type checkers as the expected kinds.
1490
+
1491
+ ```ruby
1492
+ validates :alive, kind: Kind::Boolean
1493
+ ```
1494
+
1495
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1496
+
1497
+ #### [Kind.is](#verifying-the-kind-of-some-classmodule)
1424
1498
 
1425
1499
  ```ruby
1426
1500
  #
@@ -1456,7 +1530,9 @@ validates :human_kind, kind: { is: Human }
1456
1530
  validates :human_kind, kind: { is: [Person, User] }
1457
1531
  ```
1458
1532
 
1459
- **[Object#instance_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-instance_of-3F)**
1533
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1534
+
1535
+ #### [Object#instance_of?](https://ruby-doc.org/core-3.0.0/Object.html#method-i-instance_of-3F)
1460
1536
 
1461
1537
  ```ruby
1462
1538
  validates :name, kind: { instance_of: String }
@@ -1467,13 +1543,23 @@ validates :name, kind: { instance_of: String }
1467
1543
  validates :name, kind: { instance_of: [String, Symbol] }
1468
1544
  ```
1469
1545
 
1470
- **[Object#respond_to?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-respond_to-3F)**
1546
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1547
+
1548
+ #### [Object#respond_to?](https://ruby-doc.org/core-3.0.0/Object.html#method-i-respond_to-3F)
1471
1549
 
1472
1550
  ```ruby
1473
1551
  validates :handler, kind: { respond_to: :call }
1474
1552
  ```
1475
1553
 
1476
- **Array.new.all? { |item| item.kind_of?(Class) }**
1554
+ This validation can verify one or multiple methods.
1555
+
1556
+ ```ruby
1557
+ validates :params, kind: { respond_to: [:[], :values_at] }
1558
+ ```
1559
+
1560
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1561
+
1562
+ #### Array.new.all? { |item| item.kind_of?(Class) }
1477
1563
 
1478
1564
  ```ruby
1479
1565
  validates :account_types, kind: { array_of: String }
@@ -1484,7 +1570,9 @@ validates :account_types, kind: { array_of: String }
1484
1570
  validates :account_types, kind: { array_of: [String, Symbol] }
1485
1571
  ```
1486
1572
 
1487
- **Array.new.all? { |item| expected_values.include?(item) }**
1573
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1574
+
1575
+ #### Array.new.all? { |item| expected_values.include?(item) }
1488
1576
 
1489
1577
  ```ruby
1490
1578
  # Verifies if the attribute value
@@ -1493,7 +1581,9 @@ validates :account_types, kind: { array_of: [String, Symbol] }
1493
1581
  validates :account_types, kind: { array_with: ['foo', 'bar'] }
1494
1582
  ```
1495
1583
 
1496
- #### Defining the default validation strategy
1584
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1585
+
1586
+ ### Defining the default validation strategy
1497
1587
 
1498
1588
  By default, you can define the attribute type directly (without a hash). e.g.
1499
1589
 
@@ -1515,7 +1605,9 @@ And these are the available options to define the default strategy:
1515
1605
  - `kind_of` *(default)*
1516
1606
  - `instance_of`
1517
1607
 
1518
- #### Using the `allow_nil` and `strict` options
1608
+ [⬆️ &nbsp;Back to Top](#table-of-contents-)
1609
+
1610
+ ### Using the `allow_nil` and `strict` options
1519
1611
 
1520
1612
  You can use the `allow_nil` option with any of the kind validations. e.g.
1521
1613
 
data/lib/kind.rb CHANGED
@@ -12,10 +12,10 @@ require 'kind/dig'
12
12
  require 'kind/try'
13
13
  require 'kind/presence'
14
14
  require 'kind/undefined'
15
- require 'kind/type_checker'
15
+ require 'kind/maybe'
16
16
 
17
+ require 'kind/type_checker'
17
18
  require 'kind/type_checkers'
18
- require 'kind/maybe'
19
19
 
20
20
  require 'kind/deprecations/checker'
21
21
  require 'kind/deprecations/of'
@@ -59,7 +59,7 @@ module Kind
59
59
 
60
60
  return is?(expected, object) if UNDEFINED != object
61
61
 
62
- raise ArgumentError, 'wrong number of arguments (given 1, expected 2)'
62
+ WRONG_NUMBER_OF_ARGS.error!(given: 1, expected: 2)
63
63
  end
64
64
 
65
65
  def self.of(kind = UNDEFINED, object = UNDEFINED)
@@ -35,9 +35,9 @@ class KindValidator < ActiveModel::EachValidator
35
35
  def kind_of(expected, value)
36
36
  types = Array(expected)
37
37
 
38
- return if types.any? { |type| value.kind_of?(type) }
38
+ return if types.any? { |type| type === value }
39
39
 
40
- "must be a kind of: #{types.map { |klass| klass.name }.join(', ')}"
40
+ "must be a kind of: #{types.map { |type| type.name }.join(', ')}"
41
41
  end
42
42
 
43
43
  CLASS_OR_MODULE = 'Class/Module'.freeze
@@ -45,7 +45,7 @@ class KindValidator < ActiveModel::EachValidator
45
45
  def kind_is(expected, value)
46
46
  return kind_is_not(expected, value) unless expected.kind_of?(::Array)
47
47
 
48
- result = expected.map { |kind| kind_is_not(kind, value) }.compact
48
+ result = expected.map { |kind| kind_is_not(kind, value) }.tap(&:compact!)
49
49
 
50
50
  result.empty? || result.size < expected.size ? nil : result.join(', ')
51
51
  end
@@ -66,10 +66,17 @@ class KindValidator < ActiveModel::EachValidator
66
66
  end
67
67
  end
68
68
 
69
- def respond_to(method_name, value)
70
- return if value.respond_to?(method_name)
69
+ def respond_to(expected, value)
70
+ method_names = Array(expected)
71
71
 
72
- "must respond to the method `#{method_name}`"
72
+ expected_methods = method_names.select { |method_name| !value.respond_to?(method_name) }
73
+ expected_methods.map! { |method_name| "`#{method_name}`" }
74
+
75
+ return if expected_methods.empty?
76
+
77
+ methods = expected_methods.size == 1 ? 'method' : 'methods'
78
+
79
+ "must respond to the #{methods}: #{expected_methods.join(', ')}"
73
80
  end
74
81
 
75
82
  def instance_of(expected, value)
data/lib/kind/core.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Kind
4
4
  module Core
5
+ require 'kind/core/wrong_number_of_args'
5
6
  require 'kind/core/deprecation'
6
7
  require 'kind/core/kind'
7
8
  require 'kind/core/undefined'
@@ -27,7 +27,7 @@ module Kind
27
27
  end
28
28
 
29
29
  def self.of_module?(value) # :nodoc:
30
- ::Module == value || (value.is_a?(::Module) && !of_class?(value))
30
+ ::Module == value || (value.kind_of?(::Module) && !of_class?(value))
31
31
  end
32
32
 
33
33
  def self.of_module_or_class!(value) # :nodoc:
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module WRONG_NUMBER_OF_ARGS
5
+ def self.error!(given:, expected:)
6
+ raise ArgumentError, "wrong number of arguments (given #{given}, expected #{expected})"
7
+ end
8
+ end
9
+ end
data/lib/kind/dig.rb CHANGED
@@ -5,7 +5,7 @@ module Kind
5
5
  extend self
6
6
 
7
7
  def call(data, keys)
8
- return unless keys.is_a?(::Array)
8
+ return unless keys.kind_of?(::Array)
9
9
 
10
10
  keys.reduce(data) do |memo, key|
11
11
  value = get(memo, key)
@@ -23,7 +23,7 @@ module Kind
23
23
  alias_method :check, :map
24
24
 
25
25
  def try!(method_name = UNDEFINED, *args, &block)
26
- Kind::Symbol[method_name] if UNDEFINED != method_name
26
+ KIND.of!(::Symbol, method_name)if UNDEFINED != method_name
27
27
 
28
28
  self
29
29
  end
@@ -5,7 +5,7 @@ module Kind
5
5
  class Result
6
6
  attr_reader :value
7
7
 
8
- Value = ->(arg) { arg.kind_of?(::Kind::Maybe::Result) ? arg.value : arg } # :nodoc:
8
+ Value = ->(arg) { arg.kind_of?(Maybe::Result) ? arg.value : arg } # :nodoc:
9
9
 
10
10
  def initialize(arg)
11
11
  @value = Value.(arg)
@@ -58,7 +58,7 @@ module Kind
58
58
  private
59
59
 
60
60
  def __try_method__(method_name, args)
61
- __try_block__(Kind::Symbol[method_name].to_proc, args)
61
+ __try_block__(KIND.of!(::Symbol, method_name).to_proc, args)
62
62
  end
63
63
 
64
64
  def __try_block__(block, args)
@@ -12,7 +12,7 @@ module Kind
12
12
  def new(arg)
13
13
  value = Result::Value.(arg)
14
14
 
15
- value.kind_of?(@kind) ? Maybe.some(value) : Maybe.none
15
+ @kind === value ? Maybe.some(value) : Maybe.none
16
16
  end
17
17
 
18
18
  alias_method :[], :new
@@ -22,7 +22,7 @@ module Kind
22
22
  def __call_before_expose_the_arg_in_a_block(arg)
23
23
  value = Result::Value.(arg)
24
24
 
25
- value.kind_of?(@kind) ? value : Maybe.none
25
+ @kind === value ? value : Maybe.none
26
26
  end
27
27
  end
28
28
  end
@@ -3,8 +3,6 @@
3
3
  module Kind
4
4
  module Maybe
5
5
  module Wrappable
6
- WRONG_NUMBER_OF_ARGS = 'wrong number of arguments (given 0, expected 1)'.freeze
7
-
8
6
  def wrap(arg = UNDEFINED)
9
7
  if block_given?
10
8
  begin
@@ -12,14 +10,14 @@ module Kind
12
10
 
13
11
  input = __call_before_expose_the_arg_in_a_block(arg)
14
12
 
15
- input.kind_of?(Kind::Maybe::None) ? input : new(yield(input))
13
+ input.kind_of?(Maybe::None) ? input : new(yield(input))
16
14
  rescue StandardError => exception
17
15
  Maybe.__none__(exception)
18
16
  end
19
17
  else
20
18
  return new(arg) if UNDEFINED != arg
21
19
 
22
- raise ArgumentError, WRONG_NUMBER_OF_ARGS
20
+ WRONG_NUMBER_OF_ARGS.error!(given: 0, expected: 1)
23
21
  end
24
22
  end
25
23
 
data/lib/kind/try.rb CHANGED
@@ -11,8 +11,6 @@ module Kind
11
11
  end
12
12
 
13
13
  def self.[](*args)
14
- Array[args]
15
-
16
14
  method_name = args.shift
17
15
 
18
16
  ->(object) { call!(object, method_name, args) }
@@ -44,8 +44,22 @@ module Kind
44
44
  KIND.null?(value) ? value : self[value]
45
45
  end
46
46
 
47
+ def maybe(value = UNDEFINED, &block)
48
+ return __maybe[value] if UNDEFINED != value && !block
49
+ return __maybe.wrap(&block) if UNDEFINED == value && block
50
+ return __maybe.wrap(value, &block) if UNDEFINED != value && block
51
+
52
+ __maybe
53
+ end
54
+
55
+ alias optional maybe
56
+
47
57
  private
48
58
 
59
+ def __maybe
60
+ @__maybe ||= Maybe::Typed.new(self)
61
+ end
62
+
49
63
  def __or_func
50
64
  @__or_func ||= ->(tc, fb, value) { tc === value ? value : tc.or_null(fb) }.curry[self]
51
65
  end
data/lib/kind/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kind
4
- VERSION = '4.0.0'
4
+ VERSION = '4.1.0'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kind
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
@@ -37,6 +37,7 @@ files:
37
37
  - lib/kind/core/deprecation.rb
38
38
  - lib/kind/core/kind.rb
39
39
  - lib/kind/core/undefined.rb
40
+ - lib/kind/core/wrong_number_of_args.rb
40
41
  - lib/kind/deprecations/built_in_type_checkers.rb
41
42
  - lib/kind/deprecations/checker.rb
42
43
  - lib/kind/deprecations/checker/factory.rb