kind 1.8.0 → 1.9.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 +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: []
|