kind 1.8.0 → 1.9.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: a0a88ddbce52eca41466b1c600f745b3c212e7833bbb178cabd86514e1011601
4
- data.tar.gz: f96ab5843a3596a19863389dacda8e5865eff611163112f5092a3387ea6898a4
3
+ metadata.gz: 8d4f4be415e28c7f240a097a64626588e7b3c7bc8a70dbfd71bf2b5b426e016a
4
+ data.tar.gz: 7401efa30206d27d4f10608b5164d6c334d8da02e4652d8a7f156ee081f18ec5
5
5
  SHA512:
6
- metadata.gz: 06af14f778ea084ae699a0c00e67d6808cbdace68a838cff42782fb7150f51e3524eba060784fd0cb540d08c2ecaa4b8135f75813e7d4223b87c9d1326831c05
7
- data.tar.gz: 16e1e11bce9f67237a3f306b526f1b1f6564fe10eafcd22c2c90f2f18fa22077155a4372a9149d24dac02d266895e36c256a147a625f3592e8686bca974ab94b
6
+ metadata.gz: f672462c9e64afce93af792d179d1c6095003ade48329018f4e64eb0bae7fb825699f2350c643fa2a1f2a3ae2822b3cbb1e8444c3a423101a37beffadbd7a614
7
+ data.tar.gz: 890957443724fe3fdd7fec56d8b4a87c0e92f2793d26d298b8347b75e7091612e36a87d29bae70c7a789fe9e0750b366a4fe572104351e55b04903bbfcbffe03
@@ -0,0 +1,20 @@
1
+ #!/bin/bash
2
+
3
+ bundle exec rake test
4
+
5
+ ruby_v=$(ruby -v)
6
+
7
+ ACTIVEMODEL_VERSION='3.2' bundle update && bundle exec rake test
8
+ ACTIVEMODEL_VERSION='4.0' bundle update && bundle exec rake test
9
+ ACTIVEMODEL_VERSION='4.1' bundle update && bundle exec rake test
10
+ ACTIVEMODEL_VERSION='4.2' bundle update && bundle exec rake test
11
+ ACTIVEMODEL_VERSION='5.0' bundle update && bundle exec rake test
12
+ ACTIVEMODEL_VERSION='5.1' bundle update && bundle exec rake test
13
+
14
+ if [[ ! $ruby_v =~ '2.2.0' ]]; then
15
+ ACTIVEMODEL_VERSION='5.2' bundle update && bundle exec rake test
16
+ fi
17
+
18
+ if [[ $ruby_v =~ '2.5.' ]] || [[ $ruby_v =~ '2.6.' ]] || [[ $ruby_v =~ '2.7.' ]]; then
19
+ ACTIVEMODEL_VERSION='6.0' bundle update && bundle exec rake test
20
+ fi
@@ -1,6 +1,8 @@
1
1
  ---
2
2
  language: ruby
3
3
 
4
+ sudo: false
5
+
4
6
  cache: bundler
5
7
 
6
8
  rvm:
@@ -22,7 +24,7 @@ before_script:
22
24
  - chmod +x ./cc-test-reporter
23
25
  - "./cc-test-reporter before-build"
24
26
 
25
- script: bundle exec rake test
27
+ script: "./.travis.sh"
26
28
 
27
29
  after_success:
28
30
  - "./cc-test-reporter after-build -t simplecov"
data/Gemfile CHANGED
@@ -1,8 +1,33 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- # Specify your gem's dependencies in kind.gemspec
4
- gemspec
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ activemodel_version = ENV['ACTIVEMODEL_VERSION']
6
+
7
+ activemodel = case activemodel_version
8
+ when '3.2' then '3.2.22'
9
+ when '4.0' then '4.0.13'
10
+ when '4.1' then '4.1.16'
11
+ when '4.2' then '4.2.11'
12
+ when '5.0' then '5.0.7'
13
+ when '5.1' then '5.1.7'
14
+ when '5.2' then '5.2.4'
15
+ when '6.0' then '6.0.0'
16
+ end
17
+
18
+ group :test do
19
+ if activemodel_version
20
+ gem 'activesupport', activemodel, require: false
21
+ gem 'activemodel', activemodel, require: false
22
+ gem 'minitest', activemodel_version < '4.1' ? '~> 4.2' : '~> 5.0'
23
+ else
24
+ gem 'minitest', '~> 5.0'
25
+ end
5
26
 
