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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8d4f4be415e28c7f240a097a64626588e7b3c7bc8a70dbfd71bf2b5b426e016a
4
- data.tar.gz: 7401efa30206d27d4f10608b5164d6c334d8da02e4652d8a7f156ee081f18ec5
3
+ metadata.gz: ebd68f3e676f6b030fa85da36b57a47a7f866e52373aed2b0e41315c63b0fdd0
4
+ data.tar.gz: 5800122e2ed54025450eabe06bee5f9df3474c45b6ffa396c3b80dc4ad8ca566
5
5
  SHA512:
6
- metadata.gz: f672462c9e64afce93af792d179d1c6095003ade48329018f4e64eb0bae7fb825699f2350c643fa2a1f2a3ae2822b3cbb1e8444c3a423101a37beffadbd7a614
7
- data.tar.gz: 890957443724fe3fdd7fec56d8b4a87c0e92f2793d26d298b8347b75e7091612e36a87d29bae70c7a789fe9e0750b366a4fe572104351e55b04903bbfcbffe03
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)` or if it's a class/module and if its `public_instance_methods.include?(: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 [active model validations](https://api.rubyonrails.org/classes/ActiveModel/Validations.html). e.g
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
- # or
707
- validates :status, kind: { is_a: [String, Symbol]}
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] || options[:is_a]
22
- return is_class(expected, value) if expected = options[:is] || options[:klass]
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 instance_of(expected, value)
35
+ def kind_of(expected, value)
36
36
  types = Array(expected)
37
37
 
38
- return if types.any? { |type| value.instance_of?(type) }
38
+ return if types.any? { |type| value.kind_of?(type) }
39
39
 
40
- "must be an instance of: #{types.map { |klass| klass.name }.join(', ')}"
40
+ "must be a kind of: #{types.map { |klass| klass.name }.join(', ')}"
41
41
  end
42
42
 
43
- def kind_of(expected, value)
44
- types = Array(expected)
43
+ CLASS_OR_MODULE = 'Class/Module'.freeze
45
44
 
46
- return if types.any? { |type| value.is_a?(type) }
45
+ def kind_is(expected, value)
46
+ return kind_is_not(expected, value) unless expected.kind_of?(Array)
47
47
 
48
- "must be a kind of: #{types.map { |klass| klass.name }.join(', ')}"
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 is_class(klass, value)
52
- return if Kind.of.Class(value) == Kind.of.Class(klass) || value < klass
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
- "must be the class or a subclass of `#{klass.name}`"
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 array_of(expected, value)
75
+ def instance_of(expected, value)
64
76
  types = Array(expected)
65
77
 
66
- return if value.is_a?(Array) && !value.empty? && value.all? { |value| types.any? { |type| value.is_a?(type) } }
78
+ return if types.any? { |type| value.instance_of?(type) }
67
79
 
68
- "must be an array of: #{types.map { |klass| klass.name }.join(', ')}"
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.is_a?(Array) && !value.empty? && (value - Kind.of.Array(expected)).empty?
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
@@ -2,10 +2,10 @@
2
2
 
3
3
  module Kind
4
4
  module Validator
5
- DEFAULT_STRATEGIES = Set.new(%w[instance_of kind_of is_a]).freeze
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, :instance_of, :respond_to, :klass, :array_of or :array_with'.freeze
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kind
4
- VERSION = '1.9.0'
4
+ VERSION = '2.0.0'
5
5
  end
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.is_a?(::Class)
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
- klass = Kind.of.Class(value)
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) || (value.is_a?(Module) && value.public_instance_methods.include?(: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.__kind; ::Module; end
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.__kind_undefined(value)
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: 1.9.0
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-06 00:00:00.000000000 Z
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: