dry-schema 1.9.1 → 1.10.1

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: c4447e05345b9fee9c6fa8014f1650d2f366428450f1a8b5de29da67794db47f
4
- data.tar.gz: 5dd78346a5a1f0e8df66f81ccb409e5870b409bb24547960954680b550186125
3
+ metadata.gz: 8aa8d227152a712ff8580d62686ad5a4b83b4439dc8d58f42651b869e203697c
4
+ data.tar.gz: e22028010d0ac11567a8a615725496f77db8a2acd107350363b20174da01a20c
5
5
  SHA512:
6
- metadata.gz: 1545a765733867780eef3bbfdcb4a5bf2fa9a4e7a5c7c47542a720e19f0b43a0ceef35e59a1c8238a4d4c2a38c7c01690d70df3677bc8a46f1e47d0d9eef3996
7
- data.tar.gz: a9c514202ba40aa68a503fa06a11f814cdaef34f196ad14664d23b13d713d364d328cfb73acbd889d55687e7e157e65b1e433df512c1ea2a18ff81bd5c7cb119
6
+ metadata.gz: ad3350414c764971f4c0e69ca07044901d67488625c691f2a7396c6d17b33d31a2714e8959d5f07598c03894883b7854090c6d77b182f7569acc7a32b43be3d3
7
+ data.tar.gz: 93320abcdadd4f3c48666507f829d4aaba2c9fc5ae181d2cd68f44e28eb850a8ead7adec29c7be935e17fe4112df09d17ac735dac9f50c49d45e5031f15d1ce6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,62 @@
1
1
  <!--- DO NOT EDIT THIS FILE - IT'S AUTOMATICALLY GENERATED VIA DEVTOOLS --->
2
2
 
