dry-struct 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +8 -7
- data/CHANGELOG.md +31 -2
- data/Gemfile +3 -6
- data/benchmarks/constrained.rb +1 -1
- data/bin/console +1 -1
- data/dry-struct.gemspec +3 -2
- data/lib/dry/struct.rb +12 -9
- data/lib/dry/struct/class_interface.rb +44 -38
- data/lib/dry/struct/struct_builder.rb +1 -1
- data/lib/dry/struct/version.rb +1 -1
- metadata +10 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2ea6fc5c14bec80d877a1a04549fa897c48fb6d028e9a35c86f05d59fff4cf65
|
4
|
+
data.tar.gz: 38062528ba03fb91e4d0c4ca95dc526e1db4703a71b0095a5d99d43b1112a015
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d29117cb09adefbdca14a7ed0ce5ed3e0b3cf22d5167ae30ab143bad0771c0d02782f0386f3995a4aa1625303a759894473ddc668e67d4a04bd93a818458bdc2
|
7
|
+
data.tar.gz: 5e1f4cdba2ceb5325c90fa454701daac5d82b410a4b6742eda3bfb467038aee16fd5796a8d0819cc8c510471590ffc42fb9fe3f4b04e9f3bf11d359b8b850a4d
|
data/.travis.yml
CHANGED
@@ -4,20 +4,21 @@ sudo: required
|
|
4
4
|
bundler_args: --without benchmarks tools
|
5
5
|
script:
|
6
6
|
- bundle exec rake spec
|
7
|
-
before_install:
|
8
|
-
- gem update --system
|
9
7
|
after_success:
|
10
8
|
- '[ -d coverage ] && bundle exec codeclimate-test-reporter'
|
11
9
|
rvm:
|
12
|
-
- 2.
|
13
|
-
- 2.3
|
14
|
-
- 2.
|
15
|
-
- 2.
|
16
|
-
-
|
10
|
+
- 2.4.5
|
11
|
+
- 2.5.3
|
12
|
+
- 2.6.1
|
13
|
+
- jruby-9.2.6.0
|
14
|
+
- truffleruby
|
17
15
|
env:
|
18
16
|
global:
|
19
17
|
- COVERAGE=true
|
20
18
|
- JRUBY_OPTS='--dev -J-Xmx1024M'
|
19
|
+
matrix:
|
20
|
+
allow_failures:
|
21
|
+
- rvm: truffleruby
|
21
22
|
notifications:
|
22
23
|
email: false
|
23
24
|
webhooks:
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,37 @@
|
|
1
|
+
# 0.7.0 2019-03-22
|
2
|
+
|
3
|
+
## Changed
|
4
|
+
|
5
|
+
* [BREAKING] `Struct.input` was renamed `Struct.schema`, hence `Struct.schema` returns an instance of `Dry::Types::Hash::Schema` rather than a `Hash`. Schemas are also implementing `Enumerable` but they iterate over key types.
|
6
|
+
New API:
|
7
|
+
```ruby
|
8
|
+
User.schema.each do |key|
|
9
|
+
puts "Key name: #{ key.name }"
|
10
|
+
puts "Key type: #{ key.type }"
|
11
|
+
end
|
12
|
+
```
|
13
|
+
To get a type by its name use `.key`:
|
14
|
+
```ruby
|
15
|
+
User.schema.key(:id) # => #<Dry::Types::Hash::Key ...>
|
16
|
+
```
|
17
|
+
* [BREAKING] `transform_types` now passes one argument to the block, an instance of the `Key` type. Combined with the new API from dry-types it simplifies declaring omittable keys:
|
18
|
+
```ruby
|
19
|
+
class StructWithOptionalKeys < Dry::Struct
|
20
|
+
transform_types { |key| key.required(false) }
|
21
|
+
# or simply
|
22
|
+
transform_types(&:omittable)
|
23
|
+
end
|
24
|
+
```
|
25
|
+
* `Dry::Stuct#new` is now more efficient for partial updates (flash-gordon)
|
26
|
+
* Ruby 2.3 is EOL and not officially supported. It may work but we don't test it.
|
27
|
+
|
28
|
+
[Compare v0.6.0...v0.7.0](https://github.com/dry-rb/dry-struct/compare/v0.6.0...v0.7.0)
|
29
|
+
|
1
30
|
# v0.6.0 2018-10-24
|
2
31
|
|
3
|
-
##
|
32
|
+
## Changed
|
4
33
|
|
5
|
-
* `Struct.attribute?` in the old sense is deprecated, use `has_attribute?` as a replacement
|
34
|
+
* [BREAKING] `Struct.attribute?` in the old sense is deprecated, use `has_attribute?` as a replacement
|
6
35
|
|
7
36
|
## Added
|
8
37
|
|
data/Gemfile
CHANGED
@@ -1,9 +1,8 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
2
|
|
3
|
-
|
3
|
+
git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
|
4
4
|
|
5
|
-
|
6
|
-
gem 'dry-inflector', git: 'https://github.com/dry-rb/dry-inflector'
|
5
|
+
gemspec
|
7
6
|
|
8
7
|
group :test do
|
9
8
|
gem 'codeclimate-test-reporter', platform: :mri, require: false
|
@@ -12,10 +11,8 @@ group :test do
|
|
12
11
|
end
|
13
12
|
|
14
13
|
group :tools do
|
14
|
+
gem 'pry'
|
15
15
|
gem 'pry-byebug', platform: :mri
|
16
|
-
gem 'pry', platform: :jruby
|
17
|
-
gem 'mutant'
|
18
|
-
gem 'mutant-rspec'
|
19
16
|
end
|
20
17
|
|
21
18
|
group :benchmarks do
|
data/benchmarks/constrained.rb
CHANGED
data/bin/console
CHANGED
data/dry-struct.gemspec
CHANGED
@@ -27,13 +27,14 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.bindir = 'exe'
|
28
28
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
29
|
spec.require_paths = ['lib']
|
30
|
+
spec.required_ruby_version = ">= 2.3.0"
|
30
31
|
|
31
32
|
spec.add_runtime_dependency 'dry-equalizer', '~> 0.2'
|
32
|
-
spec.add_runtime_dependency 'dry-types', '~> 0.
|
33
|
+
spec.add_runtime_dependency 'dry-types', '~> 0.15'
|
33
34
|
spec.add_runtime_dependency 'dry-core', '~> 0.4', '>= 0.4.3'
|
34
35
|
spec.add_runtime_dependency 'ice_nine', '~> 0.11'
|
35
36
|
|
36
|
-
spec.add_development_dependency 'bundler'
|
37
|
+
spec.add_development_dependency 'bundler'
|
37
38
|
spec.add_development_dependency 'rake', '~> 11.0'
|
38
39
|
spec.add_development_dependency 'rspec', '~> 3.3'
|
39
40
|
spec.add_development_dependency 'yard', '~> 0.9.5'
|
data/lib/dry/struct.rb
CHANGED
@@ -16,7 +16,7 @@ module Dry
|
|
16
16
|
# require 'dry-struct'
|
17
17
|
#
|
18
18
|
# module Types
|
19
|
-
# include Dry
|
19
|
+
# include Dry.Types
|
20
20
|
# end
|
21
21
|
#
|
22
22
|
# Person = Dry.Struct(name: Types::Strict::String, age: Types::Strict::Int)
|
@@ -60,12 +60,12 @@ module Dry
|
|
60
60
|
# require 'dry-struct'
|
61
61
|
#
|
62
62
|
# module Types
|
63
|
-
# include Dry
|
63
|
+
# include Dry.Types
|
64
64
|
# end
|
65
65
|
#
|
66
66
|
# class Book < Dry::Struct
|
67
|
-
# attribute :title, Types::
|
68
|
-
# attribute :subtitle, Types::
|
67
|
+
# attribute :title, Types::String
|
68
|
+
# attribute :subtitle, Types::String.optional
|
69
69
|
# end
|
70
70
|
#
|
71
71
|
# rom_n_roda = Book.new(
|
@@ -90,8 +90,8 @@ module Dry
|
|
90
90
|
|
91
91
|
# {Dry::Types::Hash::Schema} subclass with specific behaviour defined for
|
92
92
|
# @return [Dry::Types::Hash::Schema]
|
93
|
-
defines :
|
94
|
-
|
93
|
+
defines :schema
|
94
|
+
schema Types['coercible.hash'].schema(EMPTY_HASH)
|
95
95
|
|
96
96
|
@meta = EMPTY_HASH
|
97
97
|
|
@@ -143,8 +143,8 @@ module Dry
|
|
143
143
|
# rom_n_roda.to_hash
|
144
144
|
# #=> {title: 'Web Development with ROM and Roda', subtitle: nil}
|
145
145
|
def to_hash
|
146
|
-
self.class.schema.
|
147
|
-
result[key] = Hashify[self[key]] if attributes.key?(key)
|
146
|
+
self.class.schema.each_with_object({}) do |key, result|
|
147
|
+
result[key.name] = Hashify[self[key.name]] if attributes.key?(key.name)
|
148
148
|
end
|
149
149
|
end
|
150
150
|
alias_method :to_h, :to_hash
|
@@ -170,7 +170,10 @@ module Dry
|
|
170
170
|
# rom_n_roda.new(subtitle: '3rd edition')
|
171
171
|
# #=> #<Book title="Web Development with ROM and Roda" subtitle="3rd edition">
|
172
172
|
def new(changeset)
|
173
|
-
self.class
|
173
|
+
new_attributes = self.class.schema.apply(changeset, skip_missing: true, resolve_defaults: false)
|
174
|
+
self.class.load(__attributes__.merge(new_attributes))
|
175
|
+
rescue Types::SchemaError, Types::MissingKeyError, Types::UnknownKeysError => error
|
176
|
+
raise Struct::Error, "[#{self}.new] #{error}"
|
174
177
|
end
|
175
178
|
alias_method :__new__, :new
|
176
179
|
|
@@ -34,7 +34,7 @@ module Dry
|
|
34
34
|
# and modifies {.schema} accordingly.
|
35
35
|
#
|
36
36
|
# @param [Symbol] name name of the defined attribute
|
37
|
-
# @param [Dry::Types::
|
37
|
+
# @param [Dry::Types::Type, nil] type or superclass of nested type
|
38
38
|
# @return [Dry::Struct]
|
39
39
|
# @yield
|
40
40
|
# If a block is given, it will be evaluated in the context of
|
@@ -53,10 +53,7 @@ module Dry
|
|
53
53
|
# end
|
54
54
|
#
|
55
55
|
# Language.schema
|
56
|
-
#
|
57
|
-
# :name=>#<Dry::Types::Definition primitive=String options={} meta={}>,
|
58
|
-
# :details=>Language::Details
|
59
|
-
# }
|
56
|
+
# # => #<Dry::Types[Constructor<Schema<keys={name: Nominal<String> details: Language::Details}> fn=Kernel.Hash>]>
|
60
57
|
#
|
61
58
|
# ruby = Language.new(name: 'Ruby', details: { type: 'OO' })
|
62
59
|
# ruby.name #=> 'Ruby'
|
@@ -74,11 +71,11 @@ module Dry
|
|
74
71
|
# end
|
75
72
|
#
|
76
73
|
# Language.schema
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
74
|
+
# => #<Dry::Types[Constructor<Schema<keys={
|
75
|
+
# name: Nominal<String>
|
76
|
+
# versions: Array<Nominal<String>>
|
77
|
+
# celebrities: Array<Language::Celebrity>
|
78
|
+
# }> fn=Kernel.Hash>]>
|
82
79
|
#
|
83
80
|
# ruby = Language.new(
|
84
81
|
# name: 'Ruby',
|
@@ -114,7 +111,7 @@ module Dry
|
|
114
111
|
# User.new(name: 'John') # => #<User name="John">
|
115
112
|
#
|
116
113
|
# @param [Symbol] name name of the defined attribute
|
117
|
-
# @param [Dry::Types::
|
114
|
+
# @param [Dry::Types::Type, nil] type or superclass of nested type
|
118
115
|
# @return [Dry::Struct]
|
119
116
|
#
|
120
117
|
def attribute?(*args, &block)
|
@@ -129,11 +126,11 @@ module Dry
|
|
129
126
|
else
|
130
127
|
name, type = args
|
131
128
|
|
132
|
-
attribute(name, build_type(name, type, &block)
|
129
|
+
attribute(:"#{ name }?", build_type(name, type, &block))
|
133
130
|
end
|
134
131
|
end
|
135
132
|
|
136
|
-
# @param [Hash{Symbol => Dry::Types::
|
133
|
+
# @param [Hash{Symbol => Dry::Types::Type}] new_schema
|
137
134
|
# @return [Dry::Struct]
|
138
135
|
# @raise [RepeatedAttributeError] when trying to define attribute with the
|
139
136
|
# same name as previously defined one
|
@@ -147,14 +144,17 @@ module Dry
|
|
147
144
|
# end
|
148
145
|
#
|
149
146
|
# Book.schema
|
150
|
-
#
|
151
|
-
#
|
147
|
+
# # => #<Dry::Types[Constructor<Schema<keys={
|
148
|
+
# # title: Nominal<String>
|
149
|
+
# # author: Nominal<String>
|
150
|
+
# # }> fn=Kernel.Hash>]>
|
152
151
|
def attributes(new_schema)
|
153
|
-
|
152
|
+
keys = new_schema.keys.map { |k| k.to_s.chomp('?').to_sym }
|
153
|
+
check_schema_duplication(keys)
|
154
154
|
|
155
|
-
|
155
|
+
schema schema.schema(new_schema)
|
156
156
|
|
157
|
-
|
157
|
+
keys.each do |key|
|
158
158
|
next if instance_methods.include?(key)
|
159
159
|
class_eval(<<-RUBY)
|
160
160
|
def #{ key }
|
@@ -165,9 +165,11 @@ module Dry
|
|
165
165
|
|
166
166
|
@attribute_names = nil
|
167
167
|
|
168
|
-
descendants.
|
169
|
-
|
170
|
-
|
168
|
+
direct_descendants = descendants.select { |d| d.superclass == self }
|
169
|
+
direct_descendants.each do |d|
|
170
|
+
inherited_attrs = new_schema.reject { |k, _| d.has_attribute?(k.to_s.chomp('?').to_sym) }
|
171
|
+
d.attributes(inherited_attrs)
|
172
|
+
end
|
171
173
|
|
172
174
|
self
|
173
175
|
end
|
@@ -183,10 +185,10 @@ module Dry
|
|
183
185
|
# attribute :title, Types::Strict::String
|
184
186
|
# end
|
185
187
|
#
|
186
|
-
# Book.schema
|
188
|
+
# Book.schema.key(:title).meta # => { struct: :Book }
|
187
189
|
#
|
188
190
|
def transform_types(proc = nil, &block)
|
189
|
-
|
191
|
+
schema schema.with_type_transform(proc || block)
|
190
192
|
end
|
191
193
|
|
192
194
|
# Add an arbitrary transformation for input hash keys.
|
@@ -203,16 +205,18 @@ module Dry
|
|
203
205
|
# Book.new('title' => "The Old Man and the Sea")
|
204
206
|
# # => #<Book title="The Old Man and the Sea">
|
205
207
|
def transform_keys(proc = nil, &block)
|
206
|
-
|
208
|
+
schema schema.with_key_transform(proc || block)
|
207
209
|
end
|
208
210
|
|
209
|
-
# @param [Hash{Symbol => Dry::Types::
|
211
|
+
# @param [Hash{Symbol => Dry::Types::Type, Dry::Struct}] new_schema
|
210
212
|
# @raise [RepeatedAttributeError] when trying to define attribute with the
|
211
213
|
# same name as previously defined one
|
212
|
-
def check_schema_duplication(
|
213
|
-
|
214
|
+
def check_schema_duplication(new_keys)
|
215
|
+
overlapping_keys = new_keys & (attribute_names - superclass.attribute_names)
|
214
216
|
|
215
|
-
|
217
|
+
if overlapping_keys.any?
|
218
|
+
raise RepeatedAttributeError, overlapping_keys.first
|
219
|
+
end
|
216
220
|
end
|
217
221
|
private :check_schema_duplication
|
218
222
|
|
@@ -222,12 +226,19 @@ module Dry
|
|
222
226
|
if attributes.instance_of?(self)
|
223
227
|
attributes
|
224
228
|
else
|
225
|
-
super(
|
229
|
+
super(schema[attributes])
|
226
230
|
end
|
227
231
|
rescue Types::SchemaError, Types::MissingKeyError, Types::UnknownKeysError => error
|
228
232
|
raise Struct::Error, "[#{self}.new] #{error}"
|
229
233
|
end
|
230
234
|
|
235
|
+
# @api private
|
236
|
+
def load(attributes)
|
237
|
+
struct = allocate
|
238
|
+
struct.send(:initialize, attributes)
|
239
|
+
struct
|
240
|
+
end
|
241
|
+
|
231
242
|
# Calls type constructor. The behavior is identical to `.new` but returns
|
232
243
|
# the input back if it's a subclass of the struct.
|
233
244
|
#
|
@@ -321,16 +332,11 @@ module Dry
|
|
321
332
|
schema.key?(key)
|
322
333
|
end
|
323
334
|
|
324
|
-
# @return [Hash{Symbol => Dry::Types::Definition, Dry::Struct}]
|
325
|
-
def schema
|
326
|
-
input.member_types
|
327
|
-
end
|
328
|
-
|
329
335
|
# Gets the list of attribute names
|
330
336
|
#
|
331
337
|
# @return [Array<Symbol>]
|
332
338
|
def attribute_names
|
333
|
-
@attribute_names ||= schema.
|
339
|
+
@attribute_names ||= schema.map(&:name)
|
334
340
|
end
|
335
341
|
|
336
342
|
# @return [{Symbol => Object}]
|
@@ -367,15 +373,15 @@ module Dry
|
|
367
373
|
#
|
368
374
|
# @return [Hash{Symbol => Object}]
|
369
375
|
def default_attributes(default_schema = schema)
|
370
|
-
default_schema.each_with_object({}) do |
|
371
|
-
result[name] = default_attributes(
|
376
|
+
default_schema.each_with_object({}) do |key, result|
|
377
|
+
result[key.name] = default_attributes(key.schema) if struct?(key.type)
|
372
378
|
end
|
373
379
|
end
|
374
380
|
private :default_attributes
|
375
381
|
|
376
382
|
# Checks if the given type is a Dry::Struct
|
377
383
|
#
|
378
|
-
# @param [Dry::Types::
|
384
|
+
# @param [Dry::Types::Type] type
|
379
385
|
# @return [Boolean]
|
380
386
|
def struct?(type)
|
381
387
|
type.is_a?(Class) && type <= Struct
|
data/lib/dry/struct/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dry-struct
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-03-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-equalizer
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0.
|
33
|
+
version: '0.15'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0.
|
40
|
+
version: '0.15'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: dry-core
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -76,16 +76,16 @@ dependencies:
|
|
76
76
|
name: bundler
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
|
-
- - "
|
79
|
+
- - ">="
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
81
|
+
version: '0'
|
82
82
|
type: :development
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
|
-
- - "
|
86
|
+
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: '
|
88
|
+
version: '0'
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: rake
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,15 +178,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
178
178
|
requirements:
|
179
179
|
- - ">="
|
180
180
|
- !ruby/object:Gem::Version
|
181
|
-
version:
|
181
|
+
version: 2.3.0
|
182
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
183
183
|
requirements:
|
184
184
|
- - ">="
|
185
185
|
- !ruby/object:Gem::Version
|
186
186
|
version: '0'
|
187
187
|
requirements: []
|
188
|
-
|
189
|
-
rubygems_version: 2.7.6
|
188
|
+
rubygems_version: 3.0.1
|
190
189
|
signing_key:
|
191
190
|
specification_version: 4
|
192
191
|
summary: Typed structs and value objects.
|