dry-schema 1.9.3 → 1.10.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2dead9a036c0d9322c68b50938417ebe12a4b62ed2f99a8ae6d4f49f894dabd
4
- data.tar.gz: ac3b386e3266e8498aa62549cddfbaece9414281beee5710c1930b062eaacde8
3
+ metadata.gz: 3a3fdab16834d270d9cdfd3788fffb0899b711fc946e6aa3f4bc98115983acb7
4
+ data.tar.gz: c8349be888a2d957ba67137a7877828031d385e1452793730654cee3a9994e68
5
5
  SHA512:
6
- metadata.gz: '0831055ac93da2898c55b6194703e87bda1c27040ac23965c5f261c2e59387888f679b9dcd967a4a0665cef220b7c97db823670067267b34b40ed09a3c315b81'
7
- data.tar.gz: d82ee10469742e83ee412ebe6c06593a86c44c1e0f01fd29067700d9a37ecc461dc3e4ad6e2a09bfe4694d1e95b6c28132810bf243d27338257f66e0c50cc98e
6
+ metadata.gz: 23d0a177d1b2bfe8ba70ca0de182785ef9016d271e28ae36dd5590aae7f0b30d6a9ae1336948d3a862bf6b04afcc75cb2a115c3de589509cf46bd4a471c5e054
7
+ data.tar.gz: 478dc03869f1913f736db5ec2c69ff17c68440463f4cf23f337ef5d3b41cc944242075ce0bc36c1971765563566eb2d86e15f54ff7e1d762f6dbd6ccb3217947
data/CHANGELOG.md CHANGED
@@ -1,5 +1,64 @@
1
1
  <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
2
2
 
