dry-schema 1.9.3 → 1.10.4

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 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