kind 2.1.0 → 3.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a83d36b4c1fe131567251f418b775a8366ecf2a7c0d31682f801866cb9d83a27
4
- data.tar.gz: b9b613500675aa1ea9e10c4b5ff83a451f289aec39896aaed025c196f0212ece
3
+ metadata.gz: 7b62da87ad8443fb4d3f1d96535bc69259addf767721db70288401d677733967
4
+ data.tar.gz: 995f0a3a34ed67a3244e181380d627e076d4576a2b6e0c7de2b34fa415c5f868
5
5
  SHA512:
6
- metadata.gz: 252e2e4f3bd9bbd09ff182579d450de170688ada607dfaa30cd70748c1ac4473381c856ba1be37f74ccd1eb05d077763cbf853ea1f356c58226408108e69f4e8
7
- data.tar.gz: f35a606761e6de74f81427a4431c711252303f78e4b0b5d11dd5e1878180112c1733fa4fef85949f3414196e387b54c672e768384f92aff9ac1c434662529834
6
+ metadata.gz: 3398bbf2b67fe8b81023d9c781b14ac115f5749f45641a74fc1ff1c8d05f4fd1c4e2a4bc817d6c71e7f8dc96b245ec9f9c80a776ae11d22ba69dbc878dfaa847
7
+ data.tar.gz: 75c6c1e387548447edf601d4b73b18ff3e2700debf3f6715b2f772f582829d39a72e7bb9d8af61fe8bcd32e9f72aa8398f1703f2c706668a0ab5e59fc0612b05
@@ -3,7 +3,10 @@ language: ruby
3
3
 
4
4
  sudo: false
5
5
 
6
- cache: bundler
6
+ cache:
7
+ bundler: true
8
+ directories:
9
+ - /home/travis/.rvm/
7
10
 
8
11
  rvm:
9
12
  - 2.2.0
data/README.md CHANGED
@@ -31,22 +31,25 @@ One of the goals of this project is to do simple type checking like `"some strin
31
31
  - [Classes' type checkers](#classes-type-checkers)
32
32
  - [Modules' type checkers](#modules-type-checkers)
33
33
  - [Specials' type checkers](#specials-type-checkers)
34
+ - [Kind::Validator (ActiveModel::Validations)](#kindvalidator-activemodelvalidations)
35
+ - [Usage](#usage-1)
36
+ - [Defining the default validation strategy](#defining-the-default-validation-strategy)
37
+ - [Using the `allow_nil` and `strict` options](#using-the-allow_nil-and-strict-options)
34
38
  - [Kind::Undefined](#kindundefined)
35
39
  - [Kind.of.\<Type\>.or_undefined()](#kindoftypeor_undefined)
36
40
  - [Kind::Maybe](#kindmaybe)
37
41
  - [Replacing blocks by lambdas](#replacing-blocks-by-lambdas)
38
- - [Kind::Maybe[] and Kind::Maybe#then method aliases](#kindmaybe-and-kindmaybethen-method-aliases)
42
+ - [Kind::Maybe[], Kind::Maybe.wrap() and Kind::Maybe#then method aliases](#kindmaybe-kindmaybewrap-and-kindmaybethen-method-aliases)
39
43
  - [Replacing blocks by lambdas](#replacing-blocks-by-lambdas-1)
40
44
  - [Kind::None() and Kind::Some()](#kindnone-and-kindsome)
41
45
  - [Kind.of.Maybe()](#kindofmaybe)
42
46
  - [Kind::Optional](#kindoptional)
43
47
  - [Replacing blocks by lambdas](#replacing-blocks-by-lambdas-2)
44
48
  - [Kind.of.\<Type\>.as_optional](#kindoftypeas_optional)
49
+ - [Kind::Maybe(<Type>)](#kindmaybetype)
45
50
  - [Kind::Maybe#try](#kindmaybetry)
46
- - [Kind::Validator (ActiveModel::Validations)](#kindvalidator-activemodelvalidations)
47
- - [Usage](#usage-1)
48
- - [Defining the default validation strategy](#defining-the-default-validation-strategy)
49
- - [Using the `allow_nil` and `strict` options](#using-the-allow_nil-and-strict-options)
51
+ - [Kind::Maybe#try!](#kindmaybetry-1)
52
+ - [Kind::Maybe#dig](#kindmaybedig)
50
53
  - [Kind::Empty](#kindempty)
51
54
  - [Similar Projects](#similar-projects)
52
55
  - [Development](#development)
@@ -163,13 +166,19 @@ Kind.of.Boolean.or_nil(true) # true
163
166
  Use the method `.instance?` to verify if the given object has the expected type.
164
167
 
165
168
  ```ruby
166
- Kind.of.Hash.instance?('') # false
169
+ Kind.of.Hash.instance?({}) # true
170
+ Kind.of.Hash.instance?({}, HashWithIndifferentAccess.new) # true
171
+
172
+ Kind.of.Hash.instance?('') # false
173
+ Kind.of.Hash.instance?({}, '') # false
167
174
 
168
175
  # ---
169
176
 
170
- Kind.of.Boolean.instance?('') # false
171
- Kind.of.Boolean.instance?(true) # true
172
- Kind.of.Boolean.instance?(false) # true
177
+ Kind.of.Boolean.instance?(true) # true
178
+ Kind.of.Boolean.instance?(true, false) # true
179
+
180
+ Kind.of.Boolean.instance?(nil) # false
181
+ Kind.of.Boolean.instance?(false, true, nil) # false
173
182
  ```
174
183
 
175
184
  > **Note:** When `.instance?` is called without an argument,
@@ -186,6 +195,22 @@ collection
186
195
  > To do this, use Kind.of.\<Type\>?()
187
196
 
188
197
  ```ruby
198
+ Kind.of.Hash?({}) # true
199
+ Kind.of.Hash?({}, HashWithIndifferentAccess.new) # true
200
+
201
+ Kind.of.Hash?('') # false
202
+ Kind.of.Hash?({}, '') # false
203
+
204
+ # ---
205
+
206
+ Kind.of.Boolean?(true) # true
207
+ Kind.of.Boolean?(false, true) # true
208
+
209
+ Kind.of.Boolean?(nil) # false
210
+ Kind.of.Boolean?(false, true, nil) # false
211
+
212
+ # ---
213
+
189
214
  collection = [ {number: 1}, 'number 2', {number: 3}, :number_4 ]
190
215
 
191
216
  collection.select(&Kind.of.Hash?) # [{:number=>1}, {:number=>3}]
