kind 5.7.0 → 5.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 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