diff --git a/lib/dry/schema/key_validator.rb b/lib/dry/schema/key_validator.rb index c2d60cd8..e89da605 100644 --- a/lib/dry/schema/key_validator.rb +++ b/lib/dry/schema/key_validator.rb @@ -9,8 +9,8 @@ module Schema class KeyValidator extend Dry::Initializer - INDEX_REGEX = /\[\d+\]/.freeze - DIGIT_REGEX = /\A\d+\z/.freeze + INDEX_REGEX = /\[\d+\]/ + DIGIT_REGEX = /\A\d+\z/ BRACKETS = "[]" # @api private diff --git a/lib/dry/schema/macros/core.rb b/lib/dry/schema/macros/core.rb index eeb62dcf..8b8cdade 100644 --- a/lib/dry/schema/macros/core.rb +++ b/lib/dry/schema/macros/core.rb @@ -25,8 +25,8 @@ class Core option :schema_dsl, optional: true # @api private - def new(**options) - self.class.new(name: name, compiler: compiler, schema_dsl: schema_dsl, **options) + def new(klass: self.class, **options) + klass.new(name: name, compiler: compiler, schema_dsl: schema_dsl, **options) end # @api private diff --git a/lib/dry/schema/macros/dsl.rb b/lib/dry/schema/macros/dsl.rb index 525feba1..96182d2e 100644 --- a/lib/dry/schema/macros/dsl.rb +++ b/lib/dry/schema/macros/dsl.rb @@ -217,7 +217,6 @@ def append_macro(macro_type) # @api private # rubocop: disable Metrics/AbcSize - # rubocop: disable Metrics/CyclomaticComplexity # rubocop: disable Metrics/PerceivedComplexity def extract_type_spec(args, nullable: false, set_type: true) type_spec = args[0] unless schema_or_predicate?(args[0]) @@ -230,9 +229,9 @@ def extract_type_spec(args, nullable: false, set_type: true) if type_spec.is_a?(::Array) type_rule = type_spec.map { |ts| new(chain: false).value(ts) }.reduce(:|) - elsif type_spec.is_a?(Dry::Types::Sum) && set_type + elsif type_spec.is_a?(Dry::Types::Sum) type_rule = [type_spec.left, type_spec.right].map { |ts| - new(klass: Core, chain: false).value(ts) + new(klass: DSL, chain: false).value(ts) }.reduce(:|) else type_predicates = predicate_inferrer[resolved_type] @@ -245,14 +244,9 @@ def extract_type_spec(args, nullable: false, set_type: true) type(resolved_type) if set_type && resolved_type - if type_rule - yield(*predicates, type_spec: nil, type_rule: type_rule) - else - yield(*predicates, type_spec: type_spec, type_rule: nil) - end + yield(*predicates, type_spec: type_spec, type_rule: type_rule) end # rubocop: enable Metrics/AbcSize - # rubocop: enable Metrics/CyclomaticComplexity # rubocop: enable Metrics/PerceivedComplexity # @api private diff --git a/lib/dry/schema/macros/filled.rb b/lib/dry/schema/macros/filled.rb index 98313006..53aa1736 100644 --- a/lib/dry/schema/macros/filled.rb +++ b/lib/dry/schema/macros/filled.rb @@ -12,11 +12,11 @@ def call(*predicates, **opts, &block) ensure_valid_predicates(predicates) append_macro(Macros::Value) do |macro| - if opts[:type_spec] && !filter_empty_string? + if opts[:type_rule] + macro.call(:filled?).value(*predicates, **opts, &block) + elsif opts[:type_spec] && !filter_empty_string? macro.call(predicates[0], :filled?, *predicates[1..predicates.size - 1], **opts, &block) - elsif opts[:type_rule] - macro.call(:filled?).value(*predicates, **opts, &block) else macro.call(:filled?, *predicates, **opts, &block) end diff --git a/spec/integration/params/macros/array_spec.rb b/spec/integration/params/macros/array_spec.rb index 9f98e4f7..cf3610d4 100644 --- a/spec/integration/params/macros/array_spec.rb +++ b/spec/integration/params/macros/array_spec.rb @@ -76,5 +76,27 @@ expect(result).to be_failure expect(result.errors.to_h).to eql(nums: {1 => ["must be an integer or cannot be defined"]}) end + + it "applies coercion and rules to hashes" do + schema = Dry::Schema.Params { + required(:hashes).array( + Types::Hash.schema(name: "string") | Types::Hash.schema(other_name: "string") + ) + } + + result = schema.(hashes: [{name: "string"}, {name: "string", other_name: "string"}, {other_name: "string"}]) + + expect(result).to be_success + expect(result.output).to eql(hashes: [ + {name: "string"}, + {name: "string"}, + {other_name: "string"} + ]) + + result = schema.(hashes: [{name: "string"}, {other_key: 1}, {name: 0}, {other_name: "string"}]) + + expect(result).to be_failure + expect(result.errors.to_h).to eq(hashes: {1 => {or: [{name: ["is missing"]}, {other_name: ["is missing"]}]}, 2 => {or: [{name: ["must be a string"]}, {other_name: ["is missing"]}]}}) + end end end