kind 5.7.0 → 5.8.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: a01866d3dbb6b0ae5977a7e711b35eaa2152471b4d52781a285de03ec9ef86a1
4
- data.tar.gz: 8fd0cc81e96aa364a90f3c161e824d1a501296b4c4b40e2aca1e4286a75baaec
3
+ metadata.gz: 93717ed184e878dc6d3dea92d7c35f92f1157c3d7277d44960d7030b240173f7
4
+ data.tar.gz: d7f61ff50a6d66a2abcf62baf220528804e66bce854c8de76fe5dcb5327d0e46
5
5
  SHA512:
6
- metadata.gz: 10282e2b8777f2d1a738a6ce38285fc9f17f0d9a6b3aec26d46409d995cb0004fde5c20a3998ef68a98530c5fa25ee463fba8f3501e5cbeb0cb2b01e0f2627ba
7
- data.tar.gz: 7d16bf63dbb4928bef6182a7886e9268da869bddab12ac0e1192e39bac3fce2a4489ed308366188df4d6550047b2003e1b427f87430ec5e68c49c34a3974c13f
6
+ metadata.gz: 185a54220516ff302377c99d44aaff8d939fe14aed4dd9a3cc35c8d8e766bc2bf72451191a2751be14a1dd4687b3d818436d54646ac0f36c54ce9a61963865b8
7
+ data.tar.gz: 6c452536bc4f40a94dec53c7fa6779157f763f3a5239db9520fb75f2f5036c09bb2d145c5b2a53b85c42825b534c7c55ef4ec3228f0576f701543572f011727b
@@ -0,0 +1,27 @@
1
+
2
+ name: build
3
+ on: [pull_request]
4
+ jobs:
5
+ test:
6
+ runs-on: ubuntu-latest
7
+ strategy:
8
+ matrix:
9
+ ruby: [2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 3.0]
10
+ steps:
11
+ - uses: actions/checkout@v2
12
+ - uses: ruby/setup-ruby@v1
13
+ with:
14
+ ruby-version: ${{ matrix.ruby }}
15
+ bundler-cache: true
16
+ - name: Test and generate coverage
17
+ run: bin/test
18
+ - name: Format coverage
19
+ if: ${{ matrix.ruby >= 3 }}
20
+ run: bin/prepare_coverage
21
+ - uses: paambaati/codeclimate-action@v2.7.5
22
+ if: ${{ matrix.ruby >= 3 }}
23
+ env:
24
+ CC_TEST_REPORTER_ID: 9561ceed21b6724aea8063e82e5700bc8266e962978089594bf2d8f8ca5ffc94
25
+ with:
26
+ debug: true
27
+ coverageLocations: coverage/.resultset.json:simplecov
data/.gitignore CHANGED
@@ -9,3 +9,4 @@
9
9
 
10
10
  Gemfile.lock
11
11
  .foo
