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 +4 -4
- data/.travis.sh +20 -0
- data/.travis.yml +3 -1
- data/Gemfile +31 -6
- data/README.md +162 -23
- data/kind.gemspec +2 -2
- data/lib/kind/active_model/kind_validator.rb +76 -0
- data/lib/kind/active_model/validation.rb +7 -0
- data/lib/kind/checker.rb +3 -3
- data/lib/kind/error.rb +12 -2
- data/lib/kind/validator.rb +40 -0
- data/lib/kind/version.rb +1 -1
- data/test.sh +11 -0
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d4f4be415e28c7f240a097a64626588e7b3c7bc8a70dbfd71bf2b5b426e016a
|
4
|
+
data.tar.gz: 7401efa30206d27d4f10608b5164d6c334d8da02e4652d8a7f156ee081f18ec5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f672462c9e64afce93af792d179d1c6095003ade48329018f4e64eb0bae7fb825699f2350c643fa2a1f2a3ae2822b3cbb1e8444c3a423101a37beffadbd7a614
|
7
|
+
data.tar.gz: 890957443724fe3fdd7fec56d8b4a87c0e92f2793d26d298b8347b75e7091612e36a87d29bae70c7a789fe9e0750b366a4fe572104351e55b04903bbfcbffe03
|
data/.travis.sh
ADDED
@@ -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
|
data/.travis.yml
CHANGED
@@ -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:
|
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
|
1
|
+
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
|
4
|
-
|
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
|
7
|
-
|
8
|
-
|
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
|
-
|
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
|
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,
|
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) } #
|
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
|
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.
|
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
|
-
|
622
|
+
optional = Kind::Of::Hash.as_optional(params)
|
617
623
|
|
618
|
-
"Hi my name is #{full_name(
|
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:
|
data/kind.gemspec
CHANGED
@@ -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{
|
10
|
-
spec.description = %q{
|
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
|
data/lib/kind/checker.rb
CHANGED
@@ -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
|
-
|
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
|
32
|
-
@
|
31
|
+
def to_proc
|
32
|
+
@to_proc ||=
|
33
33
|
-> checker { -> value { checker.__is_instance__(value) } }.call(self)
|
34
34
|
end
|
35
35
|
|
data/lib/kind/error.rb
CHANGED
@@ -2,8 +2,18 @@
|
|
2
2
|
|
3
3
|
module Kind
|
4
4
|
class Error < TypeError
|
5
|
-
|
6
|
-
|
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
|
data/lib/kind/version.rb
CHANGED
data/test.sh
ADDED
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.
|
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-
|
11
|
+
date: 2020-05-06 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
|
-
description:
|
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:
|
69
|
+
summary: A simple type system (at runtime) for Ruby.
|
65
70
|
test_files: []
|