dry-struct 1.3.0 → 1.4.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/CHANGELOG.md +47 -5
- data/LICENSE +1 -1
- data/README.md +1 -1
- data/dry-struct.gemspec +3 -4
- data/lib/dry-struct.rb +1 -1
- data/lib/dry/struct.rb +20 -20
- data/lib/dry/struct/class_interface.rb +19 -19
- data/lib/dry/struct/compiler.rb +2 -2
- data/lib/dry/struct/errors.rb +1 -1
- data/lib/dry/struct/extensions.rb +1 -1
- data/lib/dry/struct/extensions/pretty_print.rb +5 -5
- data/lib/dry/struct/printer.rb +1 -1
- data/lib/dry/struct/struct_builder.rb +21 -6
- data/lib/dry/struct/sum.rb +2 -2
- data/lib/dry/struct/value.rb +2 -2
- data/lib/dry/struct/version.rb +1 -1
- metadata +10 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf0892469a434b85578e7350f52039b85203dbd251ca5c4bd6b038373edc703e
|
4
|
+
data.tar.gz: 263e3d2d4ce824be64210a27d074fb42126dde12d94e56290307d9ff08c0efad
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '08ea5f7780bac10495f93a5043c5e100fc9386688920e4e7fd1b2304ceaeb8f37853f6ed70f5d5a69b1d7a30c0340450f8ce41fba91e812e00cf6a008f9c2de0'
|
7
|
+
data.tar.gz: da176db2c5d8127ea7ef6a088edf7f8f4d18c74e65d96e7f6a80dd9822c0baefdfa1dd7eb6d607ac077c033d64dcddb0ca6c1498eb411c4cd94ea96e23c701b4
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,32 @@
|
|
1
|
+
<!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
|
2
|
+
|
3
|
+
## 1.4.0 2021-01-21
|
4
|
+
|
5
|
+
|
6
|
+
### Added
|
7
|
+
|
8
|
+
- Support for wrapping constructors and fallbacks, see release notes for dry-types 1.5.0 (@flash-gordon)
|
9
|
+
- Improvements of the attribute DSL, now it's possible to use optional structs as a base class (@flash-gordon)
|
10
|
+
```ruby
|
11
|
+
class User < Dry::Struct
|
12
|
+
attribute :name, Types::String
|
13
|
+
attribute :address, Dry::Struct.optional do
|
14
|
+
attribute :city, Types::String
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
User.new(name: "John", address: nil) # => #<User name="John" address=nil>
|
19
|
+
```
|
20
|
+
|
21
|
+
|
22
|
+
[Compare v1.3.0...v1.4.0](https://github.com/dry-rb/dry-struct/compare/v1.3.0...v1.4.0)
|
23
|
+
|
1
24
|
## 1.3.0 2020-02-10
|
2
25
|
|
3
26
|
|
4
27
|
### Added
|
5
28
|
|
6
|
-
- Nested structures will reuse type and key transformations from
|
29
|
+
- Nested structures will reuse type and key transformations from the enclosing struct (@flash-gordon)
|
7
30
|
|
8
31
|
```ruby
|
9
32
|
class User < Dry::Struct
|
@@ -22,13 +45,32 @@
|
|
22
45
|
end
|
23
46
|
end
|
24
47
|
```
|
25
|
-
- `Dry::Struct::Constructor` finally acts like a fully-featured type (flash-gordon)
|
26
|
-
- `Dry::Struct.abstract` declares a struct class as abstract. An abstract class is used as a default superclass for nested structs (flash-gordon)
|
27
|
-
- `Struct.to_ast` and struct compiler (@flash-gordon)
|
48
|
+
- `Dry::Struct::Constructor` finally acts like a fully-featured type (@flash-gordon)
|
49
|
+
- `Dry::Struct.abstract` declares a struct class as abstract. An abstract class is used as a default superclass for nested structs (@flash-gordon)
|
50
|
+
- `Dry::Struct.to_ast` and struct compiler (@flash-gordon)
|
51
|
+
- Struct composition with `Dry::Struct.attributes_from`. It's more flexible than inheritance (@waiting-for-dev + @flash-gordon)
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class Address < Dry::Struct
|
55
|
+
attribute :city, Types::String
|
56
|
+
attribute :zipcode, Types::String
|
57
|
+
end
|
58
|
+
|
59
|
+
class Buyer < Dry::Struct
|
60
|
+
attribute :name, Types::String
|
61
|
+
attributes_from Address
|
62
|
+
end
|
63
|
+
|
64
|
+
class Seller < Dry::Struct
|
65
|
+
attribute :name, Types::String
|
66
|
+
attribute :email, Types::String
|
67
|
+
attributes_from Address
|
68
|
+
end
|
69
|
+
```
|
28
70
|
|
29
71
|
### Changed
|
30
72
|
|
31
|
-
- [internal] metadata is now stored inside schema (flash-gordon)
|
73
|
+
- [internal] metadata is now stored inside schema (@flash-gordon)
|
32
74
|
|
33
75
|
[Compare v1.2.0...v1.3.0](https://github.com/dry-rb/dry-struct/compare/v1.2.0...v1.3.0)
|
34
76
|
|
data/LICENSE
CHANGED
data/README.md
CHANGED
data/dry-struct.gemspec
CHANGED
@@ -25,12 +25,11 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.metadata['source_code_uri'] = 'https://github.com/dry-rb/dry-struct'
|
26
26
|
spec.metadata['bug_tracker_uri'] = 'https://github.com/dry-rb/dry-struct/issues'
|
27
27
|
|
28
|
-
spec.required_ruby_version = ">= 2.
|
28
|
+
spec.required_ruby_version = ">= 2.5.0"
|
29
29
|
|
30
30
|
# to update dependencies edit project.yml
|
31
|
-
spec.add_runtime_dependency "dry-core", "~> 0.
|
32
|
-
spec.add_runtime_dependency "dry-
|
33
|
-
spec.add_runtime_dependency "dry-types", "~> 1.3"
|
31
|
+
spec.add_runtime_dependency "dry-core", "~> 0.5", ">= 0.5"
|
32
|
+
spec.add_runtime_dependency "dry-types", "~> 1.5"
|
34
33
|
spec.add_runtime_dependency "ice_nine", "~> 0.11"
|
35
34
|
|
36
35
|
spec.add_development_dependency "bundler"
|
data/lib/dry-struct.rb
CHANGED
data/lib/dry/struct.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
13
|
-
require
|
3
|
+
require "dry/types"
|
4
|
+
require "dry/core/equalizer"
|
5
|
+
require "dry/core/extensions"
|
6
|
+
require "dry/core/constants"
|
7
|
+
require "dry/core/deprecations"
|
8
|
+
|
9
|
+
require "dry/struct/version"
|
10
|
+
require "dry/struct/errors"
|
11
|
+
require "dry/struct/class_interface"
|
12
|
+
require "dry/struct/hashify"
|
13
|
+
require "dry/struct/struct_builder"
|
14
14
|
|
15
15
|
module Dry
|
16
16
|
# Constructor method for easily creating a {Dry::Struct}.
|
@@ -95,14 +95,14 @@ module Dry
|
|
95
95
|
define_method(:prepend, ::Module.method(:prepend))
|
96
96
|
end
|
97
97
|
|
98
|
-
autoload :Value,
|
98
|
+
autoload :Value, "dry/struct/value"
|
99
99
|
|
100
100
|
include ::Dry::Equalizer(:__attributes__, inspect: false, immutable: true)
|
101
101
|
|
102
102
|
# {Dry::Types::Hash::Schema} subclass with specific behaviour defined for
|
103
103
|
# @return [Dry::Types::Hash::Schema]
|
104
104
|
defines :schema
|
105
|
-
schema Types[
|
105
|
+
schema Types["coercible.hash"].schema(EMPTY_HASH)
|
106
106
|
|
107
107
|
defines :abstract_class
|
108
108
|
abstract
|
@@ -134,7 +134,7 @@ module Dry
|
|
134
134
|
# rom_n_roda[:title] #=> 'Web Development with ROM and Roda'
|
135
135
|
# rom_n_roda[:subtitle] #=> nil
|
136
136
|
def [](name)
|
137
|
-
@attributes.fetch(name) { raise MissingAttributeError
|
137
|
+
@attributes.fetch(name) { raise MissingAttributeError, name }
|
138
138
|
end
|
139
139
|
|
140
140
|
# Converts the {Dry::Struct} to a hash with keys representing
|
@@ -185,8 +185,8 @@ module Dry
|
|
185
185
|
def new(changeset)
|
186
186
|
new_attributes = self.class.schema.apply(changeset, skip_missing: true, resolve_defaults: false)
|
187
187
|
self.class.load(__attributes__.merge(new_attributes))
|
188
|
-
rescue Types::SchemaError, Types::MissingKeyError, Types::UnknownKeysError =>
|
189
|
-
raise Error, "[#{self}.new] #{
|
188
|
+
rescue Types::SchemaError, Types::MissingKeyError, Types::UnknownKeysError => e
|
189
|
+
raise Error, "[#{self}.new] #{e}"
|
190
190
|
end
|
191
191
|
alias_method :__new__, :new
|
192
192
|
|
@@ -197,16 +197,16 @@ module Dry
|
|
197
197
|
"#<#{klass.name || klass.inspect}#{attrs}>"
|
198
198
|
end
|
199
199
|
|
200
|
-
if RUBY_VERSION >=
|
200
|
+
if RUBY_VERSION >= "2.7"
|
201
201
|
# Pattern matching support
|
202
202
|
#
|
203
203
|
# @api private
|
204
|
-
def deconstruct_keys(
|
204
|
+
def deconstruct_keys(_keys)
|
205
205
|
attributes
|
206
206
|
end
|
207
207
|
end
|
208
208
|
end
|
209
209
|
end
|
210
210
|
|
211
|
-
require
|
212
|
-
require
|
211
|
+
require "dry/struct/extensions"
|
212
|
+
require "dry/struct/printer"
|
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "weakref"
|
4
|
+
require "dry/core/class_attributes"
|
5
|
+
require "dry/core/inflector"
|
6
|
+
require "dry/core/descendants_tracker"
|
7
7
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
8
|
+
require "dry/struct/errors"
|
9
|
+
require "dry/struct/constructor"
|
10
|
+
require "dry/struct/sum"
|
11
11
|
|
12
12
|
module Dry
|
13
13
|
class Struct
|
@@ -22,7 +22,7 @@ module Dry
|
|
22
22
|
def inherited(klass)
|
23
23
|
super
|
24
24
|
|
25
|
-
unless klass.name.eql?(
|
25
|
+
unless klass.name.eql?("Dry::Struct::Value")
|
26
26
|
klass.extend(Core::DescendantsTracker)
|
27
27
|
end
|
28
28
|
end
|
@@ -149,8 +149,8 @@ module Dry
|
|
149
149
|
def attribute?(*args, &block)
|
150
150
|
if args.size == 1 && block.nil?
|
151
151
|
Core::Deprecations.warn(
|
152
|
-
|
153
|
-
|
152
|
+
"Dry::Struct.attribute? is deprecated for checking attribute presence, "\
|
153
|
+
"use has_attribute? instead",
|
154
154
|
tag: :'dry-struct'
|
155
155
|
)
|
156
156
|
|
@@ -181,7 +181,7 @@ module Dry
|
|
181
181
|
# # author: Constrained<Nominal<String> rule=[type?(String)]>
|
182
182
|
# # }> fn=Kernel.Hash>]>
|
183
183
|
def attributes(new_schema)
|
184
|
-
keys = new_schema.keys.map { |k| k.to_s.chomp(
|
184
|
+
keys = new_schema.keys.map { |k| k.to_s.chomp("?").to_sym }
|
185
185
|
check_schema_duplication(keys)
|
186
186
|
|
187
187
|
schema schema.schema(new_schema)
|
@@ -192,7 +192,7 @@ module Dry
|
|
192
192
|
|
193
193
|
direct_descendants = descendants.select { |d| d.superclass == self }
|
194
194
|
direct_descendants.each do |d|
|
195
|
-
inherited_attrs = new_schema.reject { |k, _| d.has_attribute?(k.to_s.chomp(
|
195
|
+
inherited_attrs = new_schema.reject { |k, _| d.has_attribute?(k.to_s.chomp("?").to_sym) }
|
196
196
|
d.attributes(inherited_attrs)
|
197
197
|
end
|
198
198
|
|
@@ -233,7 +233,7 @@ module Dry
|
|
233
233
|
schema schema.with_key_transform(proc || block)
|
234
234
|
end
|
235
235
|
|
236
|
-
# @param [Hash{Symbol => Dry::Types::Type, Dry::Struct}]
|
236
|
+
# @param [Hash{Symbol => Dry::Types::Type, Dry::Struct}] new_keys
|
237
237
|
# @raise [RepeatedAttributeError] when trying to define attribute with the
|
238
238
|
# same name as previously defined one
|
239
239
|
def check_schema_duplication(new_keys)
|
@@ -264,8 +264,8 @@ module Dry
|
|
264
264
|
else
|
265
265
|
load(schema.call_unsafe(attributes))
|
266
266
|
end
|
267
|
-
rescue Types::CoercionError =>
|
268
|
-
raise Error, "[#{self}.new] #{
|
267
|
+
rescue Types::CoercionError => e
|
268
|
+
raise Error, "[#{self}.new] #{e}", e.backtrace
|
269
269
|
end
|
270
270
|
|
271
271
|
# @api private
|
@@ -289,7 +289,7 @@ module Dry
|
|
289
289
|
# @api private
|
290
290
|
def load(attributes)
|
291
291
|
struct = allocate
|
292
|
-
struct.
|
292
|
+
struct.__send__(:initialize, attributes)
|
293
293
|
struct
|
294
294
|
end
|
295
295
|
|
@@ -297,7 +297,7 @@ module Dry
|
|
297
297
|
# @param [#call,nil] block
|
298
298
|
# @return [Dry::Struct::Constructor]
|
299
299
|
def constructor(constructor = nil, **, &block)
|
300
|
-
Constructor
|
300
|
+
Constructor[self, fn: constructor || block]
|
301
301
|
end
|
302
302
|
|
303
303
|
# @param [Hash{Symbol => Object},Dry::Struct] input
|
@@ -345,7 +345,7 @@ module Dry
|
|
345
345
|
false
|
346
346
|
end
|
347
347
|
|
348
|
-
# @param [Object, Dry::Struct]
|
348
|
+
# @param [Object, Dry::Struct] other
|
349
349
|
# @return [Boolean]
|
350
350
|
def ===(other)
|
351
351
|
other.is_a?(self)
|
@@ -463,7 +463,7 @@ module Dry
|
|
463
463
|
elsif block.nil? && Undefined.equal?(type)
|
464
464
|
raise(
|
465
465
|
::ArgumentError,
|
466
|
-
|
466
|
+
"you must supply a type or a block to `Dry::Struct.attribute`"
|
467
467
|
)
|
468
468
|
else
|
469
469
|
type
|
data/lib/dry/struct/compiler.rb
CHANGED
data/lib/dry/struct/errors.rb
CHANGED
@@ -25,7 +25,7 @@ module Dry
|
|
25
25
|
# This shouldn't happen in a working application
|
26
26
|
class RecycledStructError < ::RuntimeError
|
27
27
|
def initialize
|
28
|
-
super(
|
28
|
+
super("Reference to struct class was garbage collected")
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -1,18 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "pp"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
class Struct
|
7
7
|
def pretty_print(pp)
|
8
8
|
klass = self.class
|
9
|
-
pp.group(1, "#<#{klass.name || klass.inspect}",
|
10
|
-
pp.seplist(@attributes.keys, proc { pp.text
|
9
|
+
pp.group(1, "#<#{klass.name || klass.inspect}", ">") do
|
10
|
+
pp.seplist(@attributes.keys, proc { pp.text "," }) do |column_name|
|
11
11
|
column_value = @attributes[column_name]
|
12
|
-
pp.breakable
|
12
|
+
pp.breakable " "
|
13
13
|
pp.group(1) do
|
14
14
|
pp.text column_name
|
15
|
-
pp.text
|
15
|
+
pp.text "="
|
16
16
|
pp.pp column_value
|
17
17
|
end
|
18
18
|
end
|
data/lib/dry/struct/printer.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "dry/struct/compiler"
|
4
4
|
|
5
5
|
module Dry
|
6
6
|
class Struct
|
@@ -30,10 +30,13 @@ module Dry
|
|
30
30
|
|
31
31
|
class_exec(&block)
|
32
32
|
end
|
33
|
+
|
33
34
|
struct.const_set(const_name, new_type)
|
34
35
|
|
35
36
|
if array?(type)
|
36
37
|
type.of(new_type)
|
38
|
+
elsif optional?(type)
|
39
|
+
new_type.optional
|
37
40
|
else
|
38
41
|
new_type
|
39
42
|
end
|
@@ -41,13 +44,23 @@ module Dry
|
|
41
44
|
|
42
45
|
private
|
43
46
|
|
47
|
+
def type?(type)
|
48
|
+
type.is_a?(Types::Type)
|
49
|
+
end
|
50
|
+
|
44
51
|
def array?(type)
|
45
|
-
type
|
52
|
+
type?(type) && !type.optional? && type.primitive.equal?(::Array)
|
53
|
+
end
|
54
|
+
|
55
|
+
def optional?(type)
|
56
|
+
type?(type) && type.optional?
|
46
57
|
end
|
47
58
|
|
48
59
|
def parent(type)
|
49
60
|
if array?(type)
|
50
61
|
visit(type.to_ast)
|
62
|
+
elsif optional?(type)
|
63
|
+
type.right
|
51
64
|
else
|
52
65
|
type
|
53
66
|
end
|
@@ -65,10 +78,12 @@ module Dry
|
|
65
78
|
end
|
66
79
|
|
67
80
|
def check_name(name)
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
81
|
+
if struct.const_defined?(name, false)
|
82
|
+
raise(
|
83
|
+
Error,
|
84
|
+
"Can't create nested attribute - `#{struct}::#{name}` already defined"
|
85
|
+
)
|
86
|
+
end
|
72
87
|
end
|
73
88
|
|
74
89
|
def visit_constrained(node)
|
data/lib/dry/struct/sum.rb
CHANGED
data/lib/dry/struct/value.rb
CHANGED
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: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Solnica
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dry-core
|
@@ -16,48 +16,34 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0.
|
19
|
+
version: '0.5'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.
|
22
|
+
version: '0.5'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
27
|
- - "~>"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '0.
|
29
|
+
version: '0.5'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: dry-equalizer
|
35
|
-
requirement: !ruby/object:Gem::Requirement
|
36
|
-
requirements:
|
37
|
-
- - "~>"
|
38
|
-
- !ruby/object:Gem::Version
|
39
|
-
version: '0.3'
|
40
|
-
type: :runtime
|
41
|
-
prerelease: false
|
42
|
-
version_requirements: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '0.3'
|
32
|
+
version: '0.5'
|
47
33
|
- !ruby/object:Gem::Dependency
|
48
34
|
name: dry-types
|
49
35
|
requirement: !ruby/object:Gem::Requirement
|
50
36
|
requirements:
|
51
37
|
- - "~>"
|
52
38
|
- !ruby/object:Gem::Version
|
53
|
-
version: '1.
|
39
|
+
version: '1.5'
|
54
40
|
type: :runtime
|
55
41
|
prerelease: false
|
56
42
|
version_requirements: !ruby/object:Gem::Requirement
|
57
43
|
requirements:
|
58
44
|
- - "~>"
|
59
45
|
- !ruby/object:Gem::Version
|
60
|
-
version: '1.
|
46
|
+
version: '1.5'
|
61
47
|
- !ruby/object:Gem::Dependency
|
62
48
|
name: ice_nine
|
63
49
|
requirement: !ruby/object:Gem::Requirement
|
@@ -169,14 +155,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
169
155
|
requirements:
|
170
156
|
- - ">="
|
171
157
|
- !ruby/object:Gem::Version
|
172
|
-
version: 2.
|
158
|
+
version: 2.5.0
|
173
159
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
160
|
requirements:
|
175
161
|
- - ">="
|
176
162
|
- !ruby/object:Gem::Version
|
177
163
|
version: '0'
|
178
164
|
requirements: []
|
179
|
-
rubygems_version: 3.
|
165
|
+
rubygems_version: 3.1.4
|
180
166
|
signing_key:
|
181
167
|
specification_version: 4
|
182
168
|
summary: Typed structs and value objects
|