3
+ ## 1.10.1 2022-08-22
4
+
5
+
6
+ ### Changed
7
+
8
+ - Reverted zeitwerk-related changes that were included in 1.10.0 by an accident (@solnic)
9
+
10
+ [Compare v1.10.0...v1.10.1](https://github.com/dry-rb/dry-schema/compare/v1.10.0...v1.10.1)
11
+
12
+ ## 1.10.0 2022-08-16
13
+
14
+
15
+ ### Added
16
+
17
+ - Allow nested `filled` and `value` macro usage (via #412) (@robhanlon22)
18
+ - Support for more complex scenarios when composing schemas (via #420) (@robhanlon22)
19
+
20
+ ### Fixed
21
+
22
+ - Fix `or` messages for complex schemas (via #413) (@robhanlon22)
23
+ - Using `filled` with a constrained constructor type works as expected (via #416) (@robhanlon22)
24
+ - Fix types and key maps for composed schemas (via #415) (@robhanlon22)
25
+
26
+ ### Changed
27
+
28
+ - Freeze message hash (fixes #417 via #418) (@solnic)
29
+
30
+ [Compare v1.9.3...v1.10.0](https://github.com/dry-rb/dry-schema/compare/v1.9.3...v1.10.0)
31
+
32
+ ## 1.9.3 2022-06-23
33
+
34
+
35
+ ### Added
36
+
37
+ - Support `anyOf` composition in JSON schema output (@robhanlon22)
38
+
39
+ ### Fixed
40
+
41
+ - Allow composition of multiple ors (issue #307 fixed via #409) (@robhanlon22)
42
+
43
+
44
+ [Compare v1.9.2...v1.9.3](https://github.com/dry-rb/dry-schema/compare/v1.9.2...v1.9.3)
45
+
46
+ ## 1.9.2 2022-05-28
47
+
48
+
49
+ ### Fixed
50
+
51
+ - Fix loose JSON schemas for nested hashes (via #401) (@tomdalling)
52
+ - Correct spelling error 'mininum' to 'minimum' in json-schema extension (via #404) (@svenanderzen)
53
+
54
+ ### Changed
55
+
56
+ - [performance] YAML message backend allocates less strings (via #399) (@casperisfine)
57
+
58
+ [Compare v1.9.1...v1.9.2](https://github.com/dry-rb/dry-schema/compare/v1.9.1...v1.9.2)
59
+
3
60
  ## 1.9.1 2022-02-17
4
61
 
5
62
 
@@ -146,7 +203,7 @@ This release ships with a bunch of internal refactorings that should improve per
146
203
  - Key validation works correctly with a non-nested maybe hashes (issue #311 fixed via #312) (@svobom57)
147
204
 
148
205
 
149
- [Compare v1.5.3...master](https://github.com/dry-rb/dry-schema/compare/v1.5.3...master)
206
+ [Compare v1.5.3...main](https://github.com/dry-rb/dry-schema/compare/v1.5.3...main)
150
207
 
151
208
  ## 1.5.3 2020-08-21
152
209
 
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/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  [![CI Status](https://github.com/dry-rb/dry-schema/workflows/ci/badge.svg)][actions]
12
12
  [![Codacy Badge](https://api.codacy.com/project/badge/Grade/961f5c776f1d49218b2cede3745e059c)][codacy]
13
13
  [![Codacy Badge](https://api.codacy.com/project/badge/Coverage/961f5c776f1d49218b2cede3745e059c)][codacy]
14
- [![Inline docs](http://inch-ci.org/github/dry-rb/dry-schema.svg?branch=master)][inchpages]
14
+ [![Inline docs](http://inch-ci.org/github/dry-rb/dry-schema.svg?branch=main)][inchpages]
15
15
 
16
16
  ## Links
17
17
 
data/dry-schema.gemspec CHANGED
@@ -27,7 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.require_paths = ["lib"]
28
28
 
29
29
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
30
- spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-schema/blob/master/CHANGELOG.md"
30
+ spec.metadata["changelog_uri"] = "https://github.com/dry-rb/dry-schema/blob/main/CHANGELOG.md"
31
31
  spec.metadata["source_code_uri"] = "https://github.com/dry-rb/dry-schema"
32
32
  spec.metadata["bug_tracker_uri"] = "https://github.com/dry-rb/dry-schema/issues"
33
33
 
@@ -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
@@ -316,7 +318,7 @@ module Dry
316
318
  type = resolve_type(spec)
317
319
  meta = {required: false, maybe: type.optional?}
318
320
 
319
- types[name] = type.meta(meta)
321
+ @types[name] = type.meta(meta)
320
322
  end
321
323
 
322
324
  # Check if a custom type was set under provided key name
@@ -369,6 +371,18 @@ module Dry
369
371
  parents.any?(&:filter_rules?)
370
372
  end
371
373
 
374
+ # This DSL's type map merged with any parent type maps
375
+ #
376
+ # @api private
377
+ def types
378
+ [*parents.map(&:types), @types].reduce(:merge)
379
+ end
380
+
381
+ # @api private
382
+ def merge_types(op_class, lhs, rhs)
383
+ types_merger.(op_class, lhs, rhs)
384
+ end
385
+
372
386
  protected
373
387
 
374
388
  # Build a rule applier
@@ -495,6 +509,10 @@ module Dry
495
509
 
496
510
  (parent || Schema).config.dup
497
511
  end
512
+
513
+ def types_merger
514
+ @types_merger ||= TypesMerger.new(type_registry)
515
+ end
498
516
  end
499
517
  end
500
518
  end
@@ -47,7 +47,7 @@ module Dry
47
47
  pattern: "^[0-9A-F]{8}-[0-9A-F]{4}-5[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$"
48
48
  },
49
49
  gt?: {exclusiveMinimum: IDENTITY},
50
- gteq?: {mininum: IDENTITY},
50
+ gteq?: {minimum: IDENTITY},
51
51
  lt?: {exclusiveMaximum: IDENTITY},
52
52
  lteq?: {maximum: IDENTITY},
53
53
  odd?: {type: "integer", not: {multipleOf: 2}},
@@ -88,7 +88,7 @@ module Dry
88
88
 
89
89
  # @api private
90
90
  def visit_set(node, opts = EMPTY_HASH)
91
- target = (key = opts[:key]) ? self.class.new : self
91
+ target = (key = opts[:key]) ? self.class.new(loose: loose?) : self
92
92
 
93
93
  node.map { |child| target.visit(child, opts) }
94
94
 
@@ -114,6 +114,18 @@ module Dry
114
114
  end
115
115
  end
116
116
 
117
+ # @api private
118
+ def visit_or(node, opts = EMPTY_HASH)
119
+ node.each do |child|
120
+ c = self.class.new(loose: loose?)
121
+ c.keys.update(subschema: {})
122
+ c.visit(child, opts.merge(key: :subschema))
123
+
124
+ any_of = (keys[opts[:key]][:anyOf] ||= [])
125
+ any_of << c.keys[:subschema]
126
+ end
127
+ end
128
+
117
129
  # @api private
118
130
  def visit_implication(node, opts = EMPTY_HASH)
119
131
  node.each do |el|
@@ -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,13 @@ 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
82
85
  end
83
86
  end
84
- ruby2_keywords :filled if respond_to?(:ruby2_keywords, true)
85
87
 
86
88
  # Specify a nested hash without enforced `hash?` type-check
87
89
  #
@@ -201,7 +203,7 @@ module Dry
201
203
 
202
204
  # @api private
203
205
  # rubocop: disable Metrics/PerceivedComplexity
204
- def extract_type_spec(*args, nullable: false, set_type: true)
206
+ def extract_type_spec(args, nullable: false, set_type: true)
205
207
  type_spec = args[0] unless schema_or_predicate?(args[0])
206
208
 
207
209
  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
 
@@ -32,49 +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
35
  # Set type specification and predicates for a maybe value
79
36
  #
80
37
  # @example
@@ -86,7 +43,7 @@ module Dry
86
43
  #
87
44
  # @api public
88
45
  def maybe(*args, **opts, &block)
89
- extract_type_spec(*args, nullable: true) do |*predicates, type_spec:, type_rule:|
46
+ extract_type_spec(args, nullable: true) do |*predicates, type_spec:, type_rule:|
90
47
  append_macro(Macros::Maybe) do |macro|
91
48
  macro.call(*predicates, type_spec: type_spec, type_rule: type_rule, **opts, &block)
92
49
  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)
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dry/core/equalizer"
4
-
5
3
  require "dry/schema/message/or/abstract"
6
4
  require "dry/schema/path"
7
5
 
@@ -14,23 +12,89 @@ module Dry
14
12
  # @api public
15
13
  class MultiPath < Abstract
16
14
  # @api private
17
- attr_reader :root
15
+ class MessageArray
16
+ # @api private
17
+ def initialize(messages)
18
+ @messages = messages.flatten
19
+ end
20
+
21
+ # @api private
22
+ def _paths
23
+ @messages.map(&:_path)
24
+ end
25
+
26
+ # @api private
27
+ def to_or(root)
28
+ self.class.new(@messages.map { _1.to_or(root) })
29
+ end
30
+
31
+ # @api private
32
+ def to_h
33
+ MessageSet.new(@messages).to_h
34
+ end
35
+ end
36
+
37
+ MESSAGE_ARRAY_HANDLER = -> { MessageArray.new(_1) }
18
38
 
19
39
  # @api private
20
- def initialize(...)
21
- super
22
- flat_left = left.flatten
23
- flat_right = right.flatten
24
- @root = [*flat_left, *flat_right].map(&:_path).reduce(:&)
25
- @left = flat_left.map { _1.to_or(root) }
26
- @right = flat_right.map { _1.to_or(root) }
40
+ def self.handler(message)
41
+ case message
42
+ when self
43
+ IDENTITY
44
+ when Array
45
+ MESSAGE_ARRAY_HANDLER
46
+ end
27
47
  end
28
48
 
29
49
  # @api public
30
50
  def to_h
31
- @to_h ||= Path[[*root, :or]].to_h(
32
- [MessageSet.new(left).to_h, MessageSet.new(right).to_h]
33
- )
51
+ @to_h ||= Path[[*root, :or]].to_h(messages.map(&:to_h))
52
+ end
53
+
54
+ # @api private
55
+ def messages
56
+ @messages ||= _messages.flat_map { _1.to_or(root) }
57
+ end
58
+
59
+ # @api private
60
+ def root
61
+ @root ||= _paths.reduce(:&)
62
+ end
63
+
64
+ # @api private
65
+ def path
66
+ root
67
+ end
68
+
69
+ # @api private
70
+ def _path
71
+ @_path ||= Path[root]
72
+ end
73
+
74
+ # @api private
75
+ def _paths
76
+ @paths ||= _messages.flat_map(&:_paths)
77
+ end
78
+
79
+ # @api private
80
+ def to_or(root)
81
+ self.root == root ? messages : [self]
82
+ end
83
+
84
+ private
85
+
86
+ # @api private
87
+ def _messages
88
+ @_messages ||= [left, right].map do |message|
89
+ handler = self.class.handler(message)
90
+
91
+ unless handler
92
+ raise ArgumentError,
93
+ "#{message.inspect} is of unknown type #{message.class.inspect}"
94
+ end
95
+
96
+ handler.(message)
97
+ end
34
98
  end
35
99
  end
36
100
  end
@@ -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
@@ -17,8 +17,8 @@ module Dry
17
17
 
18
18
  if paths.uniq.size == 1
19
19
  SinglePath.new(left, right, messages)
20
- elsif right.is_a?(Array)
21
- if left.is_a?(Array) && paths.uniq.size > 1
20
+ elsif MultiPath.handler(right)
21
+ if MultiPath.handler(left) && paths.uniq.size > 1
22
22
  MultiPath.new(left, right)
23
23
  else
24
24
  right
@@ -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
@@ -39,10 +39,10 @@ module Dry
39
39
  super do |config|
40
40
  config.default_locale = :en unless config.default_locale
41
41
 
42
- config.root = "%<locale>s.#{config.root}"
42
+ config.root = -"%<locale>s.#{config.root}"
43
43
 
44
44
  config.rule_lookup_paths = config.rule_lookup_paths.map { |path|
45
- "%<locale>s.#{path}"
45
+ -"%<locale>s.#{path}"
46
46
  }
47
47
  end
48
48
  end
@@ -116,7 +116,7 @@ module Dry
116
116
  ->(input) { call(input) }
117
117
  end
118
118
 
119
- # Return string represntation
119
+ # Return string representation
120
120
  #
121
121
  # @return [String]
122
122
  #
@@ -188,6 +188,13 @@ module Dry
188
188
  rule_applier.rules
189
189
  end
190
190
 
191
+ # Return the types from the schema DSL
192
+ #
193
+ # @api private
194
+ def types
195
+ schema_dsl.types
196
+ end
197
+
191
198
  # Check if there are filter rules
192
199
  #
193
200
  # @api private
@@ -0,0 +1,125 @@
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
+ handlers.fetch(op_class).call
31
+ end
32
+
33
+ private
34
+
35
+ # @api private
36
+ def handlers
37
+ @handlers ||=
38
+ {
39
+ Dry::Logic::Operations::Or => method(:handle_or),
40
+ Dry::Logic::Operations::And => method(:handle_and),
41
+ Dry::Logic::Operations::Implication => method(:handle_implication)
42
+ }
43
+ end
44
+
45
+ # @api private
46
+ def handle_or
47
+ old | new
48
+ end
49
+
50
+ # @api private
51
+ def handle_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_underlying_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 :handle_and, :handle_ordered
67
+ alias_method :handle_implication, :handle_ordered
68
+
69
+ # @api private
70
+ def merge_underlying_types(unwrapped_old, unwrapped_new)
71
+ case [unwrapped_old, unwrapped_new]
72
+ in Dry::Types::Schema, Dry::Types::Schema
73
+ types_merger.type_registry["hash"].schema(
74
+ types_merger.call(
75
+ op_class,
76
+ unwrapped_old.name_key_map,
77
+ unwrapped_new.name_key_map
78
+ )
79
+ )
80
+ in [Dry::Types::AnyClass, _] | [Dry::Types::Hash, Dry::Types::Schema]
81
+ unwrapped_new
82
+ in [Dry::Types::Hash, Dry::Types::Schema] | [_, Dry::Types::AnyClass]
83
+ unwrapped_old
84
+ else
85
+ if unwrapped_old.primitive != unwrapped_new.primitive
86
+ raise ArgumentError, <<~MESSAGE
87
+ Can't merge types, unwrapped_old=#{unwrapped_old.inspect}, unwrapped_new=#{unwrapped_new.inspect}
88
+ MESSAGE
89
+ end
90
+
91
+ unwrapped_old
92
+ end
93
+ end
94
+
95
+ # @api private
96
+ def unwrap_type(type)
97
+ rules = []
98
+
99
+ while type.is_a?(Dry::Types::Decorator)
100
+ rules << type.rule if type.is_a?(Dry::Types::Constrained)
101
+
102
+ if type.meta[:maybe] & type.respond_to?(:right)
103
+ type = type.right
104
+ else
105
+ type = type.type
106
+ end
107
+ end
108
+
109
+ [type, rules.reduce(:&)]
110
+ end
111
+ end
112
+
113
+ def initialize(type_registry = TypeRegistry.new)
114
+ @type_registry = type_registry
115
+ end
116
+
117
+ # @api private
118
+ def call(op_class, lhs, rhs)
119
+ lhs.merge(rhs) do |_k, old, new|
120
+ ValueMerger.new(self, op_class, old, new).call
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Dry
4
4
  module Schema
5
- VERSION = "1.9.1"
5
+ VERSION = "1.10.1"
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.1
4
+ version: 1.10.1
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-02-17 00:00:00.000000000 Z
11
+ date: 2022-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -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
@@ -237,7 +238,7 @@ licenses:
237
238
  - MIT
238
239
  metadata:
239
240
  allowed_push_host: https://rubygems.org
240
- changelog_uri: https://github.com/dry-rb/dry-schema/blob/master/CHANGELOG.md
241
+ changelog_uri: https://github.com/dry-rb/dry-schema/blob/main/CHANGELOG.md
241
242
  source_code_uri: https://github.com/dry-rb/dry-schema
242
243
  bug_tracker_uri: https://github.com/dry-rb/dry-schema/issues
243
244
  post_install_message: