kind 1.9.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|