3
+ ## 1.10.4 2022-10-13
4
+
5
+
6
+ ### Fixed
7
+
8
+ - Once again reverting zeitwerk related changes that were included in 1.10.3 by an accident :( (@solnic)
9
+
10
+
11
+ [Compare v1.10.3...v1.10.4](https://github.com/dry-rb/dry-schema/compare/v1.10.3...v1.10.4)
12
+
13
+ ## 1.10.3 2022-10-10
14
+
15
+
16
+ ### Fixed
17
+
18
+ - Addressed regressions causing issues with handling sum types (see #419 and #423 fixed via #425) (@robhanlon22)
19
+
20
+
21
+ [Compare v1.10.2...v1.10.3](https://github.com/dry-rb/dry-schema/compare/v1.10.2...v1.10.3)
22
+
23
+ ## 1.10.2 2022-08-23
24
+
25
+
26
+ ### Fixed
27
+
28
+ - Fix value coercion for composed schemas (via #421) (@robhanlon22)
29
+
30
+
31
+ [Compare v1.10.1...v1.10.2](https://github.com/dry-rb/dry-schema/compare/v1.10.1...v1.10.2)
32
+
33
+ ## 1.10.1 2022-08-22
34
+
35
+
36
+ ### Changed
37
+
38
+ - Reverted zeitwerk-related changes that were included in 1.10.0 by an accident (@solnic)
39
+
40
+ [Compare v1.10.0...v1.10.1](https://github.com/dry-rb/dry-schema/compare/v1.10.0...v1.10.1)
41
+
42
+ ## 1.10.0 2022-08-16
43
+
44
+
45
+ ### Added
46
+
47
+ - Allow nested `filled` and `value` macro usage (via #412) (@robhanlon22)
48
+ - Support for more complex scenarios when composing schemas (via #420) (@robhanlon22)
49
+
50
+ ### Fixed
51
+
52
+ - Fix `or` messages for complex schemas (via #413) (@robhanlon22)
53
+ - Using `filled` with a constrained constructor type works as expected (via #416) (@robhanlon22)
54
+ - Fix types and key maps for composed schemas (via #415) (@robhanlon22)
55
+
56
+ ### Changed
57
+
58
+ - Freeze message hash (fixes #417 via #418) (@solnic)
59
+
60
+ [Compare v1.9.3...v1.10.0](https://github.com/dry-rb/dry-schema/compare/v1.9.3...v1.10.0)
61
+
3
62
  ## 1.9.3 2022-06-23
4
63
 
5
64
 
@@ -165,7 +224,7 @@ This release ships with a bunch of internal refactorings that should improve per
165
224
 
166
225
  [Compare v1.5.4...v1.5.5](https://github.com/dry-rb/dry-schema/compare/v1.5.4...v1.5.5)
167
226
 
168
- ## 1.5.4
227
+ ## 1.5.4
169
228
 
170
229
  2020-09-03
171
230
 
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2015-2021 dry-rb team
3
+ Copyright (c) 2015-2022 dry-rb team
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of
6
6
  this software and associated documentation files (the "Software"), to deal in
data/dry-schema.gemspec CHANGED
@@ -38,7 +38,7 @@ Gem::Specification.new do |spec|
38
38
  spec.add_runtime_dependency "dry-configurable", "~> 0.13", ">= 0.13.0"
39
39
  spec.add_runtime_dependency "dry-core", "~> 0.5", ">= 0.5"
40
40
  spec.add_runtime_dependency "dry-initializer", "~> 3.0"
41
- spec.add_runtime_dependency "dry-logic", "~> 1.0"
41
+ spec.add_runtime_dependency "dry-logic", "~> 1.2"
42
42
  spec.add_runtime_dependency "dry-types", "~> 1.5"
43
43
 
44
44
  spec.add_development_dependency "bundler"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/initializer"
4
+ require "dry/logic"
4
5
 
5
6
  require "dry/schema/constants"
6
7
  require "dry/schema/path"
@@ -16,6 +17,7 @@ require "dry/schema/key_coercer"
16
17
  require "dry/schema/key_validator"
17
18
  require "dry/schema/value_coercer"
18
19
  require "dry/schema/rule_applier"
20
+ require "dry/schema/types_merger"
19
21
 
20
22
  module Dry
21
23
  module Schema
@@ -286,13 +288,20 @@ module Dry
286
288
 
287
289
  # Return type schema used by the value coercer
288
290
  #
289
- # @return [Dry::Types::Safe]
291
+ # @return [Dry::Types::Lax]
290
292
  #
291
293
  # @api private
292
294
  def type_schema
293
- our_schema = type_registry["hash"].schema(types).lax
294
- schemas = [*parents.map(&:type_schema), our_schema]
295
- schemas.inject { |result, schema| result.schema(schema.to_a) }
295
+ strict_type_schema.lax
296
+ end
297
+
298
+ # Return type schema used when composing subschemas
299
+ #
300
+ # @return [Dry::Types::Schema]
301
+ #
302
+ # @api private
303
+ def strict_type_schema
304
+ type_registry["hash"].schema(types)
296
305
  end
297
306
 
298
307
  # Return a new DSL instance using the same processor type
@@ -314,9 +323,9 @@ module Dry
314
323
  # @api private
315
324
  def set_type(name, spec)
316
325
  type = resolve_type(spec)
317
- meta = {required: false, maybe: type.optional?}
326
+ meta = {required: true, maybe: type.optional?}
318
327
 
319
- types[name] = type.meta(meta)
328
+ @types[name] = type.meta(meta)
320
329
  end
321
330
 
322
331
  # Check if a custom type was set under provided key name
@@ -369,6 +378,18 @@ module Dry
369
378
  parents.any?(&:filter_rules?)
370
379
  end
371
380
 
381
+ # This DSL's type map merged with any parent type maps
382
+ #
383
+ # @api private
384
+ def types
385
+ [*parents.map(&:types), @types].reduce(:merge)
386
+ end
387
+
388
+ # @api private
389
+ def merge_types(op_class, lhs, rhs)
390
+ types_merger.(op_class, lhs, rhs)
391
+ end
392
+
372
393
  protected
373
394
 
374
395
  # Build a rule applier
@@ -495,6 +516,10 @@ module Dry
495
516
 
496
517
  (parent || Schema).config.dup
497
518
  end
519
+
520
+ def types_merger
521
+ @types_merger ||= TypesMerger.new(type_registry)
522
+ end
498
523
  end
499
524
  end
500
525
  end
@@ -15,7 +15,7 @@ module Dry
15
15
  def value(*args, **opts, &block)
16
16
  type(:array)
17
17
 
18
- extract_type_spec(*args, set_type: false) do |*predicates, type_spec:, type_rule:|
18
+ extract_type_spec(args, set_type: false) do |*predicates, type_spec:, type_rule:|
19
19
  type(schema_dsl.array[type_spec]) if type_spec
20
20
 
21
21
  is_hash_block = type_spec.equal?(:hash)
@@ -58,12 +58,13 @@ module Dry
58
58
  # @return [Macros::Core]
59
59
  #
60
60
  # @api public
61
- def value(...)
62
- append_macro(Macros::Value) do |macro|
63
- macro.call(...)
61
+ def value(*args, **opts, &block)
62
+ extract_type_spec(args) do |*predicates, type_spec:, type_rule:|
63
+ append_macro(Macros::Value) do |macro|
64
+ macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
65
+ end
64
66
  end
65
67
  end
66
- ruby2_keywords :value if respond_to?(:ruby2_keywords, true)
67
68
 
68
69
  # Prepends `:filled?` predicate
69
70
  #
@@ -76,12 +77,31 @@ module Dry
76
77
  # @return [Macros::Core]
77
78
  #
78
79
  # @api public
79
- def filled(...)
80
- append_macro(Macros::Filled) do |macro|
81
- macro.call(...)
80
+ def filled(*args, **opts, &block)
81
+ extract_type_spec(args) do |*predicates, type_spec:, type_rule:|
82
+ append_macro(Macros::Filled) do |macro|
83
+ macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
84
+ end
85
+ end
86
+ end
87
+
88
+ # Set type specification and predicates for a maybe value
89
+ #
90
+ # @example
91
+ # required(:name).maybe(:string)
92
+ #
93
+ # @see Macros::Key#value
94
+ #
95
+ # @return [Macros::Key]
96
+ #
97
+ # @api public
98
+ def maybe(*args, **opts, &block)
99
+ extract_type_spec(args, nullable: true) do |*predicates, type_spec:, type_rule:|
100
+ append_macro(Macros::Maybe) do |macro|
101
+ macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
102
+ end
82
103
  end
83
104
  end
84
- ruby2_keywords :filled if respond_to?(:ruby2_keywords, true)
85
105
 
86
106
  # Specify a nested hash without enforced `hash?` type-check
87
107
  #
@@ -201,7 +221,7 @@ module Dry
201
221
 
202
222
  # @api private
203
223
  # rubocop: disable Metrics/PerceivedComplexity
204
- def extract_type_spec(*args, nullable: false, set_type: true)
224
+ def extract_type_spec(args, nullable: false, set_type: true)
205
225
  type_spec = args[0] unless schema_or_predicate?(args[0])
206
226
 
207
227
  predicates = Array(type_spec ? args[1..] : args)
@@ -11,13 +11,15 @@ module Dry
11
11
  # @api private
12
12
  class Each < DSL
13
13
  # @api private
14
- def value(*args, **opts)
15
- extract_type_spec(*args, set_type: false) do |*predicates, type_spec:, type_rule:|
14
+ def value(*args, **opts, &block)
15
+ extract_type_spec(args, set_type: false) do |*predicates, type_spec:, type_rule:|
16
16
  if type_spec && !type_spec.is_a?(Dry::Types::Type)
17
17
  type(schema_dsl.array[type_spec])
18
18
  end
19
19
 
20
- super(*predicates, type_spec: type_spec, type_rule: type_rule, **opts)
20
+ append_macro(Macros::Value) do |macro|
21
+ macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
22
+ end
21
23
  end
22
24
  end
23
25
 
@@ -13,12 +13,15 @@ module Dry
13
13
  def call(*predicates, **opts, &block)
14
14
  ensure_valid_predicates(predicates)
15
15
 
16
- if opts[:type_spec] && !filter_empty_string?
17
- value(predicates[0], :filled?, *predicates[1..predicates.size - 1], **opts, &block)
18
- elsif opts[:type_rule]
19
- value(:filled?).value(*predicates, **opts, &block)
20
- else
21
- value(:filled?, *predicates, **opts, &block)
16
+ append_macro(Macros::Value) do |macro|
17
+ if opts[:type_spec] && !filter_empty_string?
18
+ macro.call(predicates[0], :filled?, *predicates[1..predicates.size - 1], **opts,
19
+ &block)
20
+ elsif opts[:type_rule]
21
+ macro.call(:filled?).value(*predicates, **opts, &block)
22
+ else
23
+ macro.call(:filled?, *predicates, **opts, &block)
24
+ end
22
25
  end
23
26
  end
24
27
 
@@ -32,67 +32,6 @@ module Dry
32
32
  end
33
33
  ruby2_keywords(:filter) if respond_to?(:ruby2_keywords, true)
34
34
 
35
- # @overload value(type_spec, *predicates, **predicate_opts)
36
- # Set type specification and predicates
37
- #
38
- # @param [Symbol,Types::Type,Array] type_spec
39
- # @param [Array<Symbol>] predicates
40
- # @param [Hash] predicate_opts
41
- #
42
- # @example with a predicate
43
- # required(:name).value(:string, :filled?)
44
- #
45
- # @example with a predicate with arguments
46
- # required(:name).value(:string, min_size?: 2)
47
- #
48
- # @example with a block
49
- # required(:name).value(:string) { filled? & min_size?(2) }
50
- #
51
- # @return [Macros::Key]
52
- #
53
- # @see Macros::DSL#value
54
- #
55
- # @api public
56
- def value(*args, **opts, &block)
57
- extract_type_spec(*args) do |*predicates, type_spec:, type_rule:|
58
- super(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
59
- end
60
- end
61
-
62
- # Set type specification and predicates for a filled value
63
- #
64
- # @example
65
- # required(:name).filled(:string)
66
- #
67
- # @see Macros::Key#value
68
- #
69
- # @return [Macros::Key]
70
- #
71
- # @api public
72
- def filled(*args, **opts, &block)
73
- extract_type_spec(*args) do |*predicates, type_spec:, type_rule:|
74
- super(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
75
- end
76
- end
77
-
78
- # Set type specification and predicates for a maybe value
79
- #
80
- # @example
81
- # required(:name).maybe(:string)
82
- #
83
- # @see Macros::Key#value
84
- #
85
- # @return [Macros::Key]
86
- #
87
- # @api public
88
- def maybe(*args, **opts, &block)
89
- extract_type_spec(*args, nullable: true) do |*predicates, type_spec:, type_rule:|
90
- append_macro(Macros::Maybe) do |macro|
91
- macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
92
- end
93
- end
94
- end
95
-
96
35
  # Coerce macro to a rule
97
36
  #
98
37
  # @return [Dry::Logic::Rule]
@@ -19,7 +19,9 @@ module Dry
19
19
  raise ::Dry::Schema::InvalidSchemaError, "Using maybe with nil? predicate is redundant"
20
20
  end
21
21
 
22
- value(*args, **opts, &block)
22
+ append_macro(Macros::Value) do |macro|
23
+ macro.call(*args, **opts, &block)
24
+ end
23
25
 
24
26
  self
25
27
  end
@@ -30,13 +30,7 @@ module Dry
30
30
 
31
31
  # @api private
32
32
  def process_operation(op)
33
- schemas = op.rules.select { |rule| rule.is_a?(Processor) }
34
-
35
- hash_schema = hash_type.schema(
36
- schemas.map(&:schema_dsl).map(&:types).reduce(:merge)
37
- )
38
-
39
- type(hash_schema)
33
+ type(hash_type.schema(merge_operation_types(op)))
40
34
  end
41
35
 
42
36
  # @api private
@@ -44,6 +38,23 @@ module Dry
44
38
  schema_dsl.resolve_type(:hash)
45
39
  end
46
40
 
41
+ # @api private
42
+ def merge_operation_types(op)
43
+ op.rules.reduce({}) do |acc, rule|
44
+ types =
45
+ case rule
46
+ when Dry::Logic::Operations::Abstract
47
+ merge_operation_types(rule)
48
+ when Processor
49
+ rule.types
50
+ else
51
+ EMPTY_HASH.dup
52
+ end
53
+
54
+ schema_dsl.merge_types(op.class, acc, types)
55
+ end
56
+ end
57
+
47
58
  # @api private
48
59
  # rubocop: disable Metrics/AbcSize
49
60
  def define(*args, &block)
@@ -51,11 +62,11 @@ module Dry
51
62
  schema = definition.call
52
63
  type_schema =
53
64
  if array_type?(parent_type)
54
- build_array_type(parent_type, definition.type_schema)
65
+ build_array_type(parent_type, definition.strict_type_schema)
55
66
  elsif redefined_schema?(args)
56
67
  parent_type.schema(definition.types)
57
68
  else
58
- definition.type_schema
69
+ definition.strict_type_schema
59
70
  end
60
71
  final_type = optional? ? type_schema.optional : type_schema
61
72
 
@@ -30,9 +30,9 @@ module Dry
30
30
 
31
31
  updated_type =
32
32
  if array_type?(current_type)
33
- build_array_type(current_type, schema.type_schema)
33
+ build_array_type(current_type, schema.strict_type_schema)
34
34
  else
35
- schema.type_schema
35
+ schema.strict_type_schema
36
36
  end
37
37
 
38
38
  import_steps(schema)
@@ -34,17 +34,16 @@ module Dry
34
34
  end
35
35
  end
36
36
 
37
- # @api private
38
- def self.handler(message)
39
- handlers.find { |k,| message.is_a?(k) }&.last
40
- end
37
+ MESSAGE_ARRAY_HANDLER = -> { MessageArray.new(_1) }
41
38
 
42
39
  # @api private
43
- private_class_method def self.handlers
44
- @handlers ||= {
45
- self => -> { _1 },
46
- Array => -> { MessageArray.new(_1) }
47
- }.freeze
40
+ def self.handler(message)
41
+ case message
42
+ when self
43
+ IDENTITY
44
+ when Array
45
+ MESSAGE_ARRAY_HANDLER
46
+ end
48
47
  end
49
48
 
50
49
  # @api public
@@ -59,7 +58,7 @@ module Dry
59
58
 
60
59
  # @api private
61
60
  def root
62
- @root ||= _messages.flat_map(&:_paths).reduce(:&)
61
+ @root ||= _paths.reduce(:&)
63
62
  end
64
63
 
65
64
  # @api private
@@ -67,9 +66,14 @@ module Dry
67
66
  root
68
67
  end
69
68
 
69
+ # @api private
70
+ def _path
71
+ @_path ||= Path[root]
72
+ end
73
+
70
74
  # @api private
71
75
  def _paths
72
- @paths ||= [Path[root]]
76
+ @paths ||= _messages.flat_map(&:_paths)
73
77
  end
74
78
 
75
79
  # @api private
@@ -21,10 +21,11 @@ module Dry
21
21
 
22
22
  # @api private
23
23
  def initialize(*args, messages)
24
- super(*args)
24
+ super(*args.map { [_1].flatten })
25
25
  @messages = messages
26
- @path = left.path
27
- @_path = left._path
26
+ message = left.first
27
+ @path = message.path
28
+ @_path = message._path
28
29
  end
29
30
 
30
31
  # Dump a message into a string
@@ -38,7 +39,7 @@ module Dry
38
39
  #
39
40
  # @api public
40
41
  def dump
41
- @dump ||= "#{left.dump} #{messages[:or]} #{right.dump}"
42
+ @dump ||= [*left, *right].map(&:dump).join(" #{messages[:or]} ")
42
43
  end
43
44
  alias_method :to_s, :dump
44
45
 
@@ -55,7 +56,16 @@ module Dry
55
56
 
56
57
  # @api private
57
58
  def to_a
58
- @to_a ||= [left, right]
59
+ @to_a ||= [*left, *right]
60
+ end
61
+
62
+ # @api private
63
+ def to_or(root)
64
+ to_ored = [left, right].map do |msgs|
65
+ msgs.map { _1.to_or(root) }
66
+ end
67
+
68
+ self.class.new(*to_ored, messages)
59
69
  end
60
70
  end
61
71
  end
@@ -105,7 +105,7 @@ module Dry
105
105
 
106
106
  # @api private
107
107
  def messages_map(messages = self.messages)
108
- combine_message_hashes(messages.map(&:to_h))
108
+ combine_message_hashes(messages.map(&:to_h)).freeze
109
109
  end
110
110
 
111
111
  # @api private
@@ -138,13 +138,22 @@ module Dry
138
138
 
139
139
  # Return the type schema
140
140
  #
141
- # @return [Dry::Types::Safe]
141
+ # @return [Dry::Types::Lax]
142
142
  #
143
143
  # @api private
144
144
  def type_schema
145
145
  steps.type_schema
146
146
  end
147
147
 
148
+ # Return type schema used when composing subschemas
149
+ #
150
+ # @return [Dry::Types::Schema]
151
+ #
152
+ # @api private
153
+ def strict_type_schema
154
+ schema_dsl.strict_type_schema
155
+ end
156
+
148
157
  # Return the rule applier
149
158
  #
150
159
  # @api private
@@ -188,6 +197,13 @@ module Dry
188
197
  rule_applier.rules
189
198
  end
190
199
 
200
+ # Return the types from the schema DSL
201
+ #
202
+ # @api private
203
+ def types
204
+ schema_dsl.types
205
+ end
206
+
191
207
  # Check if there are filter rules
192
208
  #
193
209
  # @api private
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Schema
5
+ # Combines multiple logical operations into a single type, taking into
6
+ # account the type of logical operation (or, and, implication) and the
7
+ # underlying types (schemas, nominals, etc.)
8
+ #
9
+ # @api private
10
+ class TypesMerger
11
+ attr_reader :type_registry
12
+
13
+ # @api private
14
+ class ValueMerger
15
+ attr_reader :types_merger
16
+ attr_reader :op_class
17
+ attr_reader :old
18
+ attr_reader :new
19
+
20
+ # @api private
21
+ def initialize(types_merger, op_class, old, new)
22
+ @types_merger = types_merger
23
+ @op_class = op_class
24
+ @old = old
25
+ @new = new
26
+ end
27
+
28
+ # @api private
29
+ def call
30
+ if op_class <= Dry::Logic::Operations::Or
31
+ merge_or
32
+ elsif op_class <= Dry::Logic::Operations::And
33
+ merge_and
34
+ elsif op_class <= Dry::Logic::Operations::Implication
35
+ merge_implication
36
+ else
37
+ raise ArgumentError, <<~MESSAGE
38
+ Can't merge operations, op_class=#{op_class}
39
+ MESSAGE
40
+ end
41
+ end
42
+
43
+ private
44
+
45
+ # @api private
46
+ def merge_or
47
+ old | new
48
+ end
49
+
50
+ # @api private
51
+ def merge_ordered
52
+ return old if old == new
53
+
54
+ unwrapped_old, old_rule = unwrap_type(old)
55
+ unwrapped_new, new_rule = unwrap_type(new)
56
+
57
+ type = merge_unwrapped_types(unwrapped_old, unwrapped_new)
58
+
59
+ rule = [old_rule, new_rule].compact.reduce { op_class.new(_1, _2) }
60
+
61
+ type = Dry::Types::Constrained.new(type, rule: rule) if rule
62
+
63
+ type
64
+ end
65
+
66
+ alias_method :merge_and, :merge_ordered
67
+ alias_method :merge_implication, :merge_ordered
68
+
69
+ # @api private
70
+ def merge_unwrapped_types(unwrapped_old, unwrapped_new)
71
+ case [unwrapped_old, unwrapped_new]
72
+ in Dry::Types::Schema, Dry::Types::Schema
73
+ merge_schemas(unwrapped_old, unwrapped_new)
74
+ in [Dry::Types::AnyClass, _] | [Dry::Types::Hash, Dry::Types::Schema]
75
+ unwrapped_new
76
+ in [Dry::Types::Schema, Dry::Types::Hash] | [_, Dry::Types::AnyClass]
77
+ unwrapped_old
78
+ else
79
+ merge_equivalent_types(unwrapped_old, unwrapped_new)
80
+ end
81
+ end
82
+
83
+ # @api private
84
+ def merge_schemas(unwrapped_old, unwrapped_new)
85
+ types_merger.type_registry["hash"].schema(
86
+ types_merger.call(
87
+ op_class,
88
+ unwrapped_old.name_key_map,
89
+ unwrapped_new.name_key_map
90
+ )
91
+ )
92
+ end
93
+
94
+ # @api private
95
+ def merge_equivalent_types(unwrapped_old, unwrapped_new)
96
+ if unwrapped_old.primitive <= unwrapped_new.primitive
97
+ unwrapped_new
98
+ elsif unwrapped_new.primitive <= unwrapped_old.primitive
99
+ unwrapped_old
100
+ else
101
+ raise ArgumentError, <<~MESSAGE
102
+ Can't merge types, unwrapped_old=#{unwrapped_old.inspect}, unwrapped_new=#{unwrapped_new.inspect}
103
+ MESSAGE
104
+ end
105
+ end
106
+
107
+ # @api private
108
+ def unwrap_type(type)
109
+ rules = []
110
+
111
+ loop do
112
+ rules << type.rule if type.respond_to?(:rule)
113
+
114
+ if type.optional?
115
+ type = type.left.primitive?(nil) ? type.right : type.left
116
+ elsif type.is_a?(Dry::Types::Decorator)
117
+ type = type.type
118
+ else
119
+ break
120
+ end
121
+ end
122
+
123
+ [type, rules.reduce(:&)]
124
+ end
125
+ end
126
+
127
+ def initialize(type_registry = TypeRegistry.new)
128
+ @type_registry = type_registry
129
+ end
130
+
131
+ # @api private
132
+ def call(op_class, lhs, rhs)
133
+ lhs.merge(rhs) do |_k, old, new|
134
+ ValueMerger.new(self, op_class, old, new).call
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Schema
5
- VERSION = "1.9.3"
5
+ VERSION = "1.10.4"
6
6
  end
7
7
  end
data/lib/dry/schema.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "dry/core/extensions"
4
+ require "dry/configurable"
5
+ require "dry/logic"
4
6
 
5
7
  require "dry/schema/config"
6
8
  require "dry/schema/constants"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dry-schema
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.3
4
+ version: 1.10.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Solnica
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-06-23 00:00:00.000000000 Z
11
+ date: 2022-09-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -84,14 +84,14 @@ dependencies:
84
84
  requirements:
85
85
  - - "~>"
86
86
  - !ruby/object:Gem::Version
87
- version: '1.0'
87
+ version: '1.2'
88
88
  type: :runtime
89
89
  prerelease: false
90
90
  version_requirements: !ruby/object:Gem::Requirement
91
91
  requirements:
92
92
  - - "~>"
93
93
  - !ruby/object:Gem::Version
94
- version: '1.0'
94
+ version: '1.2'
95
95
  - !ruby/object:Gem::Dependency
96
96
  name: dry-types
97
97
  requirement: !ruby/object:Gem::Requirement
@@ -230,6 +230,7 @@ files:
230
230
  - lib/dry/schema/type_container.rb
231
231
  - lib/dry/schema/type_registry.rb
232
232
  - lib/dry/schema/types.rb
233
+ - lib/dry/schema/types_merger.rb
233
234
  - lib/dry/schema/value_coercer.rb
234
235
  - lib/dry/schema/version.rb
235
236
  homepage: https://dry-rb.org/gems/dry-schema