12
+ .tool-versions
@@ -0,0 +1,8 @@
1
+ {
2
+ "cSpell.enabled": true,
3
+ "cSpell.ignoreWords": [
4
+ "paambaati",
5
+ "resultset",
6
+ "simplecov"
7
+ ]
8
+ }
data/CHANGELOG.md CHANGED
@@ -3,85 +3,87 @@
3
3
  This project follows [semver 2.0.0](http://semver.org/spec/v2.0.0.html) and the recommendations of [keepachangelog.com](http://keepachangelog.com/).
4
4
 
5
5
  - [Unreleased](#unreleased)
6
- - [5.7.0 (2021-06-22)](#570-2021-06-22)
6
+ - [5.8.0 (2021-09-22)](#580-2021-09-22)
7
7
  - [Added](#added)
8
- - [5.6.0 (2021-05-14)](#560-2021-05-14)
8
+ - [5.7.0 (2021-06-22)](#570-2021-06-22)
9
9
  - [Added](#added-1)
10
- - [5.5.0 (2021-04-05)](#550-2021-04-05)
10
+ - [5.6.0 (2021-05-14)](#560-2021-05-14)
11
11
  - [Added](#added-2)
12
+ - [5.5.0 (2021-04-05)](#550-2021-04-05)
13
+ - [Added](#added-3)
12
14
  - [5.4.1 (2021-03-26)](#541-2021-03-26)
13
15
  - [Fixed](#fixed)
14
16
  - [5.4.0 (2021-03-25)](#540-2021-03-25)
15
- - [Added](#added-3)
16
- - [5.3.0 (2021-03-23)](#530-2021-03-23)
17
17
  - [Added](#added-4)
18
- - [5.2.0 (2021-03-17)](#520-2021-03-17)
18
+ - [5.3.0 (2021-03-23)](#530-2021-03-23)
19
19
  - [Added](#added-5)
20
+ - [5.2.0 (2021-03-17)](#520-2021-03-17)
21
+ - [Added](#added-6)
20
22
  - [Deprecated](#deprecated)
21
23
  - [Changes](#changes)
22
24
  - [5.1.0 (2021-02-23)](#510-2021-02-23)
23
- - [Added](#added-6)
25
+ - [Added](#added-7)
24
26
  - [Deprecated](#deprecated-1)
25
27
  - [5.0.0 (2021-02-22)](#500-2021-02-22)
26
28
  - [Breaking Changes](#breaking-changes)
27
29
  - [Removed](#removed)
28
30
  - [4.1.0 (2021-02-22)](#410-2021-02-22)
29
- - [Added](#added-7)
30
- - [4.0.0 (2021-02-22)](#400-2021-02-22)
31
31
  - [Added](#added-8)
32
+ - [4.0.0 (2021-02-22)](#400-2021-02-22)
33
+ - [Added](#added-9)
32
34
  - [Deprecated](#deprecated-2)
33
35
  - [Fixed](#fixed-1)
34
36
  - [3.1.0 (2020-07-08)](#310-2020-07-08)
35
- - [Added](#added-9)
37
+ - [Added](#added-10)
36
38
  - [3.0.0 (2020-06-25)](#300-2020-06-25)
37
39
  - [Breaking Changes](#breaking-changes-1)
38
- - [Added](#added-10)
39
- - [2.3.0 (2020-06-24)](#230-2020-06-24)
40
40
  - [Added](#added-11)
41
- - [2.2.0 (2020-06-23)](#220-2020-06-23)
41
+ - [2.3.0 (2020-06-24)](#230-2020-06-24)
42
42
  - [Added](#added-12)
43
- - [2.1.0 (2020-05-12)](#210-2020-05-12)
43
+ - [2.2.0 (2020-06-23)](#220-2020-06-23)
44
44
  - [Added](#added-13)
45
+ - [2.1.0 (2020-05-12)](#210-2020-05-12)
46
+ - [Added](#added-14)
45
47
  - [Breaking Changes](#breaking-changes-2)
46
48
  - [2.0.0 (2020-05-07)](#200-2020-05-07)
47
- - [Added](#added-14)
49
+ - [Added](#added-15)
48
50
  - [Breaking Changes](#breaking-changes-3)
49
51
  - [Removed](#removed-1)
50
52
  - [1.9.0 (2020-05-06)](#190-2020-05-06)
51
- - [Added](#added-15)
52
- - [1.8.0 (2020-05-03)](#180-2020-05-03)
53
53
  - [Added](#added-16)
54
+ - [1.8.0 (2020-05-03)](#180-2020-05-03)
55
+ - [Added](#added-17)
54
56
  - [1.7.0 (2020-05-03)](#170-2020-05-03)
55
57
  - [Fixed](#fixed-2)
56
58
  - [1.6.0 (2020-04-17)](#160-2020-04-17)
57
- - [Added](#added-17)
59
+ - [Added](#added-18)
58
60
  - [Changes](#changes-1)
59
61
  - [1.5.0 (2020-04-12)](#150-2020-04-12)
60
- - [Added](#added-18)
61
- - [1.4.0 (2020-04-12)](#140-2020-04-12)
62
62
  - [Added](#added-19)
63
- - [1.3.0 (2020-04-12)](#130-2020-04-12)
63
+ - [1.4.0 (2020-04-12)](#140-2020-04-12)
64
64
  - [Added](#added-20)
65
- - [1.2.0 (2020-04-12)](#120-2020-04-12)
65
+ - [1.3.0 (2020-04-12)](#130-2020-04-12)
66
66
  - [Added](#added-21)
67
- - [1.1.0 (2020-04-09)](#110-2020-04-09)
67
+ - [1.2.0 (2020-04-12)](#120-2020-04-12)
68
68
  - [Added](#added-22)
69
+ - [1.1.0 (2020-04-09)](#110-2020-04-09)
70
+ - [Added](#added-23)
69
71
  - [Fixed](#fixed-3)
70
72
  - [1.0.0 (2020-03-16)](#100-2020-03-16)
71
- - [Added](#added-23)
72
- - [0.6.0 (2020-01-06)](#060-2020-01-06)
73
73
  - [Added](#added-24)
74
- - [0.5.0 (2020-01-04)](#050-2020-01-04)
74
+ - [0.6.0 (2020-01-06)](#060-2020-01-06)
75
75
  - [Added](#added-25)
76
- - [0.4.0 (2020-01-03)](#040-2020-01-03)
76
+ - [0.5.0 (2020-01-04)](#050-2020-01-04)
77
77
  - [Added](#added-26)
78
- - [0.3.0 (2020-01-03)](#030-2020-01-03)
78
+ - [0.4.0 (2020-01-03)](#040-2020-01-03)
79
79
  - [Added](#added-27)
80
+ - [0.3.0 (2020-01-03)](#030-2020-01-03)
81
+ - [Added](#added-28)
80
82
  - [Breaking Changes](#breaking-changes-4)
81
83
  - [0.2.0 (2020-01-02)](#020-2020-01-02)
82
- - [Added](#added-28)
83
- - [0.1.0 (2019-12-26)](#010-2019-12-26)
84
84
  - [Added](#added-29)
85
+ - [0.1.0 (2019-12-26)](#010-2019-12-26)
86
+ - [Added](#added-30)
85
87
 
86
88
  ## Unreleased
87
89
 
@@ -93,6 +95,90 @@ This project follows [semver 2.0.0](http://semver.org/spec/v2.0.0.html) and the
93
95
  ### Fixed
94
96
  -->
95
97
 
98
+ 5.8.0 (2021-09-22)
99
+ ------------------
100
+
101
+ ### Added
102
+
103
+ * [#66](https://github.com/serradura/kind/pull/66) - Add `Kind::Any` to make easier the verification of a value in a list (array) of expected values.
104
+ ```ruby
105
+ require 'kind/any'
106
+
107
+ Level = Kind::Any[:low, :high] # or Kind::Any.new([:low, :high])
108
+
109
+ Level === :low # true
110
+ Level === :high # true
111
+
112
+ Level === :foo # false
113
+
114
+ Level[:low] # :low
115
+ Level[:high] # :high
116
+
117
+ Level[:foo] # Kind::Error (:foo expected to be a kind of Kind::Any[:low, :high])
118
+
119
+ level_or_any_symbol = # (Kind::Any[:low, :high] | Symbol)
120
+
121
+ Level.name # 'Kind::Any[:low, :high]'
122
+ Level.inspect # 'Kind::Any[:low, :high]'
123
+
124
+ Level.values # [:low, :high]
125
+ ```
126
+
127
+ * [#66](https://github.com/serradura/kind/pull/66) - Make `Kind.assert_hash!(hash, schema:)` works with a `Kind::Object`.
128
+ ```ruby
129
+ require 'kind/enum'
130
+
131
+ module Level
132
+ include Kind::Enum.from_array([:low, :medium, :high], use_index_as_value: false)
133
+ end
134
+
135
+ Level.keys # ["low", "medium", "high"]
136
+ Level.values # [:low, :medium, :high]
137
+
138
+ # ---
139
+
140
+ module Status
141
+ include Kind::Enum.from_array([:open, :closed], use_index_as_value: true)
142
+ end
143
+
144
+ Status.keys # ["open", "closed"]
145
+ Status.values # [0, 1]
146
+ ```
147
+
148
+ * [#66](https://github.com/serradura/kind/pull/66) - Make `Kind.assert_hash!(hash, schema:)` works with a `Kind::Object`.
149
+ ```ruby
150
+ FilledString = begin
151
+ filled_string = ->(value) {value.is_a?(String) && value.present?}
152
+
153
+ Kind::Of(filled_string, name: 'FilledString')
154
+ end
155
+
156
+ Kind.assert_hash!(some_hash, schema: {
157
+ string: FilledString,
158
+ callable: Kind::Callable,
159
+ })
160
+ ```
161
+
162
+ * [#66](https://github.com/serradura/kind/pull/66) - Improve the exception messages of `Kind.assert_hash!(hash, schema:)`.
163
+ ```ruby
164
+ Kind.assert_hash!({status: 1}, schema: {status: Kind::String | Symbol})
165
+ # Kind::Error (The key :status has an invalid value. Expected: (String | Symbol))
166
+
167
+ Kind.assert_hash!({status: 'closed'}, schema: {status: 'active'})
168
+ # Kind::Error (The key :status has an invalid value. Expected: active, Given: closed)
169
+
170
+ Kind.assert_hash!({callable: 1}, schema: {callable: Kind::Callable})
171
+ # Kind::Error (The key :callable has an invalid value. Expected: Callable)
172
+ ```
173
+
174
+ * [#66](https://github.com/serradura/kind/pull/66) - Make `Kind.assert_hash!(hash, **options)` raises an error if the given hash be empty.
175
+ ```ruby
176
+ Kind.assert_hash!({}, keys: []) # ArgumentError (hash can't be empty)
177
+ Kind.assert_hash!({}, schema: {}) # ArgumentError (hash can't be empty)
178
+ ```
179
+
180
+ [⬆️  Back to Top](#changelog-)
181
+
96
182
  5.7.0 (2021-06-22)
97
183
  ------------------
98
184
 
data/Gemfile CHANGED
@@ -20,7 +20,7 @@ simplecov_version =
20
20
  case RUBY_VERSION
21
21
  when /\A2.[123]/ then '0.17.1'
22
22
  when /\A2.4/ then '~> 0.18.5'
23
- else '~> 0.19'
23
+ else '~> 0.21.2'
24
24
  end
25
25
 
26
26
  is_ruby_2_1 = RUBY_VERSION <= '2.2.0'
data/README.md CHANGED
@@ -8,8 +8,8 @@
8
8
  <img alt="Gem" src="https://img.shields.io/gem/v/kind.svg?style=flat-square">
9
9
  </a>
10
10
 
11
- <a href="https://travis-ci.com/serradura/kind">
12
- <img alt="Build Status" src="https://travis-ci.com/serradura/kind.svg?branch=master">
11
+ <a href="https://github.com/serradura/kind/actions/workflows/ci.yml">
12
+ <img alt="Build Status" src="https://github.com/serradura/kind/actions/workflows/ci.yml/badge.svg">
13
13
  </a>
14
14
 
15
15
  <br />
@@ -42,7 +42,7 @@ So, I invite you to check out these features to see how they could be useful for
42
42
  Version | Documentation
43
43
  ---------- | -------------
44
44
  unreleased | https://github.com/serradura/kind/blob/main/README.md
45
- 5.7.0 | https://github.com/serradura/kind/blob/v5.x/README.md
45
+ 5.8.0 | https://github.com/serradura/kind/blob/v5.x/README.md
46
46
  4.1.0 | https://github.com/serradura/kind/blob/v4.x/README.md
47
47
  3.1.0 | https://github.com/serradura/kind/blob/v3.x/README.md
48
48
  2.3.0 | https://github.com/serradura/kind/blob/v2.x/README.md
@@ -125,7 +125,7 @@ unreleased | https://github.com/serradura/kind/blob/main/README.md
125
125
  | kind | branch | ruby | activemodel |
126
126
  | -------------- | ------- | ------------------ | -------------- |
127
127
  | unreleased | main | >= 2.1.0, <= 3.0.0 | >= 3.2, < 7.0 |
128
- | 5.7.0 | v5.x | >= 2.1.0, <= 3.0.0 | >= 3.2, < 7.0 |
128
+ | 5.8.0 | v5.x | >= 2.1.0, <= 3.0.0 | >= 3.2, < 7.0 |
129
129
  | 4.1.0 | v4.x | >= 2.2.0, <= 3.0.0 | >= 3.2, < 7.0 |
130
130
  | 3.1.0 | v3.x | >= 2.2.0, <= 2.7 | >= 3.2, < 7.0 |
131
131
  | 2.3.0 | v2.x | >= 2.2.0, <= 2.7 | >= 3.2, <= 6.0 |
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ # Borrowed from https://gist.github.com/qortex/7e7c49f3731391a91ee898336183acef
4
+
5
+ # Temporary hack to get CodeClimate to work with SimpleCov 0.18 JSON format until issue is fixed
6
+ # upstream: https://github.com/codeclimate/test-reporter/issues/413
7
+
8
+ require "json"
9
+
10
+ filename = "coverage/.resultset.json"
11
+ contents = JSON.parse(File.read(filename))
12
+
13
+ def remove_lines_key(obj)
14
+ case obj
15
+ when Hash
16
+ obj.transform_values do |val|
17
+ val.is_a?(Hash) && val.key?("lines") ? val["lines"] : remove_lines_key(val)
18
+ end
19
+ else
20
+ obj
21
+ end
22
+ end
23
+
24
+ # overwrite
25
+ File.write(filename, JSON.generate(remove_lines_key(contents)))
26
+
27
+ puts Dir['coverage/.*.json']
data/bin/test ADDED
@@ -0,0 +1,76 @@
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ RUBY_V=$(ruby -v)
6
+
7
+ function reset_gemfile_and_test {
8
+ rm Gemfile.lock
9
+
10
+ eval "$1 bundle update"
11
+ eval "$1 bundle exec rake test"
12
+ }
13
+
14
+ function test_with_activemodel {
15
+ reset_gemfile_and_test "ACTIVEMODEL_VERSION=$1"
16
+ }
17
+
18
+ function run_tests_by_modules {
19
+ rm Gemfile.lock
20
+
21
+ bundle update
22
+
23
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/{basic/*_test,basic_test}.rb'"
24
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/enum_test.rb'"
25
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/presence_test.rb'"
26
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/dig_test.rb'"
27
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/try_test.rb'"
28
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/maybe_test.rb'"
29
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/immutable_attributes_test.rb'"
30
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/function_test.rb'"
31
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/action_test.rb'"
32
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/{functional/*_test,functional_test}.rb'"
33
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/either/*_test.rb'"
34
+ eval "KIND_BASIC=t bundle exec rake test TEST='test/kind/result/*_test.rb'"
35
+
36
+ eval "KIND_STRICT=t bundle exec rake test TEST='test/kind/strict_disabled_test.rb'"
37
+ }
38
+
39
+ RUBY_2_12345="ruby 2.[12345]."
40
+ RUBY_2_2345="ruby 2.[2345]."
41
+ RUBY_2_1234="ruby 2.[1234]."
42
+ RUBY_2_567="ruby 2.[567]."
43
+ RUBY_2_12="ruby 2.[12]."
44
+ RUBY_3_X="ruby 3.0."
45
+
46
+ if [[ $RUBY_V =~ $RUBY_2_12345 ]]; then
47
+ if [[ $RUBY_V =~ $RUBY_2_12 ]]; then
48
+ test_with_activemodel "3.2"
49
+ fi
50
+
51
+ if [[ $RUBY_V =~ $RUBY_2_2345 ]]; then
52
+ test_with_activemodel "4.0"
53
+ test_with_activemodel "4.1"
54
+ test_with_activemodel "4.2"
55
+ test_with_activemodel "5.0"
56
+ test_with_activemodel "5.1"
57
+ test_with_activemodel "5.2"
58
+ fi
59
+
60
+ if [[ $RUBY_V =~ $RUBY_2_1234 ]]; then
61
+ run_tests_by_modules
62
+
63
+ reset_gemfile_and_test
64
+ fi
65
+ fi
66
+
67
+ if [[ $RUBY_V =~ $RUBY_2_567 ]] || [[ $RUBY_V =~ $RUBY_3_X ]]; then
68
+ gem install bundler -v ">= 2" --no-doc
69
+
70
+ test_with_activemodel "6.0"
71
+ test_with_activemodel "6.1"
72
+
73
+ run_tests_by_modules
74
+
75
+ reset_gemfile_and_test
76
+ fi
@@ -0,0 +1,92 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ module AssertHash
5
+ module Keys
6
+ def self.require_all(keys, hash)
7
+ expected_keys = keys - hash.keys
8
+
9
+ unless expected_keys.empty?
10
+ raise KeyError.new("#{hash.inspect} expected to have these keys: #{expected_keys}")
11
+ end
12
+
13
+ unexpected_keys = hash.keys - keys
14
+
15
+ unless unexpected_keys.empty?
16
+ raise KeyError.new("#{hash.inspect} expected to NOT have these keys: #{unexpected_keys}")
17
+ end
18
+
19
+ hash
20
+ end
21
+ end
22
+
23
+ module Schema
24
+ extend self
25
+
26
+ KindObject = ->(value) do
27
+ defined?(Kind::Object) ? Kind::Object === value : false
28
+ end
29
+
30
+ KindUnionType = ->(value) do
31
+ defined?(Kind::UnionType) ? Kind::UnionType === value : false
32
+ end
33
+
34
+ def any(hash, spec)
35
+ spec.each do |key, expected|
36
+ value = hash[key]
37
+ error_message = "The key #{key.inspect} has an invalid value"
38
+
39
+ case expected
40
+ when KindUnionType, KindObject then assert_kind_object(expected, value, error_message)
41
+ when ::Module then assert_kind_of(expected, value, error_message)
42
+ when ::Proc then assert(expected.call(value), error_message)
43
+ when ::Regexp then assert_match(expected, value, error_message)
44
+ when ::NilClass then assert_nil(value, error_message)
45
+ else assert_equal(expected, value, error_message)
46
+ end
47
+ end
48
+
49
+ hash
50
+ end
51
+
52
+ def all(hash, spec)
53
+ Keys.require_all(spec.keys, hash)
54
+
55
+ any(hash, spec)
56
+ end
57
+
58
+ private
59
+
60
+ def assert_equal(expected, value, message)
61
+ raise_kind_error("#{message}. Expected: #{expected}, Given: #{value}") if expected != value
62
+ end
63
+
64
+ def assert(value, message)
65
+ raise_kind_error(message) unless value
66
+ end
67
+
68
+ def assert_nil(value, message)
69
+ raise_kind_error("#{message}. Expected: nil") unless value.nil?
70
+ end
71
+
72
+ def assert_match(expected, value, message)
73
+ STRICT.kind_of(String, value)
74
+
75
+ raise_kind_error("#{message}. Expected: #{expected}") if value !~ expected
76
+ end
77
+
78
+ def assert_kind_of(expected, value, message)
79
+ raise_kind_error("#{message}. Expected: #{expected}") unless expected === value
80
+ end
81
+
82
+ def assert_kind_object(expected, value, message)
83
+ raise_kind_error("#{message}. Expected: #{expected.name}") unless expected === value
84
+ end
85
+
86
+
87
+ def raise_kind_error(message)
88
+ raise Error.new(message)
89
+ end
90
+ end
91
+ end
92
+ end
@@ -6,16 +6,16 @@ module Kind
6
6
  module STRICT
7
7
  extend self
8
8
 
9
- require 'kind/__lib__/assert_hash_schema'
9
+ require 'kind/__lib__/assert_hash'
10
10
 
11
11
  def error(kind_name, value, label = nil) # :nodoc:
12
12
  raise Error.new(kind_name, value, label: label)
13
13
  end
14
14
 
15
- def object_is_a(kind, value, label = nil) # :nodoc:
15
+ def object_is_a(kind, value, label = nil, expected = nil) # :nodoc:
16
16
  return value if kind === value
17
17
 
18
- error(kind.name, value, label)
18
+ error(expected || kind.name, value, label)
19
19
  end
20
20
 
21
21
  def kind_of(kind, value, kind_name = nil) # :nodoc:
@@ -53,12 +53,17 @@ module Kind
53
53
  end
54
54
 
55
55
  def assert_hash!(hash, options)
56
+ check_keys = options.key?(:keys)
57
+ check_schema = options.key?(:schema)
58
+
59
+ raise ArgumentError, ':keys or :schema is missing' if !check_keys && !check_schema
60
+ raise ArgumentError, "hash can't be empty" if hash.empty?
61
+
56
62
  require_all = options[:require_all]
57
63
 
58
- return assert_hash_keys!(hash, options[:keys], require_all) if options.key?(:keys)
59
- return assert_hash_schema!(hash, options[:schema], require_all) if options.key?(:schema)
64
+ return assert_hash_keys!(hash, options[:keys], require_all) if check_keys
60
65
 
61
- raise ArgumentError, ':keys or :schema is missing'
66
+ assert_hash_schema!(hash, options[:schema], require_all)
62
67
  end
63
68
 
64
69
  private
@@ -66,7 +71,7 @@ module Kind
66
71
  def assert_hash_keys!(hash, arg, require_all)
67
72
  keys = Array(arg)
68
73
 
69
- ASSERT_HASH_KEYS.require_all(keys, hash) if require_all
74
+ AssertHash::Keys.require_all(keys, hash) if require_all
70
75
 
71
76
  hash.each_key do |k|
72
77
  unless keys.include?(k)
@@ -76,9 +81,9 @@ module Kind
76
81
  end
77
82
 
78
83
  def assert_hash_schema!(hash, schema, require_all)
79
- return ASSERT_HASH_SCHEMA.all(hash, schema) if require_all
84
+ return AssertHash::Schema.all(hash, schema) if require_all
80
85
 
81
- ASSERT_HASH_SCHEMA.any(hash, schema)
86
+ AssertHash::Schema.any(hash, schema)
82
87
  end
83
88
  end
84
89
 
data/lib/kind/any.rb ADDED
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Kind
4
+ class Any
5
+ FilledArray = ->(value) {value.is_a?(::Array) && !value.empty?}
6
+
7
+ singleton_class.send(:alias_method, :[], :new)
8
+
9
+ attr_reader :values
10
+
11
+ def initialize(*args)
12
+ array = args.size == 1 ? args[0] : args
13
+
14
+ @values = Kind.of(FilledArray, array, expected: 'filled array')
15
+ end
16
+
17
+ def ===(other)
18
+ @values.any? { |value| value == other }
19
+ end
20
+
21
+ def [](value, label: nil)
22
+ STRICT.object_is_a(self, value, label)
23
+ end
24
+
25
+ def |(another_kind)
26
+ UnionType[self] | another_kind
27
+ end
28
+
29
+ def name
30
+ "Kind::Any#{@values}"
31
+ end
32
+
33
+ alias inspect name
34
+
35
+ private_constant :FilledArray
36
+ end
37
+ end
data/lib/kind/basic.rb CHANGED
@@ -48,8 +48,8 @@ module Kind
48
48
  KIND.interface?(method_names, value)
49
49
  end
50
50
 
51
- def of(kind, value, label: nil)
52
- STRICT.object_is_a(kind, value, label)
51
+ def of(kind, value, label: nil, expected: nil)
52
+ STRICT.object_is_a(kind, value, label, expected)
53
53
  end
54
54
 
55
55
  alias_method :of!, :of
@@ -33,7 +33,7 @@ module Kind
33
33
  end
34
34
 
35
35
  def key?(arg)
36
- arg.respond_to?(:to_sym) ? ref?(arg) && !value?(arg) : false
36
+ arg.respond_to?(:to_sym) ? ENUM__KEYS.member?(arg.to_s) : false
37
37
  end
38
38
 
39
39
  def value?(arg)
data/lib/kind/enum.rb CHANGED
@@ -11,50 +11,58 @@ module Kind
11
11
  extend self
12
12
 
13
13
  def values(input)
14
- enum_module = ::Module.new
14
+ __create(input)
15
+ end
15
16
 
16
- enum_items =
17
- case input
18
- when ::Hash then create_from_hash(input)
19
- when ::Array then create_from_array(input)
20
- else raise ArgumentError, 'use an array or hash to define a Kind::Enum'
21
- end
17
+ def from_array(input, use_index_as_value:)
18
+ __create(input, use_index_as_value)
19
+ end
22
20
 
23
- enum_items.each { |item| enum_module.const_set(item.name, item) }
21
+ private
24
22
 
25
- enum_map = enum_items.each_with_object({}) do |item, memo|
26
- memo[item.to_s] = item
27
- memo[item.value] = item
28
- memo[item.to_sym] = item
29
- end
23
+ def __create(input, use_index_as_value = true)
24
+ enum_module = ::Module.new
30
25
 
31
- enum_module.const_set(:ENUM__MAP, enum_map)
32
- enum_module.const_set(:ENUM__HASH, enum_items.map(&:to_ary).to_h.freeze)
33
- enum_module.const_set(:ENUM__KEYS, ::Set.new(enum_items.map(&:key)).freeze)
34
- enum_module.const_set(:ENUM__VALS, ::Set.new(enum_items.map(&:value)).freeze)
35
- enum_module.const_set(:ENUM__REFS, ::Set.new(enum_map.keys))
36
- enum_module.const_set(:ENUM__ITEMS, enum_items.freeze)
26
+ enum_items =
27
+ case input
28
+ when ::Hash then __create_from_hash(input)
29
+ when ::Array then __create_from_array(input, use_index_as_value)
30
+ else raise ArgumentError, 'use an array or hash to define a Kind::Enum'
31
+ end
37
32
 
38
- enum_module.send(:private_constant, :ENUM__MAP, :ENUM__HASH, :ENUM__KEYS,
39
- :ENUM__VALS, :ENUM__REFS, :ENUM__ITEMS)
33
+ enum_items.each { |item| enum_module.const_set(item.name, item) }
40
34
 
41
- enum_module.module_eval(METHODS)
35
+ enum_map = enum_items.each_with_object({}) do |item, memo|
36
+ memo[item.to_s] = item
37
+ memo[item.value] = item
38
+ memo[item.to_sym] = item
39
+ end
42
40
 
43
- enum_module.extend(enum_module)
44
- enum_module
45
- end
41
+ enum_module.const_set(:ENUM__MAP, enum_map)
42
+ enum_module.const_set(:ENUM__HASH, enum_items.map(&:to_ary).to_h.freeze)
43
+ enum_module.const_set(:ENUM__KEYS, ::Set.new(enum_items.map(&:key)).freeze)
44
+ enum_module.const_set(:ENUM__VALS, ::Set.new(enum_items.map(&:value)).freeze)
45
+ enum_module.const_set(:ENUM__REFS, ::Set.new(enum_map.keys))
46
+ enum_module.const_set(:ENUM__ITEMS, enum_items.freeze)
46
47
 
47
- private
48
+ enum_module.send(:private_constant, :ENUM__MAP, :ENUM__HASH, :ENUM__KEYS,
49
+ :ENUM__VALS, :ENUM__REFS, :ENUM__ITEMS)
50
+
51
+ enum_module.module_eval(METHODS)
52
+
53
+ enum_module.extend(enum_module)
54
+ enum_module
55
+ end
48
56
 
49
- def create_from_hash(input)
50
- input.map { |key, value| build_item(key, value) }
57
+ def __create_from_hash(input)
58
+ input.map { |key, value| __item(key, value) }
51
59
  end
52
60
 
53
- def create_from_array(input)
54
- input.map.with_index { |key, index| build_item(key, index) }
61
+ def __create_from_array(input, use_index_as_value)
62
+ input.map.with_index { |key, index| use_index_as_value ? __item(key, index) : __item(key, key) }
55
63
  end
56
64
 
57
- def build_item(key, value)
65
+ def __item(key, value)
58
66
  return Item.new(key, value) if key.respond_to?(:to_sym)
59
67
 
60
68
  raise ArgumentError, 'use a string or symbol to define a Kind::Enum item'
@@ -13,7 +13,7 @@ module Kind
13
13
  :assert_hash!
14
14
  ].each { |method_name| remove_method(method_name) }
15
15
 
16
- def object_is_a(_kind, value, _label = nil) # :nodoc:
16
+ def object_is_a(_kind, value, _label = nil, _expected = nil) # :nodoc:
17
17
  value
18
18
  end
19
19
 
data/lib/kind/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Kind
4
- VERSION = '5.7.0'
4
+ VERSION = '5.8.0'
5
5
  end
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: 5.7.0
4
+ version: 5.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Serradura
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-06-22 00:00:00.000000000 Z
11
+ date: 2021-09-22 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A development toolkit for Ruby with several small/cohesive abstractions
14
14
  (monads, enums, business logic, data validation...) to empower your development
@@ -19,10 +19,10 @@ executables: []
19
19
  extensions: []
20
20
  extra_rdoc_files: []
21
21
  files:
22
+ - ".github/workflows/ci.yml"
22
23
  - ".gitignore"
23
24
  - ".tool-versions"
24
- - ".travis.sh"
25
- - ".travis.yml"
25
+ - ".vscode/settings.json"
26
26
  - CHANGELOG.md
27
27
  - CODE_OF_CONDUCT.md
28
28
  - Gemfile
@@ -30,11 +30,13 @@ files:
30
30
  - README.md
31
31
  - Rakefile
32
32
  - bin/console
33
+ - bin/prepare_coverage
33
34
  - bin/setup
35
+ - bin/test
34
36
  - kind.gemspec
35
37
  - lib/kind.rb
36
38
  - lib/kind/__lib__/action_steps.rb
37
- - lib/kind/__lib__/assert_hash_schema.rb
39
+ - lib/kind/__lib__/assert_hash.rb
38
40
  - lib/kind/__lib__/attributes.rb
39
41
  - lib/kind/__lib__/kind.rb
40
42
  - lib/kind/__lib__/of.rb
@@ -42,6 +44,7 @@ files:
42
44
  - lib/kind/__lib__/undefined.rb
43
45
  - lib/kind/action.rb
44
46
  - lib/kind/active_model/validation.rb
47
+ - lib/kind/any.rb
45
48
  - lib/kind/basic.rb
46
49
  - lib/kind/basic/error.rb
47
50
  - lib/kind/basic/undefined.rb
@@ -120,14 +123,13 @@ files:
120
123
  - lib/kind/try.rb
121
124
  - lib/kind/validator.rb
122
125
  - lib/kind/version.rb
123
- - test.sh
124
126
  homepage: https://github.com/serradura/kind
125
127
  licenses:
126
128
  - MIT
127
129
  metadata:
128
130
  homepage_uri: https://github.com/serradura/kind
129
131
  source_code_uri: https://github.com/serradura/kind
130
- post_install_message:
132
+ post_install_message:
131
133
  rdoc_options: []
132
134
  require_paths:
133
135
  - lib
@@ -143,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
143
145
  version: '0'
144
146
  requirements: []
145
147
  rubygems_version: 3.2.11
146
- signing_key:
148
+ signing_key:
147
149
  specification_version: 4
148
150
  summary: A development toolkit for Ruby with several small/cohesive abstractions to
149
151
  empower your development workflow.
data/.travis.sh DELETED
@@ -1,77 +0,0 @@
1
- #!/bin/bash
2
-
3
- RUBY_V=$(ruby -v)
4
-
5
- function run_basic_tests {
6
- if [ ! -z "$1" ]; then
7
- bundle_cmd="bundle _$1_"
8
- else
9
- bundle_cmd="bundle"
10
- fi
11
-
12
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/{basic/*_test,basic_test}.rb'"
13
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/enum_test.rb'"
14
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/presence_test.rb'"
15
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/dig_test.rb'"
16
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/try_test.rb'"
17
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/maybe_test.rb'"
18
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/immutable_attributes_test.rb'"
19
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/function_test.rb'"
20
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/action_test.rb'"
21
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/{functional/*_test,functional_test}.rb'"
22
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/either/*_test.rb'"
23
- eval "KIND_BASIC=t $bundle_cmd exec rake test TEST='test/kind/result/*_test.rb'"
24
-
25
- eval "KIND_STRICT=t $bundle_cmd exec rake test TEST='test/kind/strict_disabled_test.rb'"
26
- }
27
-
28
- function run_with_bundler {
29
- rm Gemfile.lock
30
-
31
- if [ ! -z "$1" ]; then
32
- bundle_cmd="bundle _$1_"
33
- else
34
- bundle_cmd="bundle"
35
- fi
36
-
37
- eval "$2 $bundle_cmd update"
38
- eval "$2 $bundle_cmd exec rake test"
39
- }
40
-
41
- function run_with_am_version_and_bundler {
42
- run_with_bundler "$2" "ACTIVEMODEL_VERSION=$1"
43
- }
44
-
45
- RUBY_2_12="ruby 2.[12]."
46
- RUBY_2_2345="ruby 2.[2345]."
47
- RUBY_2_12345="ruby 2.[12345]."
48
- RUBY_2_567="ruby 2.[567]."
49
- RUBY_3_0="ruby 3.0."
50
-
51
- if [[ $RUBY_V =~ $RUBY_2_12 ]]; then
52
- run_with_am_version_and_bundler "3.2" "$BUNDLER_V1"
53
- fi
54
-
55
- if [[ $RUBY_V =~ $RUBY_2_2345 ]]; then
56
- run_with_am_version_and_bundler "4.0" "$BUNDLER_V1"
57
- run_with_am_version_and_bundler "4.1" "$BUNDLER_V1"
58
- run_with_am_version_and_bundler "4.2" "$BUNDLER_V1"
59
- run_with_am_version_and_bundler "5.0" "$BUNDLER_V1"
60
- run_with_am_version_and_bundler "5.1" "$BUNDLER_V1"
61
- run_with_am_version_and_bundler "5.2" "$BUNDLER_V1"
62
- fi
63
-
64
- if [[ $RUBY_V =~ $RUBY_2_12345 ]]; then
65
- run_basic_tests "$BUNDLER_V1"
66
- run_with_bundler "$BUNDLER_V1"
67
- fi
68
-
69
- if [[ $RUBY_V =~ $RUBY_2_567 ]] || [[ $RUBY_V =~ $RUBY_3_0 ]]; then
70
- gem install bundler -v ">= 2" --no-doc
71
-
72
- run_with_am_version_and_bundler "6.0"
73
- run_with_am_version_and_bundler "6.1"
74
-
75
- run_basic_tests
76
- run_with_bundler
77
- fi
data/.travis.yml DELETED
@@ -1,35 +0,0 @@
1
- ---
2
- language: ruby
3
-
4
- cache:
5
- bundler: true
6
- directories:
7
- - /home/travis/.rvm/
8
-
9
- rvm:
10
- - 2.1.10
11
- - 2.2.2
12
- - 2.3.0
13
- - 2.4.0
14
- - 2.5.0
15
- - 2.6.0
16
- - 2.7.0
17
- - 3.0.0
18
-
19
- env:
20
- - BUNDLER_V1="1.17.3"
21
-
22
- before_install:
23
- - gem install bundler -v "$BUNDLER_V1"
24
-
25
- install: bundle install --jobs=3 --retry=3
26
-
27
- before_script:
28
- - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
29
- - chmod +x ./cc-test-reporter
30
- - "./cc-test-reporter before-build"
31
-
32
- script: "./.travis.sh"
33
-
34
- after_success:
35
- - "./cc-test-reporter after-build -t simplecov"
@@ -1,81 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Kind
4
- module ASSERT_HASH_KEYS
5
- def self.require_all(keys, hash)
6
- expected_keys = keys - hash.keys
7
-
8
- unless expected_keys.empty?
9
- raise KeyError.new("#{hash.inspect} expected to have these keys: #{expected_keys}")
10
- end
11
-
12
- unexpected_keys = hash.keys - keys
13
-
14
- unless unexpected_keys.empty?
15
- raise KeyError.new("#{hash.inspect} expected to NOT have these keys: #{unexpected_keys}")
16
- end
17
-
18
- hash
19
- end
20
- end
21
-
22
- module ASSERT_HASH_SCHEMA
23
- extend self
24
-
25
- UnionType = ->(value) do
26
- defined?(Kind::UnionType) ? Kind::UnionType === value : false
27
- end
28
-
29
- def any(hash, spec)
30
- spec.each do |key, expected|
31
- value = hash[key]
32
- error_message = "The key #{key.inspect} has an invalid value"
33
-
34
- case expected
35
- when ::Module then assert_kind_of(expected, value, error_message)
36
- when ::Proc then assert(expected.call(value), error_message)
37
- when ::Regexp then assert_match(expected, value, error_message)
38
- when ::NilClass then assert_nil(value, error_message)
39
- when UnionType then assert(expected === value, error_message)
40
- else assert_equal(expected, value, error_message)
41
- end
42
- end
43
-
44
- hash
45
- end
46
-
47
- def all(hash, spec)
48
- ASSERT_HASH_KEYS.require_all(spec.keys, hash)
49
-
50
- any(hash, spec)
51
- end
52
-
53
- private
54
-
55
- def assert_equal(expected, value, message)
56
- raise_kind_error(message) if expected != value
57
- end
58
-
59
- def assert(value, message)
60
- raise_kind_error(message) unless value
61
- end
62
-
63
- def assert_nil(value, message)
64
- raise_kind_error(message) unless value.nil?
65
- end
66
-
67
- def assert_match(expected, value, message)
68
- STRICT.kind_of(String, value)
69
-
70
- raise_kind_error(message) if value !~ expected
71
- end
72
-
73
- def assert_kind_of(expected, value, message)
74
- raise_kind_error(message) unless expected === value
75
- end
76
-
77
- def raise_kind_error(message)
78
- raise Error.new(message)
79
- end
80
- end
81
- end
data/test.sh DELETED
@@ -1,11 +0,0 @@
1
- #!/bin/bash
2
-
3
- source $(dirname $0)/.travis.sh
4
-
5
- echo ''
6
- echo 'Resetting Gemfile'
7
- echo ''
8
-
9
- rm Gemfile.lock
10
-
11
- bundle