kind 1.9.0 → 2.0.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 +4 -4
- data/README.md +81 -18
- data/lib/kind/active_model/kind_validator.rb +36 -16
- data/lib/kind/validator.rb +2 -2
- data/lib/kind/version.rb +1 -1
- data/lib/kind.rb +9 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ebd68f3e676f6b030fa85da36b57a47a7f866e52373aed2b0e41315c63b0fdd0
|
4
|
+
data.tar.gz: 5800122e2ed54025450eabe06bee5f9df3474c45b6ffa396c3b80dc4ad8ca566
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3769fbbe39073a41961af28fde90412f30f1caab3b2129b4a91a39afb1e482310e209b1a5eea4249f09c667760f862c06cc98dc56ab7bb40854561ef75ea435
|
7
|
+
data.tar.gz: 8356c7a49afe6370ecced9485acd2a663d1f17729cbbccd89dec2c1f839ad0f754778502e447c89b8a129697a891bed07af30c20df0b52a9e4d338cb4df593ed
|
data/README.md
CHANGED
@@ -195,6 +195,49 @@ Kind.of.Hash.class?(Hash) # true
|
|
195
195
|
Kind.of.Hash.class?(ActiveSupport::HashWithIndifferentAccess) # true
|
196
196
|
```
|
197
197
|
|
198
|
+
> **Note:** The `Kind.is` could check the inheritance of Classes/Modules.
|
199
|
+
|
200
|
+
```ruby
|
201
|
+
#
|
202
|
+
# Verifying if the attribute value is the class or a subclass.
|
203
|
+
#
|
204
|
+
class Human; end
|
205
|
+
class Person < Human; end
|
206
|
+
class User < Human; end
|
207
|
+
|
208
|
+
Kind.is(Human, User) # true
|
209
|
+
Kind.is(Human, Human) # true
|
210
|
+
Kind.is(Human, Person) # true
|
211
|
+
|
212
|
+
Kind.is(Human, Struct) # false
|
213
|
+
|
214
|
+
#
|
215
|
+
# Verifying if the attribute value is the module or if it is a class that includes the module
|
216
|
+
#
|
217
|
+
module Human; end
|
218
|
+
class Person; include Human; end
|
219
|
+
class User; include Human; end
|
220
|
+
|
221
|
+
Kind.is(Human, User) # true
|
222
|
+
Kind.is(Human, Human) # true
|
223
|
+
Kind.is(Human, Person) # true
|
224
|
+
|
225
|
+
Kind.is(Human, Struct) # false
|
226
|
+
|
227
|
+
#
|
228
|
+
# Verifying if the attribute value is the module or if it is a module that extends the module
|
229
|
+
#
|
230
|
+
module Human; end
|
231
|
+
module Person; extend Human; end
|
232
|
+
module User; extend Human; end
|
233
|
+
|
234
|
+
Kind.is(Human, User) # true
|
235
|
+
Kind.is(Human, Human) # true
|
236
|
+
Kind.is(Human, Person) # true
|
237
|
+
|
238
|
+
Kind.is(Human, Struct) # false
|
239
|
+
```
|
240
|
+
|
198
241
|
[⬆️ Back to Top](#table-of-contents-)
|
199
242
|
|
200
243
|
### How to create a new type checker?
|
@@ -377,7 +420,7 @@ The list of types (classes and modules) available to use with `Kind.of.*` or `Ki
|
|
377
420
|
- `Kind.of.Module()`
|
378
421
|
- `Kind.of.Lambda()`
|
379
422
|
- `Kind.of.Boolean()`
|
380
|
-
- `Kind.of.Callable()`: verifies if the given value `respond_to?(:call)
|
423
|
+
- `Kind.of.Callable()`: verifies if the given value `respond_to?(:call)`.
|
381
424
|
- `Kind.of.Maybe()` or its alias `Kind.of.Optional()`
|
382
425
|
|
383
426
|
**Note:** Remember, you can use the `Kind.is.*` method to check if some given value is a class/module with all type checkers above.
|
@@ -668,7 +711,7 @@ end
|
|
668
711
|
|
669
712
|
## Kind::Validator (ActiveModel::Validations)
|
670
713
|
|
671
|
-
This module enables the capability to validate types via [
|
714
|
+
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
|
672
715
|
|
673
716
|
```ruby
|
674
717
|
class Person
|
@@ -696,15 +739,47 @@ require 'kind/active_model/validation'
|
|
696
739
|
|
697
740
|
```ruby
|
698
741
|
validates :name, kind: { of: String }
|
699
|
-
# or
|
700
|
-
validates :name, kind: { is_a: String }
|
701
742
|
|
702
743
|
# Use an array to verify if the attribute
|
703
744
|
# is an instance of one of the classes/modules.
|
704
745
|
|
705
746
|
validates :status, kind: { of: [String, Symbol]}
|
706
|
-
|
707
|
-
|
747
|
+
```
|
748
|
+
|
749
|
+
**[Kind.is](#verifying-the-kind-of-some-classmodule)**
|
750
|
+
|
751
|
+
```ruby
|
752
|
+
#
|
753
|
+
# Verifying if the attribute value is the class or a subclass.
|
754
|
+
#
|
755
|
+
class Human; end
|
756
|
+
class Person < Human; end
|
757
|
+
class User < Human; end
|
758
|
+
|
759
|
+
validates :human_kind, kind: { is: Human }
|
760
|
+
|
761
|
+
#
|
762
|
+
# Verifying if the attribute value is the module or if it is a class that includes the module
|
763
|
+
#
|
764
|
+
module Human; end
|
765
|
+
class Person; include Human; end
|
766
|
+
class User; include Human; end
|
767
|
+
|
768
|
+
validates :human_kind, kind: { is: Human }
|
769
|
+
|
770
|
+
#
|
771
|
+
# Verifying if the attribute value is the module or if it is a module that extends the module
|
772
|
+
#
|
773
|
+
module Human; end
|
774
|
+
module Person; extend Human; end
|
775
|
+
module User; extend Human; end
|
776
|
+
|
777
|
+
validates :human_kind, kind: { is: Human }
|
778
|
+
|
779
|
+
# or use an array to verify if the attribute
|
780
|
+
# is a kind of one those classes/modules.
|
781
|
+
|
782
|
+
validates :human_kind, kind: { is: [Person, User] }
|
708
783
|
```
|
709
784
|
|
710
785
|
**[Object#instance_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-instance_of-3F)**
|
@@ -725,18 +800,6 @@ validates :name, kind: { instance_of: [String, Symbol] }
|
|
725
800
|
validates :handler, kind: { respond_to: :call }
|
726
801
|
```
|
727
802
|
|
728
|
-
**Class == Class || Class < Class**
|
729
|
-
|
730
|
-
```ruby
|
731
|
-
# Verifies if the attribute value is the class or a subclass.
|
732
|
-
|
733
|
-
validates :handler, kind: { klass: Handler }
|
734
|
-
|
735
|
-
# or use the :is option
|
736
|
-
|
737
|
-
validates :handler, kind: { is: Handler }
|
738
|
-
```
|
739
|
-
|
740
803
|
**Array.new.all? { |item| item.kind_of?(Class) }**
|
741
804
|
|
742
805
|
```ruby
|
@@ -18,8 +18,8 @@ class KindValidator < ActiveModel::EachValidator
|
|
18
18
|
|
19
19
|
return validate_with_default_strategy(expected, value) if expected
|
20
20
|
|
21
|
-
return kind_of(expected, value) if expected = options[:of]
|
22
|
-
return
|
21
|
+
return kind_of(expected, value) if expected = options[:of]
|
22
|
+
return kind_is(expected, value) if expected = options[:is]
|
23
23
|
return respond_to(expected, value) if expected = options[:respond_to]
|
24
24
|
return instance_of(expected, value) if expected = options[:instance_of]
|
25
25
|
return array_with(expected, value) if expected = options[:array_with]
|
@@ -32,26 +32,38 @@ class KindValidator < ActiveModel::EachValidator
|
|
32
32
|
send(Kind::Validator.default_strategy, expected, value)
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
35
|
+
def kind_of(expected, value)
|
36
36
|
types = Array(expected)
|
37
37
|
|
38
|
-
return if types.any? { |type| value.
|
38
|
+
return if types.any? { |type| value.kind_of?(type) }
|
39
39
|
|
40
|
-
"must be
|
40
|
+
"must be a kind of: #{types.map { |klass| klass.name }.join(', ')}"
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
types = Array(expected)
|
43
|
+
CLASS_OR_MODULE = 'Class/Module'.freeze
|
45
44
|
|
46
|
-
|
45
|
+
def kind_is(expected, value)
|
46
|
+
return kind_is_not(expected, value) unless expected.kind_of?(Array)
|
47
47
|
|
48
|
-
|
48
|
+
result = expected.map { |kind| kind_is_not(kind, value) }.compact
|
49
|
+
|
50
|
+
result.empty? || result.size < expected.size ? nil : result.join(', ')
|
49
51
|
end
|
50
52
|
|
51
|
-
def
|
52
|
-
|
53
|
+
def kind_is_not(expected, value)
|
54
|
+
case expected
|
55
|
+
when Class
|
56
|
+
return if Kind.of.Class(value) == expected || value < expected
|
53
57
|
|
54
|
-
|
58
|
+
"must be the class or a subclass of `#{expected.name}`"
|
59
|
+
when Module
|
60
|
+
return if value.kind_of?(Class) && value <= expected
|
61
|
+
return if Kind.of.Module(value) == expected || value.kind_of?(expected)
|
62
|
+
|
63
|
+
"must include the `#{expected.name}` module"
|
64
|
+
else
|
65
|
+
raise Kind::Error.new(CLASS_OR_MODULE, expected)
|
66
|
+
end
|
55
67
|
end
|
56
68
|
|
57
69
|
def respond_to(method_name, value)
|
@@ -60,17 +72,25 @@ class KindValidator < ActiveModel::EachValidator
|
|
60
72
|
"must respond to the method `#{method_name}`"
|
61
73
|
end
|
62
74
|
|
63
|
-
def
|
75
|
+
def instance_of(expected, value)
|
64
76
|
types = Array(expected)
|
65
77
|
|
66
|
-
return if
|
78
|
+
return if types.any? { |type| value.instance_of?(type) }
|
67
79
|
|
68
|
-
"must be an
|
80
|
+
"must be an instance of: #{types.map { |klass| klass.name }.join(', ')}"
|
69
81
|
end
|
70
82
|
|
71
83
|
def array_with(expected, value)
|
72
|
-
return if value.
|
84
|
+
return if value.kind_of?(Array) && !value.empty? && (value - Kind.of.Array(expected)).empty?
|
73
85
|
|
74
86
|
"must be an array with: #{expected.join(', ')}"
|
75
87
|
end
|
88
|
+
|
89
|
+
def array_of(expected, value)
|
90
|
+
types = Array(expected)
|
91
|
+
|
92
|
+
return if value.kind_of?(Array) && !value.empty? && value.all? { |value| types.any? { |type| value.kind_of?(type) } }
|
93
|
+
|
94
|
+
"must be an array of: #{types.map { |klass| klass.name }.join(', ')}"
|
95
|
+
end
|
76
96
|
end
|
data/lib/kind/validator.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
module Kind
|
4
4
|
module Validator
|
5
|
-
DEFAULT_STRATEGIES = Set.new(%w[instance_of kind_of
|
5
|
+
DEFAULT_STRATEGIES = Set.new(%w[instance_of kind_of]).freeze
|
6
6
|
|
7
7
|
class InvalidDefinition < ArgumentError
|
8
|
-
OPTIONS = 'Options to define one: :of, :
|
8
|
+
OPTIONS = 'Options to define one: :of, :is, :respond_to, :instance_of, :array_of or :array_with'.freeze
|
9
9
|
|
10
10
|
def initialize(attribute)
|
11
11
|
super "invalid type definition for :#{attribute} attribute. #{OPTIONS}"
|
data/lib/kind/version.rb
CHANGED
data/lib/kind.rb
CHANGED
@@ -55,7 +55,7 @@ module Kind
|
|
55
55
|
|
56
56
|
module Is
|
57
57
|
def self.Class(value)
|
58
|
-
value.
|
58
|
+
value.kind_of?(::Class)
|
59
59
|
end
|
60
60
|
|
61
61
|
def self.Module(value)
|
@@ -63,12 +63,11 @@ module Kind
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def self.Boolean(value)
|
66
|
-
|
67
|
-
klass <= TrueClass || klass <= FalseClass
|
66
|
+
Kind.of.Class(value) <= TrueClass || value <= FalseClass
|
68
67
|
end
|
69
68
|
|
70
69
|
def self.Callable(value)
|
71
|
-
value.respond_to?(:call)
|
70
|
+
value.respond_to?(:call)
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
@@ -102,7 +101,11 @@ module Kind
|
|
102
101
|
const_set(:Module, ::Module.new do
|
103
102
|
extend Checkable
|
104
103
|
|
105
|
-
def self.
|
104
|
+
def self.__kind_undefined(value)
|
105
|
+
__kind_error(Kind::Undefined) if value == Kind::Undefined
|
106
|
+
|
107
|
+
yield
|
108
|
+
end
|
106
109
|
|
107
110
|
def self.__kind_error(value)
|
108
111
|
raise Kind::Error.new('Module'.freeze, value)
|
@@ -114,11 +117,7 @@ module Kind
|
|
114
117
|
__kind_error(value)
|
115
118
|
end
|
116
119
|
|
117
|
-
def self.
|
118
|
-
__kind_error(Kind::Undefined) if value == Kind::Undefined
|
119
|
-
|
120
|
-
yield
|
121
|
-
end
|
120
|
+
def self.__kind; ::Module; end
|
122
121
|
|
123
122
|
def self.class?(value); Kind::Is.Module(value); end
|
124
123
|
|
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:
|
4
|
+
version: 2.0.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-
|
11
|
+
date: 2020-05-07 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:
|