6
- gem "rake", "~> 12.0"
7
- gem "minitest", "~> 5.0"
8
- gem "simplecov", "~> 0.17.1"
27
+ gem 'simplecov', require: false
28
+ end
29
+
30
+ gem 'rake', '~> 13.0'
31
+
32
+ # Specify your gem's dependencies in type_validator.gemspec
33
+ gemspec
data/README.md CHANGED
@@ -6,13 +6,13 @@
6
6
 
7
7
  # Kind <!-- omit in toc -->
8
8
 
9
- Basic type system for Ruby.
9
+ A simple type system (at runtime) for Ruby - free of dependencies.
10
10
 
11
11
  **Motivation:**
12
12
 
13
13
  As a creator of Ruby gems, I have a common need that I have to handle in many of my projects: type checking of method arguments.
14
14
 
15
- One of the goals of this project is to do simple type checking like `"some string".is_a?(String)`, but, exposing useful abstractions to do it.
15
+ One of the goals of this project is to do simple type checking like `"some string".is_a?(String)`, but, exposing useful abstractions to do it. e.g: [Kind.of.\<Type\> methods](#verifying-the-kind-of-some-object), [active model validations](#kindvalidator-activemodelvalidations), [maybe monad](#kindmaybe).
16
16
 
17
17
  ## Table of Contents <!-- omit in toc -->
18
18
  - [Required Ruby version](#required-ruby-version)
@@ -35,7 +35,11 @@ One of the goals of this project is to do simple type checking like `"some strin
35
35
  - [Kind::Maybe#try](#kindmaybetry)
36
36
  - [Kind.of.Maybe()](#kindofmaybe)
37
37
  - [Kind::Optional](#kindoptional)
38
- - [Kind.of.<Type>.as_optional](#kindoftypeas_optional)
38
+ - [Kind.of.\<Type\>.as_optional](#kindoftypeas_optional)
39
+ - [Kind::Validator (ActiveModel::Validations)](#kindvalidator-activemodelvalidations)
40
+ - [Usage](#usage-1)
41
+ - [Defining the default validation strategy](#defining-the-default-validation-strategy)
42
+ - [Using the `allow_nil` and `strict` options](#using-the-allow_nil-and-strict-options)
39
43
  - [Kind::Empty](#kindempty)
40
44
  - [Similar Projects](#similar-projects)
41
45
  - [Development](#development)
@@ -94,6 +98,17 @@ Kind.of.Boolean(true) # true
94
98
  Kind.of.Boolean(false) # false
95
99
  ```
96
100
 
101
+ > **Note:** `Kind.of.<Type>` supports the to_proc protocol.
102
+ > But it won't perform a strict validation, instead, it will return true
103
+ > when the value has the desired kind and false if it hasn't.
104
+
105
+ ```ruby
106
+ collection = [ {number: 1}, 'number 2', {number: 3}, :number_4 ]
107
+
108
+ collection
109
+ .select(&Kind.of.Hash) # [{number: 1}, {number: 3}]
110
+ ```
111
+
97
112
  When the verified value is nil, it is possible to define a default value with the same type to be returned.
98
113
 
99
114
  ```ruby
@@ -106,7 +121,7 @@ Kind.of.Hash(value, or: {}) # {}
106
121
  Kind.of.Boolean(nil, or: true) # true
107
122
  ```
108
123
 
109
- As an alternative syntax, you can use the `Kind::Of` instead of the `Kind.of` method. e.g: `Kind::Of::Hash('')`
124
+ > **Note:** As an alternative syntax, you can use the `Kind::Of` instead of the `Kind.of` method. e.g: `Kind::Of::Hash('')`
110
125
 
111
126
  But if you don't need a strict type verification, use the `.or_nil` method.
112
127
 
@@ -133,19 +148,15 @@ Kind.of.Boolean.instance?(true) # true
133
148
  Kind.of.Boolean.instance?(false) # true
134
149
  ```
135
150
 
136
- **Note:** When `.instance?` is called without an argument, it will return a lambda which will perform the kind verification.
151
+ > **Note:** When `.instance?` is called without an argument,
152
+ > it will return a lambda which will perform the kind verification.
137
153
 
138
154
  ```ruby
139
- collection = [
140
- {number: 1},
141
- 'number 0',
142
- {number: 2},
143
- [0],
144
- ]
155
+ collection = [ {number: 1}, 'number 2', {number: 3}, :number_4 ]
145
156
 
146
157
  collection
147
158
  .select(&Kind.of.Hash.instance?)
148
- .reduce(0) { |total, item| total + item.fetch(:number, 0) } # 3
159
+ .reduce(0) { |total, item| total + item.fetch(:number, 0) } # 4
149
160
  ```
150
161
 
151
162
  Also, there are aliases to perform the strict type verification. e.g:
@@ -548,7 +559,7 @@ puts result2 # 35
548
559
 
549
560
  [⬆️ Back to Top](#table-of-contents-)
550
561
 
551
- ### Kind.of.<Type>.as_optional
562
+ ### Kind.of.\<Type\>.as_optional
552
563
 
553
564
  It is very common the need to avoid some computing when a method receives a wrong input.
554
565
  In these scenarios, you could check the given input type as optional and avoid unexpected behavior. e.g:
@@ -573,7 +584,7 @@ person_name(first_name: 'Rodrigo', last_name: 'Serradura') # "Rodrigo Serradura"
573
584
  # See below the previous implementation without using an optional.
574
585
  #
575
586
  def person_name(params)
576
- if params.is_a?(Hash) && params.values_at(:first_name, :last_name).compact.size == 2
587
+ if params.kind_of?(Hash) && params.values_at(:first_name, :last_name).compact.size == 2
577
588
  "#{params[:first_name]} #{params[:last_name]}"
578
589
  else
579
590
  'John Doe'
@@ -586,12 +597,7 @@ end
586
597
  Let's see another example using a collection and how the method `.as_optional` works when it receives no argument.
587
598
 
588
599
  ```ruby
589
- collection = [
590
- {number: 1},
591
- 'number 0',
592
- {number: 2},
593
- [0],
594
- ]
600
+ collection = [ {number: 1}, 'number 0', {number: 2}, [0] ]
595
601
 
596
602
  collection
597
603
  .select(&Kind.of.Hash.as_optional)
@@ -613,9 +619,9 @@ module PersonIntroduction
613
619
  extend self
614
620
 
615
621
  def call(params)
616
- optional_params = Kind::Of::Hash.as_optional(params)
622
+ optional = Kind::Of::Hash.as_optional(params)
617
623
 
618
- "Hi my name is #{full_name(optional_params)}, I'm #{age(optional_params)} years old."
624
+ "Hi my name is #{full_name(optional)}, I'm #{age(optional)} years old."
619
625
  end
620
626
 
621
627
  private
@@ -637,7 +643,7 @@ module PersonIntroduction
637
643
  extend self
638
644
 
639
645
  def call(params)
640
- "Hi my name is #{full_name(params)}, I'm #{age(params)}"
646
+ "Hi my name is #{full_name(params)}, I'm #{age(params)} years old."
641
647
  end
642
648
 
643
649
  private
@@ -660,6 +666,139 @@ end
660
666
 
661
667
  [⬆️ Back to Top](#table-of-contents-)
662
668
 
669
+ ## Kind::Validator (ActiveModel::Validations)
670
+
671
+ This module enables the capability to validate types via [active model validations](https://api.rubyonrails.org/classes/ActiveModel/Validations.html). e.g
672
+
673
+ ```ruby
674
+ class Person
675
+ include ActiveModel::Validations
676
+
677
+ attr_accessor :first_name, :last_name
678
+
679
+ validates :first_name, :last_name, kind: String
680
+ end
681
+ ```
682
+
683
+ And to make use of it, you will need to do an explicitly require. e.g:
684
+
685
+ ```ruby
686
+ # In some Gemfile
687
+ gem 'kind', require: 'kind/active_model/validation'
688
+
689
+ # In some .rb file
690
+ require 'kind/active_model/validation'
691
+ ```
692
+
693
+ ### Usage
694
+
695
+ **[Object#kind_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-kind_of-3F)**
696
+
697
+ ```ruby
698
+ validates :name, kind: { of: String }
699
+ # or
700
+ validates :name, kind: { is_a: String }
701
+
702
+ # Use an array to verify if the attribute
703
+ # is an instance of one of the classes/modules.
704
+
705
+ validates :status, kind: { of: [String, Symbol]}
706
+ # or
707
+ validates :status, kind: { is_a: [String, Symbol]}
708
+ ```
709
+
710
+ **[Object#instance_of?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-instance_of-3F)**
711
+
712
+ ```ruby
713
+ validates :name, kind: { instance_of: String }
714
+
715
+ # or use an array to verify if the attribute
716
+ # is an instance of one of the classes/modules.
717
+
718
+ validates :name, kind: { instance_of: [String, Symbol] }
719
+ ```
720
+
721
+
722
+ **[Object#respond_to?](https://ruby-doc.org/core-2.6.4/Object.html#method-i-respond_to-3F)**
723
+
724
+ ```ruby
725
+ validates :handler, kind: { respond_to: :call }
726
+ ```
727
+
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
+ **Array.new.all? { |item| item.kind_of?(Class) }**
741
+
742
+ ```ruby
743
+ validates :account_types, kind: { array_of: String }
744
+
745
+ # or use an array to verify if the attribute
746
+ # is an instance of one of the classes
747
+
748
+ validates :account_types, kind: { array_of: [String, Symbol] }
749
+ ```
750
+
751
+ **Array.new.all? { |item| expected_values.include?(item) }**
752
+
753
+ ```ruby
754
+ # Verifies if the attribute value
755
+ # is an array with some or all the expected values.
756
+
757
+ validates :account_types, kind: { array_with: ['foo', 'bar'] }
758
+ ```
759
+
760
+ #### Defining the default validation strategy
761
+
762
+ By default, you can define the attribute type directly (without a hash). e.g.
763
+
764
+ ```ruby
765
+ validates :name, kind: String
766
+ # or
767
+ validates :name, kind: [String, Symbol]
768
+ ```
769
+
770
+ To changes this behavior you can set another strategy to validates the attributes types:
771
+
772
+ ```ruby
773
+ Kind::Validator.default_strategy = :instance_of
774
+
775
+ # Tip: Create an initializer if you are in a Rails application.
776
+ ```
777
+
778
+ And these are the available options to define the default strategy:
779
+ - `is_a`
780
+ - `kind_of` *(default)*
781
+ - `instance_of`
782
+
783
+ #### Using the `allow_nil` and `strict` options
784
+
785
+ You can use the `allow_nil` option with any of the kind validations. e.g.
786
+
787
+ ```ruby
788
+ validates :name, kind: String, allow_nil: true
789
+ ```
790
+
791
+ And as any active model validation, kind validations works with the `strict: true`
792
+ option and with the `validates!` method. e.g.
793
+
794
+ ```ruby
795
+ validates :first_name, kind: String, strict: true
796
+ # or
797
+ validates! :last_name, kind: String
798
+ ```
799
+
800
+ [⬆️ Back to Top](#table-of-contents-)
801
+
663
802
  ## Kind::Empty
664
803
 
665
804
  When you define a method that has default arguments, for certain data types, you will always create a new object in memory. e.g:
@@ -6,8 +6,8 @@ Gem::Specification.new do |spec|
6
6
  spec.authors = ['Rodrigo Serradura']
7
7
  spec.email = ['rodrigo.serradura@gmail.com']
8
8
 
9
- spec.summary = %q{Basic type system for Ruby.}
10
- spec.description = %q{Basic type system for Ruby (free of dependencies).}
9
+ spec.summary = %q{A simple type system (at runtime) for Ruby.}
10
+ spec.description = %q{A simple type system (at runtime) for Ruby - free of dependencies.}
11
11
  spec.homepage = 'https://github.com/serradura/kind'
12
12
  spec.license = 'MIT'
13
13
  spec.required_ruby_version = Gem::Requirement.new('>= 2.2.0')
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ class KindValidator < ActiveModel::EachValidator
4
+ def validate_each(record, attribute, value)
5
+ return if options[:allow_nil] && value.nil?
6
+
7
+ return unless error = call_validation_for(attribute, value)
8
+
9
+ raise Kind::Error.new("#{attribute} #{error}") if options[:strict]
10
+
11
+ record.errors.add(attribute, error)
12
+ end
13
+
14
+ private
15
+
16
+ def call_validation_for(attribute, value)
17
+ expected = options[:with] || options[:in]
18
+
19
+ return validate_with_default_strategy(expected, value) if expected
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]
23
+ return respond_to(expected, value) if expected = options[:respond_to]
24
+ return instance_of(expected, value) if expected = options[:instance_of]
25
+ return array_with(expected, value) if expected = options[:array_with]
26
+ return array_of(expected, value) if expected = options[:array_of]
27
+
28
+ raise Kind::Validator::InvalidDefinition.new(attribute)
29
+ end
30
+
31
+ def validate_with_default_strategy(expected, value)
32
+ send(Kind::Validator.default_strategy, expected, value)
33
+ end
34
+
35
+ def instance_of(expected, value)
36
+ types = Array(expected)
37
+
38
+ return if types.any? { |type| value.instance_of?(type) }
39
+
40
+ "must be an instance of: #{types.map { |klass| klass.name }.join(', ')}"
41
+ end
42
+
43
+ def kind_of(expected, value)
44
+ types = Array(expected)
45
+
46
+ return if types.any? { |type| value.is_a?(type) }
47
+
48
+ "must be a kind of: #{types.map { |klass| klass.name }.join(', ')}"
49
+ end
50
+
51
+ def is_class(klass, value)
52
+ return if Kind.of.Class(value) == Kind.of.Class(klass) || value < klass
53
+
54
+ "must be the class or a subclass of `#{klass.name}`"
55
+ end
56
+
57
+ def respond_to(method_name, value)
58
+ return if value.respond_to?(method_name)
59
+
60
+ "must respond to the method `#{method_name}`"
61
+ end
62
+
63
+ def array_of(expected, value)
64
+ types = Array(expected)
65
+
66
+ return if value.is_a?(Array) && !value.empty? && value.all? { |value| types.any? { |type| value.is_a?(type) } }
67
+
68
+ "must be an array of: #{types.map { |klass| klass.name }.join(', ')}"
69
+ end
70
+
71
+ def array_with(expected, value)
72
+ return if value.is_a?(Array) && !value.empty? && (value - Kind.of.Array(expected)).empty?
73
+
74
+ "must be an array with: #{expected.join(', ')}"
75
+ end
76
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kind'
4
+ require 'kind/validator'
5
+ require 'active_model'
6
+ require 'active_model/validations'
7
+ require_relative 'kind_validator'
@@ -21,15 +21,15 @@ module Kind
21
21
  def instance?(value = Kind::Undefined)
22
22
  return __is_instance__(value) if value != Kind::Undefined
23
23
 
24
- is_instance_to_proc
24
+ to_proc
25
25
  end
26
26
 
27
27
  def __is_instance__(value)
28
28
  value.is_a?(__kind)
29
29
  end
30
30
 
31
- def is_instance_to_proc
32
- @is_instance_to_proc ||=
31
+ def to_proc
32
+ @to_proc ||=
33
33
  -> checker { -> value { checker.__is_instance__(value) } }.call(self)
34
34
  end
35
35
 
@@ -2,8 +2,18 @@
2
2
 
3
3
  module Kind
4
4
  class Error < TypeError
5
- def initialize(kind_name, object)
6
- super("#{object.inspect} expected to be a kind of #{kind_name}")
5
+ UNDEFINED_OBJECT = Object.new
6
+
7
+ private_constant :UNDEFINED_OBJECT
8
+
9
+ def initialize(arg, object = UNDEFINED_OBJECT)
10
+ if object == UNDEFINED_OBJECT
11
+ # Will be used when the exception was raised with a message. e.g:
12
+ # raise Kind::Error, "some message"
13
+ super(arg)
14
+ else
15
+ super("#{object.inspect} expected to be a kind of #{arg}")
16
+ end
7
17
  end
8
18
  end
9
19
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module Validator
5
+ DEFAULT_STRATEGIES = Set.new(%w[instance_of kind_of is_a]).freeze
6
+
7
+ class InvalidDefinition < ArgumentError
8
+ OPTIONS = 'Options to define one: :of, :instance_of, :respond_to, :klass, :array_of or :array_with'.freeze
9
+
10
+ def initialize(attribute)
11
+ super "invalid type definition for :#{attribute} attribute. #{OPTIONS}"
12
+ end
13
+
14
+ private_constant :OPTIONS
15
+ end
16
+
17
+ class InvalidDefaultStrategy < ArgumentError
18
+ OPTIONS =
19
+ DEFAULT_STRATEGIES.map { |option| ":#{option}" }.join(', ')
20
+
21
+ def initialize(option)
22
+ super "#{option.inspect} is an invalid option. Please use one of these: #{OPTIONS}"
23
+ end
24
+
25
+ private_constant :OPTIONS
26
+ end
27
+
28
+ def self.default_strategy
29
+ @default_strategy ||= :kind_of
30
+ end
31
+
32
+ def self.default_strategy=(option)
33
+ if DEFAULT_STRATEGIES.member?(String(option))
34
+ @default_strategy = option.to_sym
35
+ else
36
+ raise InvalidDefaultStrategy.new(option)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kind
4
- VERSION = '1.8.0'
4
+ VERSION = '1.9.0'
5
5
  end
data/test.sh ADDED
@@ -0,0 +1,11 @@
1
+ #!/bin/bash
2
+
3
+ bundle
4
+
5
+ rm Gemfile.lock
6
+
7
+ source $(dirname $0)/.travis.sh
8
+
9
+ rm Gemfile.lock
10
+
11
+ bundle
metadata CHANGED
@@ -1,16 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kind
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.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-04 00:00:00.000000000 Z
11
+ date: 2020-05-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
- description: Basic type system for Ruby (free of dependencies).
13
+ description: A simple type system (at runtime) for Ruby - free of dependencies.
14
14
  email:
15
15
  - rodrigo.serradura@gmail.com
16
16
  executables: []
@@ -18,6 +18,7 @@ extensions: []
18
18
  extra_rdoc_files: []
19
19
  files:
20
20
  - ".gitignore"
21
+ - ".travis.sh"
21
22
  - ".travis.yml"
22
23
  - CODE_OF_CONDUCT.md
23
24
  - Gemfile
@@ -28,6 +29,8 @@ files:
28
29
  - bin/setup
29
30
  - kind.gemspec
30
31
  - lib/kind.rb
32
+ - lib/kind/active_model/kind_validator.rb
33
+ - lib/kind/active_model/validation.rb
31
34
  - lib/kind/checker.rb
32
35
  - lib/kind/empty.rb
33
36
  - lib/kind/error.rb
@@ -36,7 +39,9 @@ files:
36
39
  - lib/kind/of.rb
37
40
  - lib/kind/types.rb
38
41
  - lib/kind/undefined.rb
42
+ - lib/kind/validator.rb
39
43
  - lib/kind/version.rb
44
+ - test.sh
40
45
  homepage: https://github.com/serradura/kind
41
46
  licenses:
42
47
  - MIT
@@ -61,5 +66,5 @@ requirements: []
61
66
  rubygems_version: 3.0.6
62
67
  signing_key:
63
68
  specification_version: 4
64
- summary: Basic type system for Ruby.
69
+ summary: A simple type system (at runtime) for Ruby.
65
70
  test_files: []