@@ -434,6 +459,7 @@ The list of types (classes and modules) available to use with `Kind.of.*` or `Ki
434
459
  - `Kind.of.Range`
435
460
  - `Kind.of.Hash`
436
461
  - `Kind.of.Struct`
462
+ - `Kind.of.OpenStruct`
437
463
  - `Kind.of.Enumerator`
438
464
  - `Kind.of.Set`
439
465
  - `Kind.of.Method`
@@ -459,6 +485,158 @@ The list of types (classes and modules) available to use with `Kind.of.*` or `Ki
459
485
 
460
486
  [⬆️ Back to Top](#table-of-contents-)
461
487
 
488
+ ## Kind::Validator (ActiveModel::Validations)
489
+
490
+ This module enables the capability to validate types via [`ActiveModel::Validations >= 3.2, < 6.1.0`](https://api.rubyonrails.org/classes/ActiveModel/Validations.html). e.g
491
+
492
+ ```ruby
493
+ class Person
494
+ include ActiveModel::Validations
495
+
496
+ attr_accessor :first_name, :last_name
497
+
498
+ validates :first_name, :last_name, kind: String
499
+ end
500
+ ```
501
+
502
+ And to make use of it, you will need to do an explicitly require. e.g:
503
+
504
+ ```ruby
505
+ # In some Gemfile
506
+ gem 'kind', require: 'kind/active_model/validation'
507
+
508
+ # In some .rb file
509
+ require 'kind/active_model/validation'
510
+ ```
511
+
512
+ ### Usage
513
+
514
+ **[Object#kind_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-kind_of-3F)**
515
+
516
+ ```ruby
517
+ validates :name, kind: { of: String }
518
+
519
+ # Use an array to verify if the attribute
520
+ # is an instance of one of the classes/modules.
521
+
522
+ validates :status, kind: { of: [String, Symbol]}
523
+ ```
524
+
525
+ **[Kind.is](#verifying-the-kind-of-some-classmodule)**
526
+
527
+ ```ruby
528
+ #
529
+ # Verifying if the attribute value is the class or a subclass.
530
+ #
531
+ class Human; end
532
+ class Person < Human; end
533
+ class User < Human; end
534
+
535
+ validates :human_kind, kind: { is: Human }
536
+
537
+ #
538
+ # Verifying if the attribute value is the module or if it is a class that includes the module
539
+ #
540
+ module Human; end
541
+ class Person; include Human; end
542
+ class User; include Human; end
543
+
544
+ validates :human_kind, kind: { is: Human }
545
+
546
+ #
547
+ # Verifying if the attribute value is the module or if it is a module that extends the module
548
+ #
549
+ module Human; end
550
+ module Person; extend Human; end
551
+ module User; extend Human; end
552
+
553
+ validates :human_kind, kind: { is: Human }
554
+
555
+ # or use an array to verify if the attribute
556
+ # is a kind of one those classes/modules.
557
+
558
+ validates :human_kind, kind: { is: [Person, User] }
559
+ ```
560
+
561
+ **[Object#instance_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-instance_of-3F)**
562
+
563
+ ```ruby
564
+ validates :name, kind: { instance_of: String }
565
+
566
+ # or use an array to verify if the attribute
567
+ # is an instance of one of the classes/modules.
568
+
569
+ validates :name, kind: { instance_of: [String, Symbol] }
570
+ ```
571
+
572
+
573
+ **[Object#respond_to?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-respond_to-3F)**
574
+
575
+ ```ruby
576
+ validates :handler, kind: { respond_to: :call }
577
+ ```
578
+
579
+ **Array.new.all? { |item| item.kind_of?(Class) }**
580
+
581
+ ```ruby
582
+ validates :account_types, kind: { array_of: String }
583
+
584
+ # or use an array to verify if the attribute
585
+ # is an instance of one of the classes
586
+
587
+ validates :account_types, kind: { array_of: [String, Symbol] }
588
+ ```
589
+
590
+ **Array.new.all? { |item| expected_values.include?(item) }**
591
+
592
+ ```ruby
593
+ # Verifies if the attribute value
594
+ # is an array with some or all the expected values.
595
+
596
+ validates :account_types, kind: { array_with: ['foo', 'bar'] }
597
+ ```
598
+
599
+ #### Defining the default validation strategy
600
+
601
+ By default, you can define the attribute type directly (without a hash). e.g.
602
+
603
+ ```ruby
604
+ validates :name, kind: String
605
+ # or
606
+ validates :name, kind: [String, Symbol]
607
+ ```
608
+
609
+ To changes this behavior you can set another strategy to validates the attributes types:
610
+
611
+ ```ruby
612
+ Kind::Validator.default_strategy = :instance_of
613
+
614
+ # Tip: Create an initializer if you are in a Rails application.
615
+ ```
616
+
617
+ And these are the available options to define the default strategy:
618
+ - `kind_of` *(default)*
619
+ - `instance_of`
620
+
621
+ #### Using the `allow_nil` and `strict` options
622
+
623
+ You can use the `allow_nil` option with any of the kind validations. e.g.
624
+
625
+ ```ruby
626
+ validates :name, kind: String, allow_nil: true
627
+ ```
628
+
629
+ And as any active model validation, kind validations works with the `strict: true`
630
+ option and with the `validates!` method. e.g.
631
+
632
+ ```ruby
633
+ validates :first_name, kind: String, strict: true
634
+ # or
635
+ validates! :last_name, kind: String
636
+ ```
637
+
638
+ [⬆️ Back to Top](#table-of-contents-)
639
+
462
640
  ## Kind::Undefined
463
641
 
464
642
  The [`Kind::Undefined`](https://github.com/serradura/kind/blob/834f6b8ebdc737de8e5628986585f30c1a5aa41b/lib/kind/undefined.rb) constant is used as the default argument of type checkers. This is necessary [to know if no arguments were passed to the type check methods](https://github.com/serradura/kind/blob/834f6b8ebdc737de8e5628986585f30c1a5aa41b/lib/kind.rb#L45-L48). But, you can use it in your codebase too, especially if you need to distinguish the usage of `nil` as a method argument.
@@ -543,7 +721,7 @@ end
543
721
  Kind::Maybe.new(nil).map(&Add).value_or(0) # 0
544
722
  ```
545
723
 
546
- ### Kind::Maybe[] and Kind::Maybe#then method aliases
724
+ ### Kind::Maybe[], Kind::Maybe.wrap() and Kind::Maybe#then method aliases
547
725
 
548
726
  You can use `Kind::Maybe[]` (brackets) instead of the `.new` to transform values in a `Kind::Maybe`. Another alias is `.then` to the `.map` method.
549
727
 
@@ -557,6 +735,19 @@ result =
557
735
  puts result # 42
558
736
  ```
559
737
 
738
+ You can also use `Kind::Maybe.wrap()` instead of the `.new` method.
739
+
740
+ ```ruby
741
+ result =
742
+ Kind::Maybe
743
+ .wrap(5)
744
+ .then { |value| value * 5 }
745
+ .then { |value| value + 17 }
746
+ .value_or(0)
747
+
748
+ puts result # 42
749
+ ```
750
+
560
751
  #### Replacing blocks by lambdas
561
752
 
562
753
  ```ruby
@@ -586,7 +777,7 @@ you could use the methods `Kind::None` and `Kind::Some` to do this. e.g:
586
777
  Add = -> params do
587
778
  a, b = Kind.of.Hash(params, or: Empty::HASH).values_at(:a, :b)
588
779
 
589
- return Kind::None unless Kind.of.Numeric.instance?(a, b)
780
+ return Kind::None unless Kind.of.Numeric?(a, b)
590
781
 
591
782
  Kind::Some(a + b)
592
783
  end
@@ -695,10 +886,11 @@ In these scenarios, you could check the given input type as optional and avoid u
695
886
 
696
887
  ```ruby
697
888
  def person_name(params)
698
- Kind::Of::Hash.as_optional(params)
699
- .map { |data| data if data.values_at(:first_name, :last_name).compact.size == 2 }
700
- .map { |data| "#{data[:first_name]} #{data[:last_name]}" }
701
- .value_or { 'John Doe' }
889
+ Kind::Of::Hash
890
+ .as_optional(params)
891
+ .map { |data| data if data.values_at(:first_name, :last_name).compact.size == 2 }
892
+ .map { |data| "#{data[:first_name]} #{data[:last_name]}" }
893
+ .value_or { 'John Doe' }
702
894
  end
703
895
 
704
896
  person_name('') # "John Doe"
@@ -719,9 +911,20 @@ def person_name(params)
719
911
  'John Doe'
720
912
  end
721
913
  end
914
+
915
+ #
916
+ # You can also use Kind::Optional(<Type>) to achieve the same behavior
917
+ #
918
+ def person_name(params)
919
+ Kind::Optional(Hash)
920
+ .wrap(params)
921
+ .map { |data| data if data.values_at(:first_name, :last_name).compact.size == 2 }
922
+ .map { |data| "#{data[:first_name]} #{data[:last_name]}" }
923
+ .value_or { 'John Doe' }
924
+ end
722
925
  ```
723
926
 
724
- > Note: You could use the `.as_optional` method (or it alias `as_maybe`) with any [type checker](https://github.com/serradura/kind/blob/b177fed9cc2b3347d63963a2a2fd99f989c51a9a/README.md#type-checkers).
927
+ > Note: You could use the `.as_optional` method (or it alias `.as_maybe`) with any [type checker](https://github.com/serradura/kind/blob/b177fed9cc2b3347d63963a2a2fd99f989c51a9a/README.md#type-checkers).
725
928
 
726
929
  Let's see another example using a collection and how the method `.as_optional` works when it receives no argument.
727
930
 
@@ -795,193 +998,162 @@ end
795
998
 
796
999
  [⬆️ Back to Top](#table-of-contents-)
797
1000
 
798
- ### Kind::Maybe#try
1001
+ ### Kind::Maybe(<Type>)
799
1002
 
800
- If you don't want to use a map to access the value, you could use the `#try` method to access it. So, if the value wasn't `nil` or `Kind::Undefined`, it will be returned.
1003
+ There is an alternative to `Kind.of.\<Type\>.as_optional`, you can use `Kind::Optional(<Type>)` to create a maybe monad which will return None if the given input hasn't the expected type. e.g:
801
1004
 
802
1005
  ```ruby
803
- object = 'foo'
804
-
805
- p Kind::Maybe[object].try(:upcase) # "FOO"
806
-
807
- p Kind::Maybe[{}].try(:fetch, :number, 0) # 0
808
-
809
- p Kind::Maybe[{number: 1}].try(:fetch, :number) # 1
810
-
811
- p Kind::Maybe[object].try { |value| value.upcase } # "FOO"
1006
+ result1 =
1007
+ Kind::Maybe(Numeric)
1008
+ .wrap(5)
1009
+ .then { |value| value * 5 }
1010
+ .value_or { 0 }
812
1011
 
813
- #############
814
- # Nil value #
815
- #############
1012
+ puts result1 # 25
816
1013
 
817
- object = nil
1014
+ # ---
818
1015
 
819
- p Kind::Maybe[object].try(:upcase) # nil
1016
+ result2 =
1017
+ Kind::Optional(Numeric)
1018
+ .wrap('5')
1019
+ .then { |value| value * 5 }
1020
+ .value_or { 0 }
820
1021
 
821
- p Kind::Maybe[object].try { |value| value.upcase } # nil
1022
+ puts result2 # 0
1023
+ ```
822
1024
 
823
- #########################
824
- # Kind::Undefined value #
825
- #########################
1025
+ This typed maybe has the same methods of `Kind::Maybe` class. e.g:
826
1026
 
827
- object = Kind::Undefined
1027
+ ```ruby
1028
+ Kind::Maybe(Numeric)[5]
1029
+ Kind::Maybe(Numeric).new(5)
1030
+ Kind::Maybe(Numeric).wrap(5)
828
1031
 
829
- p Kind::Maybe[object].try(:upcase) # nil
1032
+ # ---
830
1033
 
831
- p Kind::Maybe[object].try { |value| value.upcase } # nil
1034
+ Kind::Optional(Numeric)[5]
1035
+ Kind::Optional(Numeric).new(5)
1036
+ Kind::Optional(Numeric).wrap(5)
832
1037
  ```
833
1038
 
834
1039
  [⬆️ Back to Top](#table-of-contents-)
835
1040
 
836
- ## Kind::Validator (ActiveModel::Validations)
1041
+ ### Kind::Maybe#try
837
1042
 
838
- This module enables the capability to validate types via [`ActiveModel::Validations >= 3.2, < 6.1.0`](https://api.rubyonrails.org/classes/ActiveModel/Validations.html). e.g
1043
+ If you don't want to use `#map/#then` to access the value, you could use the `#try` method to access it. So, if the value wasn't `nil` or `Kind::Undefined`, the some monad will be returned.
839
1044
 
840
1045
  ```ruby
841
- class Person
842
- include ActiveModel::Validations
843
-
844
- attr_accessor :first_name, :last_name
845
-
846
- validates :first_name, :last_name, kind: String
847
- end
848
- ```
1046
+ object = 'foo'
849
1047
 
850
- And to make use of it, you will need to do an explicitly require. e.g:
1048
+ Kind::Maybe[object].try(:upcase).value # "FOO"
851
1049
 
852
- ```ruby
853
- # In some Gemfile
854
- gem 'kind', require: 'kind/active_model/validation'
1050
+ Kind::Maybe[{}].try(:fetch, :number, 0).value # 0
855
1051
 
856
- # In some .rb file
857
- require 'kind/active_model/validation'
858
- ```
1052
+ Kind::Maybe[{number: 1}].try(:fetch, :number).value # 1
859
1053
 
860
- ### Usage
1054
+ Kind::Maybe[object].try { |value| value.upcase }.value # "FOO"
861
1055
 
862
- **[Object#kind_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-kind_of-3F)**
863
-
864
- ```ruby
865
- validates :name, kind: { of: String }
1056
+ #############
1057
+ # Nil value #
1058
+ #############
866
1059
 
867
- # Use an array to verify if the attribute
868
- # is an instance of one of the classes/modules.
1060
+ object = nil
869
1061
 
870
- validates :status, kind: { of: [String, Symbol]}
871
- ```
1062
+ Kind::Maybe[object].try(:upcase).value # nil
872
1063
 
873
- **[Kind.is](#verifying-the-kind-of-some-classmodule)**
1064
+ Kind::Maybe[object].try { |value| value.upcase }.value # nil
874
1065
 
875
- ```ruby
876
- #
877
- # Verifying if the attribute value is the class or a subclass.
878
- #
879
- class Human; end
880
- class Person < Human; end
881
- class User < Human; end
882
-
883
- validates :human_kind, kind: { is: Human }
1066
+ #########################
1067
+ # Kind::Undefined value #
1068
+ #########################
884
1069
 
885
- #
886
- # Verifying if the attribute value is the module or if it is a class that includes the module
887
- #
888
- module Human; end
889
- class Person; include Human; end
890
- class User; include Human; end
1070
+ object = Kind::Undefined
891
1071
 
892
- validates :human_kind, kind: { is: Human }
1072
+ Kind::Maybe[object].try(:upcase).value # nil
893
1073
 
894
- #
895
- # Verifying if the attribute value is the module or if it is a module that extends the module
896
- #
897
- module Human; end
898
- module Person; extend Human; end
899
- module User; extend Human; end
1074
+ Kind::Maybe[object].try { |value| value.upcase }.value # nil
1075
+ ```
900
1076
 
901
- validates :human_kind, kind: { is: Human }
1077
+ > **Note:** You can use the `#try` method with `Kind::Optional` objects.
902
1078
 
903
- # or use an array to verify if the attribute
904
- # is a kind of one those classes/modules.
1079
+ [⬆️ Back to Top](#table-of-contents-)
905
1080
 
906
- validates :human_kind, kind: { is: [Person, User] }
907
- ```
1081
+ ### Kind::Maybe#try!
908
1082
 
909
- **[Object#instance_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-instance_of-3F)**
1083
+ Has the same behavior of its `#try`, but it will raise an error if the value doesn't respond to the expected method.
910
1084
 
911
1085
  ```ruby
912
- validates :name, kind: { instance_of: String }
913
-
914
- # or use an array to verify if the attribute
915
- # is an instance of one of the classes/modules.
1086
+ Kind::Maybe[{}].try(:upcase) # => #<Kind::Maybe::None:0x0000... @value=nil>
916
1087
 
917
- validates :name, kind: { instance_of: [String, Symbol] }
1088
+ Kind::Maybe[{}].try!(:upcase) # => NoMethodError (undefined method `upcase' for {}:Hash)
918
1089
  ```
919
1090
 
1091
+ > **Note:** You can also use the `#try!` method with `Kind::Optional` objects.
920
1092
 
921
- **[Object#respond_to?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-respond_to-3F)**
1093
+ [⬆️ Back to Top](#table-of-contents-)
922
1094
 
923
- ```ruby
924
- validates :handler, kind: { respond_to: :call }
925
- ```
1095
+ ### Kind::Maybe#dig
926
1096
 
927
- **Array.new.all? { |item| item.kind_of?(Class) }**
1097
+ 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 value can't be digged.
928
1098
 
929
1099
  ```ruby
930
- validates :account_types, kind: { array_of: String }
931
-
932
- # or use an array to verify if the attribute
933
- # is an instance of one of the classes
1100
+ [nil, 1, '', /x/].each do |value|
1101
+ p Kind::Maybe[value].dig(:foo).value # nil
1102
+ end
934
1103
 
935
- validates :account_types, kind: { array_of: [String, Symbol] }
936
- ```
1104
+ # --
937
1105
 
938
- **Array.new.all? { |item| expected_values.include?(item) }**
1106
+ a = [1, 2, 3]
939
1107
 
940
- ```ruby
941
- # Verifies if the attribute value
942
- # is an array with some or all the expected values.
1108
+ Kind::Maybe[a].dig(0).value # 1
943
1109
 
944
- validates :account_types, kind: { array_with: ['foo', 'bar'] }
945
- ```
1110
+ Kind::Maybe[a].dig(3).value # nil
946
1111
 
947
- #### Defining the default validation strategy
1112
+ # --
948
1113
 
949
- By default, you can define the attribute type directly (without a hash). e.g.
1114
+ h = { foo: {bar: {baz: 1}}}
950
1115
 
951
- ```ruby
952
- validates :name, kind: String
953
- # or
954
- validates :name, kind: [String, Symbol]
955
- ```
1116
+ Kind::Maybe[h].dig(:foo).value # {bar: {baz: 1}}
1117
+ Kind::Maybe[h].dig(:foo, :bar).value # {baz: 1}
1118
+ Kind::Maybe[h].dig(:foo, :bar, :baz).value # 1
956
1119
 
957
- To changes this behavior you can set another strategy to validates the attributes types:
1120
+ Kind::Maybe[h].dig(:foo, :bar, 'baz').value # nil
958
1121
 
959
- ```ruby
960
- Kind::Validator.default_strategy = :instance_of
1122
+ # --
961
1123
 
962
- # Tip: Create an initializer if you are in a Rails application.
963
- ```
1124
+ i = { foo: [{'bar' => [1, 2]}, {baz: [3, 4]}] }
964
1125
 
965
- And these are the available options to define the default strategy:
966
- - `kind_of` *(default)*
967
- - `instance_of`
1126
+ Kind::Maybe[i].dig(:foo, 0, 'bar', 0).value # 1
1127
+ Kind::Maybe[i].dig(:foo, 0, 'bar', 1).value # 2
1128
+ Kind::Maybe[i].dig(:foo, 0, 'bar', -1).value # 2
968
1129
 
969
- #### Using the `allow_nil` and `strict` options
1130
+ Kind::Maybe[i].dig(:foo, 0, 'bar', 2).value # nil
970
1131
 
971
- You can use the `allow_nil` option with any of the kind validations. e.g.
1132
+ # --
972
1133
 
973
- ```ruby
974
- validates :name, kind: String, allow_nil: true
1134
+ s = Struct.new(:a, :b).new(101, 102)
1135
+ o = OpenStruct.new(c: 103, d: 104)
1136
+ b = { struct: s, ostruct: o, data: [s, o]}
1137
+
1138
+ Kind::Maybe[s].dig(:a).value # 101
1139
+ Kind::Maybe[b].dig(:struct, :b).value # 102
1140
+ Kind::Maybe[b].dig(:data, 0, :b).value # 102
1141
+ Kind::Maybe[b].dig(:data, 0, 'b').value # 102
1142
+
1143
+ Kind::Maybe[o].dig(:c).value # 103
1144
+ Kind::Maybe[b].dig(:ostruct, :d).value # 104
1145
+ Kind::Maybe[b].dig(:data, 1, :d).value # 104
1146
+ Kind::Maybe[b].dig(:data, 1, 'd').value # 104
1147
+
1148
+ Kind::Maybe[s].dig(:f).value # nil
1149
+ Kind::Maybe[o].dig(:f).value # nil
1150
+ Kind::Maybe[b].dig(:struct, :f).value # nil
1151
+ Kind::Maybe[b].dig(:ostruct, :f).value # nil
1152
+ Kind::Maybe[b].dig(:data, 0, :f).value # nil
1153
+ Kind::Maybe[b].dig(:data, 1, :f).value # nil
975
1154
  ```
976
1155
 
977
- And as any active model validation, kind validations works with the `strict: true`
978
- option and with the `validates!` method. e.g.
979
-
980
- ```ruby
981
- validates :first_name, kind: String, strict: true
982
- # or
983
- validates! :last_name, kind: String
984
- ```
1156
+ > **Note:** You can also use the `#dig` method with `Kind::Optional` objects.
985
1157
 
986
1158
  [⬆️ Back to Top](#table-of-contents-)
987
1159
 
@@ -2,14 +2,16 @@
2
2
 
3
3
  require 'kind/version'
4
4
 
5
+ require 'ostruct'
6
+
5
7
  require 'kind/empty'
6
8
  require 'kind/undefined'
9
+ require 'kind/checker'
7
10
  require 'kind/maybe'
8
11
 
9
12
  require 'kind/error'
10
13
  require 'kind/of'
11
14
  require 'kind/is'
12
- require 'kind/checker'
13
15
  require 'kind/types'
14
16
 
15
17
  module Kind
@@ -18,37 +20,19 @@ module Kind
18
20
  private_constant :WRONG_NUMBER_OF_ARGUMENTS
19
21
 
20
22
  def self.is(expected = Undefined, object = Undefined)
21
- return Is if expected == Undefined && object == Undefined
23
+ return Is if Undefined == expected && Undefined == object
22
24
 
23
- return Kind::Is.(expected, object) if object != Undefined
25
+ return Kind::Is.(expected, object) if Undefined != object
24
26
 
25
27
  raise ArgumentError, WRONG_NUMBER_OF_ARGUMENTS
26
28
  end
27
29
 
28
- MODULE_OR_CLASS = 'Module/Class'.freeze
29
-
30
- private_constant :MODULE_OR_CLASS
31
-
32
- private_class_method def self.__checkers__
33
- @__checkers__ ||= {}
34
- end
35
-
36
- __checkers__
37
-
38
30
  def self.of(kind = Undefined, object = Undefined)
39
- return Of if kind == Undefined && object == Undefined
40
-
41
- return Kind::Of.(kind, object) if object != Undefined
31
+ return Of if Undefined == kind && Undefined == object
42
32
 
43
- __checkers__[kind] ||= begin
44
- kind_name = kind.name
33
+ return Kind::Of.(kind, object) if Undefined != object
45
34
 
46
- if Kind::Of.const_defined?(kind_name, false)
47
- Kind::Of.const_get(kind_name)
48
- else
49
- Checker.new(Kind::Of.(Module, kind, MODULE_OR_CLASS))
50
- end
51
- end
35
+ Kind::Checker::Factory.create(kind)
52
36
  end
53
37
 
54
38
  def self.of?(kind, *args)
@@ -65,7 +49,7 @@ module Kind
65
49
  end
66
50
 
67
51
  def self.Module(value)
68
- value == ::Module || (value.is_a?(::Module) && !self.Class(value))
52
+ ::Module == value || (value.is_a?(::Module) && !self.Class(value))
69
53
  end
70
54
 
71
55
  def self.Boolean(value)
@@ -81,13 +65,13 @@ module Kind
81
65
  # -- Class
82
66
 
83
67
  def self.Class(object = Undefined)
84
- return Class if object == Undefined
68
+ return Class if Undefined == object
85
69
 
86
70
  self.call(::Class, object)
87
71
  end
88
72
 
89
73
  const_set(:Class, ::Module.new do
90
- extend Checkable
74
+ extend Checker::Protocol
91
75
 
92
76
  def self.__kind; ::Class; end
93
77
 
@@ -103,16 +87,16 @@ module Kind
103
87
  # -- Module
104
88
 
105
89
  def self.Module(object = Undefined)
106
- return Module if object == Undefined
90
+ return Module if Undefined == object
107
91
 
108
92
  self.call(::Module, object)
109
93
  end
110
94
 
111
95
  const_set(:Module, ::Module.new do
112
- extend Checkable
96
+ extend Checker::Protocol
113
97
 
114
98
  def self.__kind_undefined(value)
115
- __kind_error(Kind::Undefined) if value == Kind::Undefined
99
+ __kind_error(Kind::Undefined) if Kind::Undefined == value
116
100
 
117
101
  yield
118
102
  end
@@ -137,7 +121,7 @@ module Kind
137
121
  if ::Kind::Maybe::Value.none?(default)
138
122
  __kind_undefined(value) { __kind_of(value) }
139
123
  else
140
- return value if value != Kind::Undefined && instance?(value)
124
+ return value if Kind::Undefined != value && instance?(value)
141
125
 
142
126
  __kind_undefined(default) { __kind_of(default) }
143
127
  end
@@ -155,7 +139,7 @@ module Kind
155
139
  def self.Boolean(object = Undefined, options = Empty::HASH)
156
140
  default = options[:or]
157
141
 
158
- return Kind::Of::Boolean if object == Undefined && default.nil?
142
+ return Kind::Of::Boolean if Undefined == object && default.nil?
159
143
 
160
144
  bool = object.nil? ? default : object
161
145
 
@@ -165,7 +149,7 @@ module Kind
165
149
  end
166
150
 
167
151
  const_set(:Boolean, ::Module.new do
168
- extend Checkable
152
+ extend Checker::Protocol
169
153
 
170
154
  def self.__kind; [TrueClass, FalseClass].freeze; end
171
155
 
@@ -177,14 +161,14 @@ module Kind
177
161
  if ::Kind::Maybe::Value.none?(default)
178
162
  __kind_undefined(value) { Kind::Of::Boolean(value) }
179
163
  else
180
- return value if value != Kind::Undefined && instance?(value)
164
+ return value if Kind::Undefined != value && instance?(value)
181
165
 
182
166
  __kind_undefined(default) { Kind::Of::Boolean(default) }
183
167
  end
184
168
  end
185
169
 
186
170
  def self.__kind_undefined(value)
187
- if value == Kind::Undefined
171
+ if Kind::Undefined == value
188
172
  raise Kind::Error.new('Boolean'.freeze, Kind::Undefined)
189
173
  else
190
174
  yield
@@ -210,7 +194,7 @@ module Kind
210
194
  def self.Lambda(object = Undefined, options = Empty::HASH)
211
195
  default = options[:or]
212
196
 
213
- return Kind::Of::Lambda if object == Undefined && default.nil?
197
+ return Kind::Of::Lambda if Undefined == object && default.nil?
214
198
 
215
199
  func = object || default
216
200
 
@@ -220,7 +204,7 @@ module Kind
220
204
  end
221
205
 
222
206
  const_set(:Lambda, ::Module.new do
223
- extend Checkable
207
+ extend Checker::Protocol
224
208
 
225
209
  def self.__kind; ::Proc; end
226
210
 
@@ -230,14 +214,14 @@ module Kind
230
214
  if ::Kind::Maybe::Value.none?(default)
231
215
  __kind_undefined(value) { Kind::Of::Lambda(value) }
232
216
  else
233
- return value if value != Kind::Undefined && instance?(value)
217
+ return value if Kind::Undefined != value && instance?(value)
234
218
 
235
219
  __kind_undefined(default) { Kind::Of::Lambda(default) }
236
220
  end
237
221
  end
238
222
 
239
223
  def self.__kind_undefined(value)
240
- if value == Kind::Undefined
224
+ if Kind::Undefined == value
241
225
  raise Kind::Error.new('Lambda'.freeze, Kind::Undefined)
242
226
  else
243
227
  yield
@@ -258,7 +242,7 @@ module Kind
258
242
  def self.Callable(object = Undefined, options = Empty::HASH)
259
243
  default = options[:or]
260
244
 
261
- return Kind::Of::Callable if object == Undefined && default.nil?
245
+ return Kind::Of::Callable if Undefined == object && default.nil?
262
246
 
263
247
  callable = object || default
264
248
 
@@ -268,7 +252,7 @@ module Kind
268
252
  end
269
253
 
270
254
  const_set(:Callable, ::Module.new do
271
- extend Checkable
255
+ extend Checker::Protocol
272
256
 
273
257
  def self.__kind; Object; end
274
258
 
@@ -282,14 +266,14 @@ module Kind
282
266
  if ::Kind::Maybe::Value.none?(default)
283
267
  __kind_undefined(value) { Kind::Of::Callable(value) }
284
268
  else
285
- return value if value != Kind::Undefined && instance?(value)
269
+ return value if Kind::Undefined != value && instance?(value)
286
270
 
287
271
  __kind_undefined(default) { Kind::Of::Callable(default) }
288
272
  end
289
273
  end
290
274
 
291
275
  def self.__kind_undefined(value)
292
- if value == Kind::Undefined
276
+ if Kind::Undefined == value
293
277
  raise Kind::Error.new('Callable'.freeze, Kind::Undefined)
294
278
  else
295
279
  yield
@@ -312,7 +296,7 @@ module Kind
312
296
  # -- Classes
313
297
  [
314
298
  String, Symbol, Numeric, Integer, Float, Regexp, Time,
315
- Array, Range, Hash, Struct, Enumerator, Set,
299
+ Array, Range, Hash, Struct, Enumerator, Set, OpenStruct,
316
300
  Method, Proc,
317
301
  IO, File
318
302
  ].each { |klass| Types.add(klass) }
@@ -53,12 +53,12 @@ class KindValidator < ActiveModel::EachValidator
53
53
  def kind_is_not(expected, value)
54
54
  case expected
55
55
  when Class
56
- return if Kind.of.Class(value) == expected || value < expected
56
+ return if expected == Kind.of.Class(value) || value < expected
57
57
 
58
58
  "must be the class or a subclass of `#{expected.name}`"
59
59
  when Module
60
60
  return if value.kind_of?(Class) && value <= expected
61
- return if Kind.of.Module(value) == expected || value.kind_of?(expected)
61
+ return if expected == Kind.of.Module(value) || value.kind_of?(expected)
62
62
 
63
63
  "must include the `#{expected.name}` module"
64
64
  else
@@ -1,78 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kind/checker/factory'
4
+ require 'kind/checker/protocol'
3
5
  module Kind
4
- module Checkable
5
- def class?(value)
6
- Kind::Is.__call__(__kind, value)
7
- end
8
-
9
- def instance(value, options = Empty::HASH)
10
- default = options[:or]
11
-
12
- return Kind::Of.(__kind, value) if ::Kind::Maybe::Value.none?(default)
13
-
14
- value != Kind::Undefined && instance?(value) ? value : Kind::Of.(__kind, default)
15
- end
16
-
17
- def [](value, options = options = Empty::HASH)
18
- instance(value, options)
19
- end
20
-
21
- def to_proc
22
- @to_proc ||=
23
- -> checker { -> value { checker.instance(value) } }.call(self)
24
- end
25
-
26
- def __is_instance__(value)
27
- value.kind_of?(__kind)
28
- end
29
-
30
- def is_instance_to_proc
31
- @is_instance_to_proc ||=
32
- -> checker { -> value { checker.__is_instance__(value) } }.call(self)
33
- end
34
-
35
- def instance?(*args)
36
- return is_instance_to_proc if args.empty?
37
-
38
- return args.all? { |object| __is_instance__(object) } if args.size > 1
39
-
40
- arg = args[0]
41
- arg == Kind::Undefined ? is_instance_to_proc : __is_instance__(arg)
42
- end
43
-
44
- def or_nil(value)
45
- return value if instance?(value)
46
- end
47
-
48
- def or_undefined(value)
49
- or_nil(value) || Kind::Undefined
50
- end
51
-
52
- def __as_maybe__(value)
53
- Kind::Maybe.new(or_nil(value))
54
- end
55
-
56
- def as_maybe_to_proc
57
- @as_maybe_to_proc ||=
58
- -> checker { -> value { checker.__as_maybe__(value) } }.call(self)
59
- end
60
-
61
- def as_maybe(value = Kind::Undefined)
62
- return __as_maybe__(value) if value != Kind::Undefined
63
-
64
- as_maybe_to_proc
65
- end
66
-
67
- def as_optional(value = Kind::Undefined)
68
- as_maybe(value)
69
- end
70
- end
71
-
72
- private_constant :Checkable
73
-
74
6
  class Checker
75
- include Checkable
7
+ include Protocol
76
8
 
77
9
  attr_reader :__kind
78
10
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'singleton'
4
+
5
+ module Kind
6
+ class Checker
7
+ class Factory
8
+ include Singleton
9
+
10
+ def self.create(kind)
11
+ instance.create(kind)
12
+ end
13
+
14
+ def initialize
15
+ @__checkers__ = {}
16
+ end
17
+
18
+ MODULE_OR_CLASS = 'Module/Class'.freeze
19
+
20
+ private_constant :MODULE_OR_CLASS
21
+
22
+ def create(kind)
23
+ @__checkers__[kind] ||= begin
24
+ kind_name = kind.name
25
+
26
+ if Kind::Of.const_defined?(kind_name, false)
27
+ Kind::Of.const_get(kind_name)
28
+ else
29
+ Kind::Checker.new(Kind::Of.(Module, kind, MODULE_OR_CLASS))
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ class Checker
5
+ module Protocol
6
+ def class?(value)
7
+ Kind::Is.__call__(__kind, value)
8
+ end
9
+
10
+ def instance(value, options = Empty::HASH)
11
+ default = options[:or]
12
+
13
+ return Kind::Of.(__kind, value) if ::Kind::Maybe::Value.none?(default)
14
+
15
+ Kind::Undefined != value && instance?(value) ? value : Kind::Of.(__kind, default)
16
+ end
17
+
18
+ def [](value, options = options = Empty::HASH)
19
+ instance(value, options)
20
+ end
21
+
22
+ def to_proc
23
+ @to_proc ||=
24
+ -> checker { -> value { checker.instance(value) } }.call(self)
25
+ end
26
+
27
+ def __is_instance__(value)
28
+ value.kind_of?(__kind)
29
+ end
30
+
31
+ def is_instance_to_proc
32
+ @is_instance_to_proc ||=
33
+ -> checker { -> value { checker.__is_instance__(value) } }.call(self)
34
+ end
35
+
36
+ def instance?(*args)
37
+ return is_instance_to_proc if args.empty?
38
+
39
+ return args.all? { |object| __is_instance__(object) } if args.size > 1
40
+
41
+ arg = args[0]
42
+ Kind::Undefined == arg ? is_instance_to_proc : __is_instance__(arg)
43
+ end
44
+
45
+ def or_nil(value)
46
+ return value if instance?(value)
47
+ end
48
+
49
+ def or_undefined(value)
50
+ or_nil(value) || Kind::Undefined
51
+ end
52
+
53
+ def __as_maybe__(value)
54
+ Kind::Maybe.new(or_nil(value))
55
+ end
56
+
57
+ def as_maybe_to_proc
58
+ @as_maybe_to_proc ||=
59
+ -> checker { -> value { checker.__as_maybe__(value) } }.call(self)
60
+ end
61
+
62
+ def as_maybe(value = Kind::Undefined)
63
+ return __as_maybe__(value) if Kind::Undefined != value
64
+
65
+ as_maybe_to_proc
66
+ end
67
+
68
+ def as_optional(value = Kind::Undefined)
69
+ as_maybe(value)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Dig
5
+ extend self
6
+
7
+ def call(data, keys)
8
+ return unless keys.is_a?(Array)
9
+
10
+ keys.reduce(data) do |memo, key|
11
+ value = get(memo, key)
12
+
13
+ break if value.nil?
14
+
15
+ value
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def get(data, key)
22
+ return data[key] if Hash === data
23
+
24
+ case data
25
+ when Array
26
+ data[key] if key.respond_to?(:to_int)
27
+ when OpenStruct
28
+ data[key] if key.respond_to?(:to_sym)
29
+ when Struct
30
+ if key.respond_to?(:to_int) || key.respond_to?(:to_sym)
31
+ data[key] rescue nil
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -7,7 +7,7 @@ module Kind
7
7
  private_constant :UNDEFINED_OBJECT
8
8
 
9
9
  def initialize(arg, object = UNDEFINED_OBJECT)
10
- if object == UNDEFINED_OBJECT
10
+ if UNDEFINED_OBJECT == object
11
11
  # Will be used when the exception was raised with a message. e.g:
12
12
  # raise Kind::Error, "some message"
13
13
  super(arg)
@@ -1,10 +1,25 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'kind/dig'
4
+
3
5
  module Kind
4
6
  module Maybe
7
+ class Typed
8
+ def initialize(kind)
9
+ @kind_checker = Kind::Checker::Factory.create(kind)
10
+ end
11
+
12
+ def wrap(value)
13
+ @kind_checker.as_maybe(value)
14
+ end
15
+
16
+ alias_method :new, :wrap
17
+ alias_method :[], :wrap
18
+ end
19
+
5
20
  module Value
6
21
  def self.none?(value)
7
- value == nil || value == Undefined
22
+ value.nil? || Undefined == value
8
23
  end
9
24
 
10
25
  def self.some?(value)
@@ -42,9 +57,9 @@ module Kind
42
57
  INVALID_DEFAULT_ARG = 'the default value must be defined as an argument or block'.freeze
43
58
 
44
59
  def value_or(default = Undefined, &block)
45
- raise ArgumentError, INVALID_DEFAULT_ARG if default == Undefined && !block
60
+ raise ArgumentError, INVALID_DEFAULT_ARG if Undefined == default && !block
46
61
 
47
- default != Undefined ? default : block.call
62
+ Undefined != default ? default : block.call
48
63
  end
49
64
 
50
65
  def none?; true; end
@@ -55,10 +70,16 @@ module Kind
55
70
 
56
71
  alias_method :then, :map
57
72
 
58
- def try(method_name = Undefined, &block)
59
- Kind.of.Symbol(method_name) if method_name != Undefined
73
+ def try!(method_name = Undefined, *args, &block)
74
+ Kind.of.Symbol(method_name) if Undefined != method_name
60
75
 
61
- nil
76
+ NONE_WITH_NIL_VALUE
77
+ end
78
+
79
+ alias_method :try, :try!
80
+
81
+ def dig(*keys)
82
+ NONE_WITH_NIL_VALUE
62
83
  end
63
84
 
64
85
  private_constant :INVALID_DEFAULT_ARG
@@ -79,22 +100,47 @@ module Kind
79
100
  def map(&fn)
80
101
  result = fn.call(@value)
81
102
 
82
- return result if Maybe::None === result
83
- return NONE_WITH_NIL_VALUE if result == nil
84
- return NONE_WITH_UNDEFINED_VALUE if result == Undefined
85
-
86
- Some.new(result)
103
+ resolve(result)
87
104
  end
88
105
 
89
106
  alias_method :then, :map
90
107
 
91
- def try(method_name = Undefined, *args, &block)
92
- fn = method_name == Undefined ? block : Kind.of.Symbol(method_name).to_proc
108
+ def try!(method_name = Undefined, *args, &block)
109
+ Kind::Of::Symbol(method_name) if Undefined != method_name
110
+
111
+ __try__(method_name, args, block)
112
+ end
93
113
 
94
- result = args.empty? ? fn.call(value) : fn.call(*args.unshift(value))
114
+ def try(method_name = Undefined, *args, &block)
115
+ if (Undefined != method_name && value.respond_to?(Kind::Of::Symbol(method_name))) ||
116
+ (Undefined == method_name && block)
117
+ __try__(method_name, args, block)
118
+ else
119
+ NONE_WITH_NIL_VALUE
120
+ end
121
+ end
95
122
 
96
- return result if Maybe::Value.some?(result)
123
+ def dig(*keys)
124
+ resolve(Kind::Dig.call(value, keys))
97
125
  end
126
+
127
+ private
128
+
129
+ def __try__(method_name = Undefined, args, block)
130
+ fn = Undefined == method_name ? block : method_name.to_proc
131
+
132
+ result = args.empty? ? fn.call(value) : fn.call(*args.unshift(value))
133
+
134
+ resolve(result)
135
+ end
136
+
137
+ def resolve(result)
138
+ return result if Maybe::None === result
139
+ return NONE_WITH_NIL_VALUE if result.nil?
140
+ return NONE_WITH_UNDEFINED_VALUE if Undefined == result
141
+
142
+ Some.new(result)
143
+ end
98
144
  end
99
145
 
100
146
  def self.new(value)
@@ -102,7 +148,11 @@ module Kind
102
148
  result_type.new(value)
103
149
  end
104
150
 
105
- def self.[](value);
151
+ def self.[](value)
152
+ new(value)
153
+ end
154
+
155
+ def self.wrap(value)
106
156
  new(value)
107
157
  end
108
158
 
@@ -132,4 +182,12 @@ module Kind
132
182
  def self.Some(value)
133
183
  Maybe.some(value)
134
184
  end
185
+
186
+ def self.Maybe(kind)
187
+ Maybe::Typed.new(kind)
188
+ end
189
+
190
+ def self.Optional(kind)
191
+ Maybe::Typed.new(kind)
192
+ end
135
193
  end
@@ -10,7 +10,7 @@ module Kind
10
10
  def self.%{method_name}(object = Undefined, options = Empty::HASH)
11
11
  default = options[:or]
12
12
 
13
- return Kind::Of::%{kind_name} if object == Undefined && default.nil?
13
+ return Kind::Of::%{kind_name} if Undefined == object && default.nil?
14
14
 
15
15
  is_instance = Kind::Of::%{kind_name}.__is_instance__(object)
16
16
 
@@ -28,7 +28,7 @@ module Kind
28
28
 
29
29
  KIND_IS = <<-RUBY
30
30
  def self.%{method_name}(value = Undefined)
31
- return Kind::Is::%{kind_name} if value == Undefined
31
+ return Kind::Is::%{kind_name} if Undefined == value
32
32
 
33
33
  Kind::Is.__call__(::%{kind_name_to_check}, value)
34
34
  end
@@ -98,7 +98,7 @@ module Kind
98
98
  kind_name = params[:kind_name]
99
99
  params[:kind_name_to_check] ||= kind_name
100
100
 
101
- kind_checker = ::Module.new { extend Checkable }
101
+ kind_checker = ::Module.new { extend Checker::Protocol }
102
102
  kind_checker.module_eval("def self.__kind; #{params[:kind_name_to_check]}; end")
103
103
 
104
104
  kind_of_mod.instance_eval(KIND_OF % params)
@@ -19,7 +19,7 @@ module Kind
19
19
  end
20
20
 
21
21
  def undefined.default(value, default)
22
- return self if value != self
22
+ return self if self != value
23
23
 
24
24
  default.respond_to?(:call) ? default.call : default
25
25
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kind
4
- VERSION = '2.1.0'
4
+ VERSION = '3.1.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kind
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 3.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-05-12 00:00:00.000000000 Z
11
+ date: 2020-07-08 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A simple type system (at runtime) for Ruby - free of dependencies.
14
14
  email:
@@ -32,6 +32,9 @@ files:
32
32
  - lib/kind/active_model/kind_validator.rb
33
33
  - lib/kind/active_model/validation.rb
34
34
  - lib/kind/checker.rb
35
+ - lib/kind/checker/factory.rb
36
+ - lib/kind/checker/protocol.rb
37
+ - lib/kind/dig.rb
35
38
  - lib/kind/empty.rb
36
39
  - lib/kind/error.rb
37
40
  - lib/kind/is.rb