From 420f372e16191ab6c50470e775a12f68ea334b77 Mon Sep 17 00:00:00 2001 From: Nikita Shilnikov Date: Mon, 6 Jan 2025 11:46:02 +0100 Subject: [PATCH 1/2] Fix bugs with coercing input to arrays of struct types (fix #192) This changes the base class for Dry::Struct::Error to Dry::Types::CoercionError. It solves one of the bugs but it also makes sense in general. --- Gemfile.devtools | 4 ++++ lib/dry/struct/errors.rb | 2 +- lib/dry/struct/sum.rb | 2 +- spec/integration/array_spec.rb | 44 ++++++++++++++++++++++++++++++++++ spec/spec_helper.rb | 8 ++++--- 5 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 spec/integration/array_spec.rb diff --git a/Gemfile.devtools b/Gemfile.devtools index fc54fc3..d3fe57b 100644 --- a/Gemfile.devtools +++ b/Gemfile.devtools @@ -17,4 +17,8 @@ group :tools do gem "rubocop", "~> 1.69.2" gem "byebug" gem "yard" + + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.4.0") + gem "debug" + end end diff --git a/lib/dry/struct/errors.rb b/lib/dry/struct/errors.rb index 02edbc2..738ebd2 100644 --- a/lib/dry/struct/errors.rb +++ b/lib/dry/struct/errors.rb @@ -3,7 +3,7 @@ module Dry class Struct # Raised when given input doesn't conform schema and constructor type - Error = Class.new(TypeError) + Error = Class.new(::Dry::Types::CoercionError) # Raised when defining duplicate attributes class RepeatedAttributeError < ::ArgumentError diff --git a/lib/dry/struct/sum.rb b/lib/dry/struct/sum.rb index 09f4d54..8af8d70 100644 --- a/lib/dry/struct/sum.rb +++ b/lib/dry/struct/sum.rb @@ -18,7 +18,7 @@ def call(input) # @return [Dry::Types::Result] def try(input) if input.is_a?(Struct) - try_struct(input) { super } + ::Dry::Types::Result::Success.new(try_struct(input) { return super }) else super end diff --git a/spec/integration/array_spec.rb b/spec/integration/array_spec.rb new file mode 100644 index 0000000..ddab8fd --- /dev/null +++ b/spec/integration/array_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +RSpec.describe Dry::Types::Array do + before do + module Test + class Street < Dry::Struct + attribute :street_name, "string" + end + + class City < Dry::Struct + attribute :city_name, "string" + end + + CityOrStreet = City | Street + end + end + + describe "#try" do + context "simple struct" do + subject(:array) { Dry::Types["array"].of(Test::Street) } + it "returns success for valid array" do + expect(array.try([{street_name: "Oxford"}, {street_name: "London"}])).to be_success + end + + it "returns failure for invalid array" do + expect(array.try([{name: "Oxford"}, {name: 123}])).to be_failure + expect(array.try([{}])).to be_failure + end + end + + context "sum struct" do + subject(:array) { Dry::Types["array"].of(Test::CityOrStreet) } + + it "returns success for valid array" do + expect(array.try([{city_name: "London"}, {street_name: "Oxford"}])).to be_success + expect(array.try([Test::Street.new(street_name: "Oxford")])).to be_success + end + + it "returns failure for invalid array" do + expect(array.try([{city_name: "London"}, {street_name: 123}])).to be_failure + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 091769b..0cede48 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -18,10 +18,12 @@ module DryStructSpec require "dry-struct" -begin - require "pry" - require "pry-byebug" +%w[debug pry-byebug pry byebug].each do |gem| + require gem rescue LoadError + nil +else + break end Dir[Pathname(__dir__).join("shared/*.rb")].each(&method(:require)) From a02cb0ee973a9ee5383eef3a8a50e0626752b4e0 Mon Sep 17 00:00:00 2001 From: Nikita Shilnikov Date: Mon, 6 Jan 2025 11:48:11 +0100 Subject: [PATCH 2/2] Update changelog --- changelog.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/changelog.yml b/changelog.yml index 937326e..1540bdb 100644 --- a/changelog.yml +++ b/changelog.yml @@ -2,10 +2,15 @@ - version: 1.7.0 summary: date: 2025-01-04 + fixed: + - 'Fixed coercion errors for structs (issue #192 via #193) + (@flash-gordon)' changed: - 'Missing attribute error now includes the name of the class (issue #170 via #191) (@phillipoertel + @cllns)' - '3.1 is now the minimum Ruby version (@flash-gordon)' + - '`Dry::Struct::Error` is now a subclass of `Dry::Types::CoercionError` (in #193) + (@flash-gordon)' - version: 1.6.0 date: 2022-11-04 changed: