dry-struct 1.3.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|