contracted_value 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CODEOWNERS +13 -0
- data/.github/FUNDING.yml +2 -0
- data/.github/dependabot.yml +20 -0
- data/.github/workflows/coverage.yml +63 -0
- data/.github/workflows/tests.yaml +53 -0
- data/Appraisals +2 -6
- data/CHANGELOG.md +22 -1
- data/README.md +52 -16
- data/contracted_value.gemspec +8 -8
- data/gemfiles/{contracts_15_0.gemfile → contracts_17_0.gemfile} +1 -1
- data/lib/contracted_value/core.rb +18 -9
- data/lib/contracted_value/version.rb +1 -1
- data/spec/contracted_value/value_spec.rb +145 -169
- data/spec/spec_helper.rb +17 -7
- metadata +31 -22
- data/.travis.yml +0 -25
- data/gemfiles/contracts_16_0.gemfile +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1955c7fa4eaf8ae64db37e57575a6da241315ebd5855d72097e8e175292d0ee3
|
4
|
+
data.tar.gz: d34b3b78b78e7e27466468851e96968293e978cadfc40104e3a67425e69eb4a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 125f0ff78bdf35d47b2fd7400ebb93db3a249d0b04abe1462394b732ad1d804326d7d89c7b04e0d3ca28cb738bc1f350a5091d2ae559490cfea468b864a1d03d
|
7
|
+
data.tar.gz: 184cd1009cbd96af31d5fce7c075c483ce4762fc77936843c66a13df2c43b0aa95e70fe14e5e7c8ddaea1ebaf6a85084fc0345479af1e2a273cab6ca8942f64d
|
data/.github/CODEOWNERS
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Lines starting with '#' are comments.
|
2
|
+
# Each line is a file pattern followed by one or more owners.
|
3
|
+
|
4
|
+
# These owners will be the default owners for everything in the repo.
|
5
|
+
* @PikachuEXE
|
6
|
+
|
7
|
+
# Order is important. The last matching pattern has the most precedence.
|
8
|
+
# So if a pull request only touches javascript files, only these owners
|
9
|
+
# will be requested to review.
|
10
|
+
# *.rb @PikachuEXE
|
11
|
+
|
12
|
+
# You can also use email addresses if you prefer.
|
13
|
+
# docs/* docs@example.com
|
data/.github/FUNDING.yml
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
version: 2
|
2
|
+
updates:
|
3
|
+
- package-ecosystem: bundler
|
4
|
+
directory: "/"
|
5
|
+
schedule:
|
6
|
+
interval: monthly
|
7
|
+
time: "06:00"
|
8
|
+
timezone: Asia/Hong_Kong
|
9
|
+
open-pull-requests-limit: 10
|
10
|
+
labels:
|
11
|
+
- "dependencies"
|
12
|
+
- package-ecosystem: github-actions
|
13
|
+
directory: "/"
|
14
|
+
schedule:
|
15
|
+
interval: monthly
|
16
|
+
time: "06:00"
|
17
|
+
timezone: Asia/Hong_Kong
|
18
|
+
open-pull-requests-limit: 10
|
19
|
+
labels:
|
20
|
+
- "dependencies"
|
@@ -0,0 +1,63 @@
|
|
1
|
+
name: Coverage
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
paths-ignore:
|
8
|
+
- 'README.md'
|
9
|
+
push:
|
10
|
+
branches:
|
11
|
+
- master
|
12
|
+
paths-ignore:
|
13
|
+
- 'README.md'
|
14
|
+
|
15
|
+
jobs:
|
16
|
+
coverage:
|
17
|
+
name: Coverage
|
18
|
+
# Homemade support for [ci skip] no longer needed
|
19
|
+
# https://github.blog/changelog/2021-02-08-github-actions-skip-pull-request-and-push-workflows-with-skip-ci/
|
20
|
+
# if: "contains(github.event.commits[0].message, '[ci skip]') == false"
|
21
|
+
strategy:
|
22
|
+
fail-fast: false
|
23
|
+
matrix:
|
24
|
+
os:
|
25
|
+
- ubuntu-latest
|
26
|
+
ruby:
|
27
|
+
- "3.2"
|
28
|
+
gemfile:
|
29
|
+
- gemfiles/contracts_17_0.gemfile
|
30
|
+
env:
|
31
|
+
BUNDLE_GEMFILE: ${{ matrix.gemfile }}
|
32
|
+
COVERALLS: true
|
33
|
+
runs-on: ${{ matrix.os }}
|
34
|
+
steps:
|
35
|
+
- name: Checkout
|
36
|
+
uses: actions/checkout@v4
|
37
|
+
|
38
|
+
- name: Setup Ruby
|
39
|
+
uses: ruby/setup-ruby@v1
|
40
|
+
with:
|
41
|
+
ruby-version: ${{ matrix.ruby }}
|
42
|
+
bundler-cache: true
|
43
|
+
|
44
|
+
- name: Collect coverage info
|
45
|
+
run: bundle exec rake spec
|
46
|
+
|
47
|
+
- name: Coveralls Parallel
|
48
|
+
uses: coverallsapp/github-action@master
|
49
|
+
continue-on-error: true
|
50
|
+
with:
|
51
|
+
github-token: ${{ secrets.github_token }}
|
52
|
+
flag-name: run-${{ matrix.ruby }}-${{ matrix.gemfile }}
|
53
|
+
parallel: true
|
54
|
+
|
55
|
+
finish:
|
56
|
+
needs: coverage
|
57
|
+
runs-on: ubuntu-latest
|
58
|
+
steps:
|
59
|
+
- name: Send to Coveralls
|
60
|
+
uses: coverallsapp/github-action@master
|
61
|
+
with:
|
62
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
63
|
+
parallel-finished: true
|
@@ -0,0 +1,53 @@
|
|
1
|
+
name: Tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
pull_request:
|
5
|
+
branches:
|
6
|
+
- master
|
7
|
+
paths-ignore:
|
8
|
+
- 'README.md'
|
9
|
+
push:
|
10
|
+
branches:
|
11
|
+
- master
|
12
|
+
paths-ignore:
|
13
|
+
- 'README.md'
|
14
|
+
|
15
|
+
jobs:
|
16
|
+
unit_tests:
|
17
|
+
name: Unit Tests
|
18
|
+
# Homemade support for [ci skip] no longer needed
|
19
|
+
# https://github.blog/changelog/2021-02-08-github-actions-skip-pull-request-and-push-workflows-with-skip-ci/
|
20
|
+
# if: "contains(github.event.commits[0].message, '[ci skip]') == false"
|
21
|
+
strategy:
|
22
|
+
fail-fast: false
|
23
|
+
matrix:
|
24
|
+
os:
|
25
|
+
- ubuntu-latest
|
26
|
+
ruby:
|
27
|
+
- "3.0"
|
28
|
+
- "3.1"
|
29
|
+
- "3.2"
|
30
|
+
gemfile:
|
31
|
+
- gemfiles/contracts_17_0.gemfile
|
32
|
+
allow_failures:
|
33
|
+
- false
|
34
|
+
include:
|
35
|
+
- os: ubuntu-latest
|
36
|
+
ruby: "ruby-head"
|
37
|
+
gemfile: gemfiles/contracts_17_0.gemfile
|
38
|
+
allow_failures: true
|
39
|
+
env:
|
40
|
+
BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
|
41
|
+
ALLOW_FAILURES: "${{ matrix.allow_failures }}"
|
42
|
+
runs-on: ${{ matrix.os }}
|
43
|
+
continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
|
44
|
+
steps:
|
45
|
+
- name: Checkout
|
46
|
+
uses: actions/checkout@v4
|
47
|
+
- name: Setup Ruby
|
48
|
+
uses: ruby/setup-ruby@v1
|
49
|
+
with:
|
50
|
+
ruby-version: ${{ matrix.ruby }}
|
51
|
+
bundler-cache: true
|
52
|
+
- name: Test
|
53
|
+
run: bundle exec rake spec || $ALLOW_FAILURES
|
data/Appraisals
CHANGED
data/CHANGELOG.md
CHANGED
@@ -18,10 +18,31 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
18
18
|
- Nothing
|
19
19
|
|
20
20
|
|
21
|
+
## [0.1.2]
|
22
|
+
|
23
|
+
### Changed
|
24
|
+
|
25
|
+
- Requires Ruby 3.0, contracts >= 0.17 (Ruby 2.7 EOL)
|
26
|
+
- Make code "Object Shape friendly"
|
27
|
+
(https://github.com/PikachuEXE/contracted_value/pull/5)
|
28
|
+
|
29
|
+
|
30
|
+
## [0.1.1]
|
31
|
+
|
32
|
+
### Changed
|
33
|
+
|
34
|
+
- Requires Ruby 2.7 (due to use of ["Forward all arguments" syntax](https://rubyreferences.github.io/rubychanges/2.7.html#keyword-argument-related-changes))
|
35
|
+
|
36
|
+
### Fixed
|
37
|
+
|
38
|
+
- Fix Ruby 3.x compatibility
|
39
|
+
|
40
|
+
|
21
41
|
## 0.1.0 - 2019-06-05
|
22
42
|
|
23
43
|
### Added
|
24
44
|
|
25
45
|
- Initial release
|
26
46
|
|
27
|
-
[
|
47
|
+
[0.1.2]: https://github.com/PikachuEXE/contracted_value/compare/v0.1.1...v0.1.2
|
48
|
+
[0.1.1]: https://github.com/PikachuEXE/contracted_value/compare/v0.1.0...v0.1.1
|
data/README.md
CHANGED
@@ -2,15 +2,6 @@
|
|
2
2
|
|
3
3
|
Library for creating contracted immutable(by default) value objects
|
4
4
|
|
5
|
-
[![Gem Version](http://img.shields.io/gem/v/contracted_value.svg?style=flat-square)](http://badge.fury.io/rb/contracted_value)
|
6
|
-
[![License](https://img.shields.io/github/license/PikachuEXE/contracted_value.svg?style=flat-square)](http://badge.fury.io/rb/contracted_value)
|
7
|
-
|
8
|
-
[![Build Status](http://img.shields.io/travis/PikachuEXE/contracted_value.svg?style=flat-square)](https://travis-ci.org/PikachuEXE/contracted_value)
|
9
|
-
|
10
|
-
[![Code Climate](https://img.shields.io/codeclimate/maintainability/PikachuEXE/contracted_value.svg?style=flat-square)](https://codeclimate.com/github/PikachuEXE/contracted_value)
|
11
|
-
[![Coverage Status](https://img.shields.io/codecov/c/github/PikachuEXE/contracted_value.svg?style=flat-square)](https://codecov.io/gh/PikachuEXE/contracted_value)
|
12
|
-
|
13
|
-
|
14
5
|
This gem allows creation of value objects which are
|
15
6
|
- contracted (enforced by [`contracts.ruby`](https://github.com/egonSchiele/contracts.ruby))
|
16
7
|
- immutable (enforced by [`ice_nine`](https://github.com/dkubb/ice_nine))
|
@@ -18,6 +9,19 @@ This gem allows creation of value objects which are
|
|
18
9
|
See details explanation in below sections
|
19
10
|
|
20
11
|
|
12
|
+
## Status
|
13
|
+
|
14
|
+
[![GitHub Build Status](https://img.shields.io/github/actions/workflow/status/PikachuEXE/contracted_value/tests.yaml?branch=master&style=flat-square)](https://github.com/PikachuEXE/contracted_value/actions/workflows/tests.yaml)
|
15
|
+
|
16
|
+
[![Gem Version](http://img.shields.io/gem/v/contracted_value.svg?style=flat-square)](http://badge.fury.io/rb/contracted_value)
|
17
|
+
[![License](https://img.shields.io/github/license/PikachuEXE/contracted_value.svg?style=flat-square)](http://badge.fury.io/rb/contracted_value)
|
18
|
+
|
19
|
+
[![Code Climate](https://img.shields.io/codeclimate/maintainability/PikachuEXE/contracted_value.svg?style=flat-square)](https://codeclimate.com/github/PikachuEXE/contracted_value)
|
20
|
+
[![Coverage Status](http://img.shields.io/coveralls/PikachuEXE/contracted_value.svg?style=flat-square)](https://coveralls.io/r/PikachuEXE/contracted_value)
|
21
|
+
|
22
|
+
> The above badges are generated by https://shields.io/
|
23
|
+
|
24
|
+
|
21
25
|
## Installation
|
22
26
|
|
23
27
|
Add this line to your application's Gemfile:
|
@@ -146,6 +150,36 @@ location_range = ::Geometry::LocationRange::Entry.new(location)
|
|
146
150
|
|
147
151
|
```
|
148
152
|
|
153
|
+
#### Passing objects of different `ContractedValue::Value` subclasses to `.new`
|
154
|
+
Possible due to the implementation calling `#to_h` for `ContractedValue::Value` objects
|
155
|
+
But in case the attribute names are different, or adding new attributes/updating existing attributes is needed
|
156
|
+
You will need to call `#to_h` to get a `Hash` and do whatever modification needed before passing into `.new`
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
class Pokemon < ::ContractedValue::Value
|
160
|
+
attribute(:name)
|
161
|
+
attribute(:type)
|
162
|
+
end
|
163
|
+
|
164
|
+
class Pikachu < ::Pokemon
|
165
|
+
attribute(:name, default_value: "Pikachu")
|
166
|
+
attribute(:type, default_value: "Thunder")
|
167
|
+
end
|
168
|
+
|
169
|
+
# Ya I love using pokemon as examples, problem?
|
170
|
+
pikachu = Pikachu.new(name: "PikaPika")
|
171
|
+
pikachu.name #=> "PikaPika"
|
172
|
+
pikachu.type #=> "Thunder"
|
173
|
+
|
174
|
+
pokemon1 = Pokemon.new(pikachu)
|
175
|
+
pokemon1.name #=> "PikaPika"
|
176
|
+
pokemon1.type #=> "Thunder"
|
177
|
+
|
178
|
+
pokemon2 = Pokemon.new(pikachu.to_h.merge(name: "Piak"))
|
179
|
+
pokemon2.name #=> "Piak"
|
180
|
+
pokemon2.type #=> "Thunder"
|
181
|
+
```
|
182
|
+
|
149
183
|
|
150
184
|
### Input Validation
|
151
185
|
|
@@ -154,9 +188,9 @@ Input values are validated on object creation (instead of on attribute value acc
|
|
154
188
|
- Value presence
|
155
189
|
|
156
190
|
#### Value contract
|
157
|
-
An attribute can be declared without any contract, and any input value would be pass the validation
|
158
|
-
But you can pass a contract via `contract` option (must be a [`contracts.ruby`](https://github.com/egonSchiele/contracts.ruby) contract)
|
159
|
-
Passing input value violating an attribute's contract would cause an error
|
191
|
+
An attribute can be declared without any contract, and any input value would be pass the validation
|
192
|
+
But you can pass a contract via `contract` option (must be a [`contracts.ruby`](https://github.com/egonSchiele/contracts.ruby) contract)
|
193
|
+
Passing input value violating an attribute's contract would cause an error
|
160
194
|
|
161
195
|
```ruby
|
162
196
|
class YetAnotherRationalNumber < ::ContractedValue::Value
|
@@ -181,10 +215,10 @@ YetAnotherRationalNumber.new(
|
|
181
215
|
```
|
182
216
|
|
183
217
|
#### Value presence
|
184
|
-
An attribute declared should be provided a value on object creation, even the input value is `nil`
|
185
|
-
Otherwise an error is raised
|
186
|
-
You can pass default value via option `default_value`
|
187
|
-
The default value will need to confront to the contract passed in `contract` option too
|
218
|
+
An attribute declared should be provided a value on object creation, even the input value is `nil`
|
219
|
+
Otherwise an error is raised
|
220
|
+
You can pass default value via option `default_value`
|
221
|
+
The default value will need to confront to the contract passed in `contract` option too
|
188
222
|
|
189
223
|
|
190
224
|
```ruby
|
@@ -289,6 +323,8 @@ end
|
|
289
323
|
|
290
324
|
# Ya I love using pokemon as examples, problem?
|
291
325
|
pikachu = Pikachu.new(name: "PikaPika")
|
326
|
+
pikachu.name #=> "PikaPika"
|
327
|
+
pikachu.type #=> "Thunder"
|
292
328
|
```
|
293
329
|
|
294
330
|
#### All existing attributes can be redeclared
|
data/contracted_value.gemspec
CHANGED
@@ -12,9 +12,9 @@ Gem::Specification.new do |s|
|
|
12
12
|
s.platform = Gem::Platform::RUBY
|
13
13
|
s.name = gem_name
|
14
14
|
s.version = ContractedValue::VERSION
|
15
|
-
s.summary = "
|
15
|
+
s.summary = "Contracted immutable(by default) value objects"
|
16
16
|
s.description = <<-DOC
|
17
|
-
|
17
|
+
Library for creating contracted immutable(by default) value objects supported by contracts.ruby & ice_nine
|
18
18
|
DOC
|
19
19
|
|
20
20
|
s.license = "MIT"
|
@@ -28,20 +28,20 @@ Gem::Specification.new do |s|
|
|
28
28
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
29
29
|
s.require_paths = ["lib"]
|
30
30
|
|
31
|
-
s.add_dependency "contracts", "~> 0.
|
31
|
+
s.add_dependency "contracts", "~> 0.17"
|
32
32
|
s.add_dependency "ice_nine"
|
33
33
|
|
34
34
|
s.add_development_dependency "bundler", ">= 1.0.0"
|
35
|
-
s.add_development_dependency "rake", ">= 10.0", "<=
|
35
|
+
s.add_development_dependency "rake", ">= 10.0", "<= 14.0"
|
36
36
|
s.add_development_dependency "pry"
|
37
37
|
|
38
|
-
s.add_development_dependency "appraisal", "~> 2.0"
|
38
|
+
s.add_development_dependency "appraisal", "~> 2.0", ">= 2.5.0"
|
39
39
|
|
40
40
|
s.add_development_dependency "rspec", "~> 3.0"
|
41
41
|
s.add_development_dependency "rspec-its", "~> 1.0"
|
42
42
|
|
43
|
-
s.add_development_dependency "simplecov"
|
44
|
-
s.add_development_dependency "
|
43
|
+
s.add_development_dependency "simplecov", ">= 0.21"
|
44
|
+
s.add_development_dependency "simplecov-lcov", ">= 0.8"
|
45
45
|
|
46
46
|
s.add_development_dependency "gem-release", ">= 0.7"
|
47
47
|
|
@@ -49,7 +49,7 @@ Gem::Specification.new do |s|
|
|
49
49
|
|
50
50
|
s.add_development_dependency "rubocop", ">= 0.70"
|
51
51
|
|
52
|
-
s.required_ruby_version = ">=
|
52
|
+
s.required_ruby_version = ">= 3.0.0"
|
53
53
|
|
54
54
|
s.required_rubygems_version = ">= 1.4.0"
|
55
55
|
end
|
@@ -131,7 +131,7 @@ module ContractedValue
|
|
131
131
|
end
|
132
132
|
|
133
133
|
class Attribute
|
134
|
-
def self.new(
|
134
|
+
def self.new(...)
|
135
135
|
::IceNine.deep_freeze(super)
|
136
136
|
end
|
137
137
|
|
@@ -182,10 +182,17 @@ module ContractedValue
|
|
182
182
|
attr_reader :default_value
|
183
183
|
|
184
184
|
def raise_error_if_inputs_invalid
|
185
|
+
raise_error_if_name_invalid
|
185
186
|
raise_error_if_refrigeration_mode_invalid
|
186
187
|
raise_error_if_default_value_invalid
|
187
188
|
end
|
188
189
|
|
190
|
+
def raise_error_if_name_invalid
|
191
|
+
return if name.is_a?(Symbol)
|
192
|
+
|
193
|
+
raise NotImplementedError, "Internal error: name is not a symbol (#{name.class.name})"
|
194
|
+
end
|
195
|
+
|
189
196
|
def raise_error_if_refrigeration_mode_invalid
|
190
197
|
return if RefrigerationMode::Enum.all.include?(refrigeration_mode)
|
191
198
|
|
@@ -231,6 +238,8 @@ module ContractedValue
|
|
231
238
|
)
|
232
239
|
end
|
233
240
|
|
241
|
+
@attr_values = {}
|
242
|
+
|
234
243
|
self.class.send(:attribute_set).each_attribute do |attribute|
|
235
244
|
attr_value = attribute.extract_value(input_attr_values_hash)
|
236
245
|
|
@@ -253,8 +262,8 @@ module ContractedValue
|
|
253
262
|
|
254
263
|
# Using symbol since attribute names are limited in number
|
255
264
|
# An alternative would be using frozen string
|
256
|
-
|
257
|
-
|
265
|
+
@attr_values.store(
|
266
|
+
attribute.name.to_sym,
|
258
267
|
sometimes_frozen_attr_value,
|
259
268
|
)
|
260
269
|
end
|
@@ -265,10 +274,7 @@ module ContractedValue
|
|
265
274
|
# rubocop:enable Metrics/CyclomaticComplexity
|
266
275
|
|
267
276
|
def to_h
|
268
|
-
|
269
|
-
each_attribute.each_with_object({}) do |attribute, hash|
|
270
|
-
hash[attribute.name] = instance_variable_get(:"@#{attribute.name}")
|
271
|
-
end
|
277
|
+
@attr_values.clone
|
272
278
|
end
|
273
279
|
|
274
280
|
# == Class interface == #
|
@@ -288,16 +294,19 @@ module ContractedValue
|
|
288
294
|
refrigeration_mode: RefrigerationMode::Enum::DEEP,
|
289
295
|
default_value: Private::ATTR_DEFAULT_VALUE_ABSENT_VAL
|
290
296
|
)
|
297
|
+
# Using symbol since attribute names are limited in number
|
298
|
+
# An alternative would be using frozen string
|
299
|
+
name_in_sym = name.to_sym
|
291
300
|
|
292
301
|
attr = Attribute.new(
|
293
|
-
name:
|
302
|
+
name: name_in_sym,
|
294
303
|
contract: contract,
|
295
304
|
refrigeration_mode: refrigeration_mode,
|
296
305
|
default_value: default_value,
|
297
306
|
)
|
298
307
|
@attribute_set = @attribute_set.add(attr)
|
299
308
|
|
300
|
-
|
309
|
+
define_method(name_in_sym) { @attr_values[name_in_sym] }
|
301
310
|
end
|
302
311
|
|
303
312
|
# @api private
|
@@ -10,40 +10,50 @@ require "spec_helper"
|
|
10
10
|
end
|
11
11
|
|
12
12
|
example "does not raise error when NOT declaring any attribute" do
|
13
|
-
expect
|
13
|
+
expect { value_class }.to_not raise_error
|
14
14
|
end
|
15
15
|
|
16
16
|
example "does not raise error when declaring 1 attribute" do
|
17
|
-
expect
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
},
|
23
|
-
).to_not raise_error
|
17
|
+
expect {
|
18
|
+
value_class.class_eval do
|
19
|
+
attribute(:attribute_1)
|
20
|
+
end
|
21
|
+
}.to_not raise_error
|
24
22
|
end
|
25
23
|
|
26
24
|
example "does not raise error when declaring N attributes with different names" do
|
27
|
-
expect
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
},
|
34
|
-
).to_not raise_error
|
25
|
+
expect {
|
26
|
+
value_class.class_eval do
|
27
|
+
attribute(:attribute_1)
|
28
|
+
attribute(:attribute_2)
|
29
|
+
end
|
30
|
+
}.to_not raise_error
|
35
31
|
end
|
36
32
|
|
37
33
|
example "does raise error when declaring N attributes with the same name" do
|
38
|
-
expect
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
34
|
+
expect {
|
35
|
+
value_class.class_eval do
|
36
|
+
attribute(:attribute_1)
|
37
|
+
attribute(:attribute_2)
|
38
|
+
attribute(:attribute_1)
|
39
|
+
end
|
40
|
+
}.to raise_error(::ContractedValue::Errors::DuplicateAttributeDeclaration)
|
41
|
+
end
|
42
|
+
|
43
|
+
example "does not raise error when declaring 1 attribute with string name" do
|
44
|
+
expect {
|
45
|
+
value_class.class_eval do
|
46
|
+
attribute("attribute_1")
|
47
|
+
end
|
48
|
+
}.to_not raise_error
|
49
|
+
end
|
50
|
+
|
51
|
+
example "does not raise error when declaring 1 attribute with number name" do
|
52
|
+
expect {
|
53
|
+
value_class.class_eval do
|
54
|
+
attribute(1)
|
55
|
+
end
|
56
|
+
}.to raise_error(::NoMethodError, /undefined method `to_sym'/)
|
47
57
|
end
|
48
58
|
end
|
49
59
|
|
@@ -79,39 +89,39 @@ require "spec_helper"
|
|
79
89
|
|
80
90
|
it "does raise error when input is not a hash" do
|
81
91
|
aggregate_failures do
|
82
|
-
expect
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
},
|
88
|
-
).to raise_error(::ContractedValue::Errors::InvalidInputType)
|
92
|
+
expect {
|
93
|
+
value_class.new(
|
94
|
+
non_hash,
|
95
|
+
)
|
96
|
+
}.to raise_error(::ContractedValue::Errors::InvalidInputType)
|
89
97
|
end
|
90
98
|
end
|
91
99
|
|
92
100
|
it "does not raise error when input is a hash" do
|
93
101
|
aggregate_failures do
|
94
|
-
expect
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
},
|
100
|
-
).to_not raise_error
|
102
|
+
expect {
|
103
|
+
value_class.new(
|
104
|
+
default_inputs,
|
105
|
+
)
|
106
|
+
}.to_not raise_error
|
101
107
|
end
|
102
108
|
end
|
103
109
|
|
104
110
|
it "does not raise error when input is a value" do
|
105
111
|
aggregate_failures do
|
106
|
-
|
107
|
-
|
112
|
+
new_val = nil
|
113
|
+
expect {
|
114
|
+
new_val = value_class.new(
|
108
115
|
value_class.new(
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
116
|
+
default_inputs,
|
117
|
+
),
|
118
|
+
)
|
119
|
+
}.to_not raise_error
|
120
|
+
if new_val
|
121
|
+
default_inputs.each_pair do |attr_name, attr_val|
|
122
|
+
expect(new_val.public_send(attr_name)).to eq(attr_val)
|
123
|
+
end
|
124
|
+
end
|
115
125
|
end
|
116
126
|
end
|
117
127
|
|
@@ -121,13 +131,11 @@ require "spec_helper"
|
|
121
131
|
:attribute_1,
|
122
132
|
:attribute_2,
|
123
133
|
].each do |attr_name|
|
124
|
-
expect
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
},
|
130
|
-
).to raise_error(::ContractedValue::Errors::MissingAttributeInput)
|
134
|
+
expect {
|
135
|
+
value_class.new(
|
136
|
+
default_inputs.dup.tap{|h| h.delete(attr_name)},
|
137
|
+
)
|
138
|
+
}.to raise_error(::ContractedValue::Errors::MissingAttributeInput)
|
131
139
|
end
|
132
140
|
end
|
133
141
|
end
|
@@ -138,15 +146,13 @@ require "spec_helper"
|
|
138
146
|
:attribute_1,
|
139
147
|
:attribute_2,
|
140
148
|
].each do |attr_name|
|
141
|
-
expect
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
},
|
149
|
-
).to_not raise_error
|
149
|
+
expect {
|
150
|
+
value_class.new(
|
151
|
+
default_inputs.each_with_object({}) do |(k, _v), h|
|
152
|
+
h[k] = nil
|
153
|
+
end
|
154
|
+
)
|
155
|
+
}.to_not raise_error
|
150
156
|
end
|
151
157
|
end
|
152
158
|
end
|
@@ -175,36 +181,30 @@ require "spec_helper"
|
|
175
181
|
|
176
182
|
|
177
183
|
it "does not raise error when all values are valid according to contracts" do
|
178
|
-
expect
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
},
|
184
|
-
).to_not raise_error
|
184
|
+
expect {
|
185
|
+
value_class.new(
|
186
|
+
default_inputs
|
187
|
+
)
|
188
|
+
}.to_not raise_error
|
185
189
|
end
|
186
190
|
|
187
191
|
it "does raise error when any value is invalid according to contracts" do
|
188
192
|
aggregate_failures do
|
189
|
-
expect
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
},
|
197
|
-
).to raise_error(::ContractedValue::Errors::InvalidAttributeValue)
|
193
|
+
expect {
|
194
|
+
value_class.new(
|
195
|
+
default_inputs.merge(
|
196
|
+
attribute_with_contract_1: "",
|
197
|
+
),
|
198
|
+
)
|
199
|
+
}.to raise_error(::ContractedValue::Errors::InvalidAttributeValue)
|
198
200
|
|
199
|
-
expect
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
},
|
207
|
-
).to raise_error(::ContractedValue::Errors::InvalidAttributeValue)
|
201
|
+
expect {
|
202
|
+
value_class.new(
|
203
|
+
default_inputs.merge(
|
204
|
+
attribute_with_contract_2: 0,
|
205
|
+
),
|
206
|
+
)
|
207
|
+
}.to raise_error(::ContractedValue::Errors::InvalidAttributeValue)
|
208
208
|
end
|
209
209
|
end
|
210
210
|
end
|
@@ -237,22 +237,18 @@ require "spec_helper"
|
|
237
237
|
# Create it just before expectation
|
238
238
|
value_object
|
239
239
|
|
240
|
-
expect
|
241
|
-
|
242
|
-
|
243
|
-
},
|
244
|
-
).to raise_error(::RuntimeError, /can't modify frozen/)
|
240
|
+
expect {
|
241
|
+
hash_as_input[:a] = nil
|
242
|
+
}.to raise_error(::RuntimeError, /can't modify frozen/)
|
245
243
|
end
|
246
244
|
|
247
245
|
it "does deeply freeze the inputs" do
|
248
246
|
# Create it just before expectation
|
249
247
|
value_object
|
250
248
|
|
251
|
-
expect
|
252
|
-
|
253
|
-
|
254
|
-
},
|
255
|
-
).to raise_error(::RuntimeError, /can't modify frozen/)
|
249
|
+
expect {
|
250
|
+
hash_as_deep_nested_content[:a] = nil
|
251
|
+
}.to raise_error(::RuntimeError, /can't modify frozen/)
|
256
252
|
end
|
257
253
|
end
|
258
254
|
|
@@ -265,22 +261,18 @@ require "spec_helper"
|
|
265
261
|
# Create it just before expectation
|
266
262
|
value_object
|
267
263
|
|
268
|
-
expect
|
269
|
-
|
270
|
-
|
271
|
-
},
|
272
|
-
).to raise_error(::RuntimeError, /can't modify frozen/)
|
264
|
+
expect {
|
265
|
+
hash_as_input[:a] = nil
|
266
|
+
}.to raise_error(::RuntimeError, /can't modify frozen/)
|
273
267
|
end
|
274
268
|
|
275
269
|
it "does not deeply freeze the inputs" do
|
276
270
|
# Create it just before expectation
|
277
271
|
value_object
|
278
272
|
|
279
|
-
expect
|
280
|
-
|
281
|
-
|
282
|
-
},
|
283
|
-
).to_not raise_error
|
273
|
+
expect {
|
274
|
+
hash_as_deep_nested_content[:a] = nil
|
275
|
+
}.to_not raise_error
|
284
276
|
end
|
285
277
|
end
|
286
278
|
|
@@ -293,22 +285,18 @@ require "spec_helper"
|
|
293
285
|
# Create it just before expectation
|
294
286
|
value_object
|
295
287
|
|
296
|
-
expect
|
297
|
-
|
298
|
-
|
299
|
-
},
|
300
|
-
).to_not raise_error
|
288
|
+
expect {
|
289
|
+
hash_as_input[:a] = nil
|
290
|
+
}.to_not raise_error
|
301
291
|
end
|
302
292
|
|
303
293
|
it "does not deeply freeze the inputs" do
|
304
294
|
# Create it just before expectation
|
305
295
|
value_object
|
306
296
|
|
307
|
-
expect
|
308
|
-
|
309
|
-
|
310
|
-
},
|
311
|
-
).to_not raise_error
|
297
|
+
expect {
|
298
|
+
hash_as_deep_nested_content[:a] = nil
|
299
|
+
}.to_not raise_error
|
312
300
|
end
|
313
301
|
end
|
314
302
|
|
@@ -533,11 +521,9 @@ require "spec_helper"
|
|
533
521
|
end
|
534
522
|
|
535
523
|
example "does not raise error" do
|
536
|
-
expect
|
537
|
-
|
538
|
-
|
539
|
-
},
|
540
|
-
).to_not raise_error
|
524
|
+
expect {
|
525
|
+
child_value_class.new(attribute_1: "wut")
|
526
|
+
}.to_not raise_error
|
541
527
|
end
|
542
528
|
|
543
529
|
end
|
@@ -559,36 +545,30 @@ require "spec_helper"
|
|
559
545
|
end
|
560
546
|
|
561
547
|
example "does not raise error when declaring 1 new attribute" do
|
562
|
-
expect
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
},
|
568
|
-
).to_not raise_error
|
548
|
+
expect {
|
549
|
+
child_value_class.class_eval do
|
550
|
+
attribute(:attribute_3)
|
551
|
+
end
|
552
|
+
}.to_not raise_error
|
569
553
|
end
|
570
554
|
|
571
555
|
example "does not raise error when declaring N attributes with different names" do
|
572
|
-
expect
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
},
|
579
|
-
).to_not raise_error
|
556
|
+
expect {
|
557
|
+
child_value_class.class_eval do
|
558
|
+
attribute(:attribute_3)
|
559
|
+
attribute(:attribute_4)
|
560
|
+
end
|
561
|
+
}.to_not raise_error
|
580
562
|
end
|
581
563
|
|
582
564
|
example "does raise error when declaring N attributes with the same name" do
|
583
|
-
expect
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
},
|
591
|
-
).to raise_error(::ContractedValue::Errors::DuplicateAttributeDeclaration)
|
565
|
+
expect {
|
566
|
+
child_value_class.class_eval do
|
567
|
+
attribute(:attribute_3)
|
568
|
+
attribute(:attribute_4)
|
569
|
+
attribute(:attribute_3)
|
570
|
+
end
|
571
|
+
}.to raise_error(::ContractedValue::Errors::DuplicateAttributeDeclaration)
|
592
572
|
end
|
593
573
|
|
594
574
|
end
|
@@ -632,31 +612,27 @@ require "spec_helper"
|
|
632
612
|
end
|
633
613
|
|
634
614
|
example "does not raise error when declaring existing attribute with different contract" do
|
635
|
-
expect
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
|
641
|
-
|
642
|
-
|
643
|
-
|
644
|
-
},
|
645
|
-
).to raise_error(::ContractedValue::Errors::InvalidAttributeValue)
|
615
|
+
expect {
|
616
|
+
child_value_class.class_eval do
|
617
|
+
attribute(
|
618
|
+
:attribute_1,
|
619
|
+
contract: ::Contracts::Builtin::NatPos
|
620
|
+
)
|
621
|
+
end
|
622
|
+
child_value_class.new(attribute_1: "")
|
623
|
+
}.to raise_error(::ContractedValue::Errors::InvalidAttributeValue)
|
646
624
|
end
|
647
625
|
|
648
626
|
example "does not raise error when declaring existing attribute with different default_value" do
|
649
|
-
expect
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
},
|
659
|
-
).to_not raise_error
|
627
|
+
expect {
|
628
|
+
child_value_class.class_eval do
|
629
|
+
attribute(
|
630
|
+
:attribute_1,
|
631
|
+
default_value: nil,
|
632
|
+
)
|
633
|
+
end
|
634
|
+
child_value_class.new
|
635
|
+
}.to_not raise_error
|
660
636
|
end
|
661
637
|
|
662
638
|
example "does not raise error when declaring existing attribute with different refrigeration_mode" do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,15 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
require "contracted_value"
|
5
|
-
|
6
|
-
if ENV["TRAVIS"]
|
3
|
+
if ENV["COVERALLS"]
|
7
4
|
require "simplecov"
|
8
|
-
|
5
|
+
require "simplecov-lcov"
|
6
|
+
|
7
|
+
SimpleCov::Formatter::LcovFormatter.config do |c|
|
8
|
+
c.report_with_single_file = true
|
9
|
+
c.single_report_path = "coverage/lcov.info"
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
+
SimpleCov.formatters = SimpleCov::Formatter::MultiFormatter.new(
|
13
|
+
[SimpleCov::Formatter::HTMLFormatter, SimpleCov::Formatter::LcovFormatter]
|
14
|
+
)
|
15
|
+
|
16
|
+
SimpleCov.start do
|
17
|
+
add_filter "spec/"
|
18
|
+
end
|
12
19
|
end
|
13
20
|
|
21
|
+
$LOAD_PATH.unshift(File.expand_path("../../lib", __FILE__))
|
22
|
+
require "contracted_value"
|
23
|
+
|
14
24
|
require "rspec"
|
15
25
|
require "rspec/its"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: contracted_value
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- PikachuEXE
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-10-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: contracts
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.17'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0.
|
26
|
+
version: '0.17'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: ice_nine
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -61,7 +61,7 @@ dependencies:
|
|
61
61
|
version: '10.0'
|
62
62
|
- - "<="
|
63
63
|
- !ruby/object:Gem::Version
|
64
|
-
version: '
|
64
|
+
version: '14.0'
|
65
65
|
type: :development
|
66
66
|
prerelease: false
|
67
67
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -71,7 +71,7 @@ dependencies:
|
|
71
71
|
version: '10.0'
|
72
72
|
- - "<="
|
73
73
|
- !ruby/object:Gem::Version
|
74
|
-
version: '
|
74
|
+
version: '14.0'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
76
|
name: pry
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -93,6 +93,9 @@ dependencies:
|
|
93
93
|
- - "~>"
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '2.0'
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 2.5.0
|
96
99
|
type: :development
|
97
100
|
prerelease: false
|
98
101
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -100,6 +103,9 @@ dependencies:
|
|
100
103
|
- - "~>"
|
101
104
|
- !ruby/object:Gem::Version
|
102
105
|
version: '2.0'
|
106
|
+
- - ">="
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: 2.5.0
|
103
109
|
- !ruby/object:Gem::Dependency
|
104
110
|
name: rspec
|
105
111
|
requirement: !ruby/object:Gem::Requirement
|
@@ -134,28 +140,28 @@ dependencies:
|
|
134
140
|
requirements:
|
135
141
|
- - ">="
|
136
142
|
- !ruby/object:Gem::Version
|
137
|
-
version: '0'
|
143
|
+
version: '0.21'
|
138
144
|
type: :development
|
139
145
|
prerelease: false
|
140
146
|
version_requirements: !ruby/object:Gem::Requirement
|
141
147
|
requirements:
|
142
148
|
- - ">="
|
143
149
|
- !ruby/object:Gem::Version
|
144
|
-
version: '0'
|
150
|
+
version: '0.21'
|
145
151
|
- !ruby/object:Gem::Dependency
|
146
|
-
name:
|
152
|
+
name: simplecov-lcov
|
147
153
|
requirement: !ruby/object:Gem::Requirement
|
148
154
|
requirements:
|
149
155
|
- - ">="
|
150
156
|
- !ruby/object:Gem::Version
|
151
|
-
version: '0'
|
157
|
+
version: '0.8'
|
152
158
|
type: :development
|
153
159
|
prerelease: false
|
154
160
|
version_requirements: !ruby/object:Gem::Requirement
|
155
161
|
requirements:
|
156
162
|
- - ">="
|
157
163
|
- !ruby/object:Gem::Version
|
158
|
-
version: '0'
|
164
|
+
version: '0.8'
|
159
165
|
- !ruby/object:Gem::Dependency
|
160
166
|
name: gem-release
|
161
167
|
requirement: !ruby/object:Gem::Requirement
|
@@ -198,8 +204,8 @@ dependencies:
|
|
198
204
|
- - ">="
|
199
205
|
- !ruby/object:Gem::Version
|
200
206
|
version: '0.70'
|
201
|
-
description: "
|
202
|
-
|
207
|
+
description: " Library for creating contracted immutable(by default) value objects
|
208
|
+
supported by contracts.ruby & ice_nine\n"
|
203
209
|
email:
|
204
210
|
- pikachuexe@gmail.com
|
205
211
|
executables: []
|
@@ -208,9 +214,13 @@ extra_rdoc_files: []
|
|
208
214
|
files:
|
209
215
|
- ".codeclimate.yml"
|
210
216
|
- ".editorconfig"
|
217
|
+
- ".github/CODEOWNERS"
|
218
|
+
- ".github/FUNDING.yml"
|
219
|
+
- ".github/dependabot.yml"
|
220
|
+
- ".github/workflows/coverage.yml"
|
221
|
+
- ".github/workflows/tests.yaml"
|
211
222
|
- ".gitignore"
|
212
223
|
- ".rubocop.yml"
|
213
|
-
- ".travis.yml"
|
214
224
|
- Appraisals
|
215
225
|
- CHANGELOG.md
|
216
226
|
- Gemfile
|
@@ -218,8 +228,7 @@ files:
|
|
218
228
|
- README.md
|
219
229
|
- Rakefile
|
220
230
|
- contracted_value.gemspec
|
221
|
-
- gemfiles/
|
222
|
-
- gemfiles/contracts_16_0.gemfile
|
231
|
+
- gemfiles/contracts_17_0.gemfile
|
223
232
|
- lib/contracted_value.rb
|
224
233
|
- lib/contracted_value/core.rb
|
225
234
|
- lib/contracted_value/version.rb
|
@@ -230,7 +239,7 @@ homepage: http://github.com/PikachuEXE/contracted_value
|
|
230
239
|
licenses:
|
231
240
|
- MIT
|
232
241
|
metadata: {}
|
233
|
-
post_install_message:
|
242
|
+
post_install_message:
|
234
243
|
rdoc_options: []
|
235
244
|
require_paths:
|
236
245
|
- lib
|
@@ -238,17 +247,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
238
247
|
requirements:
|
239
248
|
- - ">="
|
240
249
|
- !ruby/object:Gem::Version
|
241
|
-
version:
|
250
|
+
version: 3.0.0
|
242
251
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
243
252
|
requirements:
|
244
253
|
- - ">="
|
245
254
|
- !ruby/object:Gem::Version
|
246
255
|
version: 1.4.0
|
247
256
|
requirements: []
|
248
|
-
rubygems_version: 3.
|
249
|
-
signing_key:
|
257
|
+
rubygems_version: 3.4.20
|
258
|
+
signing_key:
|
250
259
|
specification_version: 4
|
251
|
-
summary:
|
260
|
+
summary: Contracted immutable(by default) value objects
|
252
261
|
test_files:
|
253
262
|
- spec/contracted_value/value_spec.rb
|
254
263
|
- spec/contracted_value_spec.rb
|
data/.travis.yml
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
# Send builds to container-based infrastructure
|
2
|
-
# http://docs.travis-ci.com/user/workers/container-based-infrastructure/
|
3
|
-
sudo: false
|
4
|
-
language: ruby
|
5
|
-
before_install:
|
6
|
-
# This is required since 2.6.8 has issue when installing `rainbow`
|
7
|
-
# https://github.com/sickill/rainbow/issues/48
|
8
|
-
- gem update --system
|
9
|
-
- gem --version
|
10
|
-
cache:
|
11
|
-
- bundler
|
12
|
-
rvm:
|
13
|
-
- 2.4
|
14
|
-
- 2.5
|
15
|
-
- 2.6
|
16
|
-
- 2.7
|
17
|
-
- ruby-head
|
18
|
-
gemfile:
|
19
|
-
- gemfiles/contracts_15_0.gemfile
|
20
|
-
- gemfiles/contracts_16_0.gemfile
|
21
|
-
matrix:
|
22
|
-
fast_finish: true
|
23
|
-
allow_failures:
|
24
|
-
- rvm: 2.7
|
25
|
-
- rvm: ruby-head
|