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 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: