Open danillos opened 1 year ago
In this case, the docs should be updated. Thanks for filing the issue
Can you point out where you found this class definition?
class User
def initialize(name:)
@name = name
end
end
Can you point out where you found this class definition?
class User def initialize(name:) @name = name end end
The docs don't have it there but based on the example here, I think it is the User definition.
I did it as a temporary fix:
module Types
include Dry::Types(default: :strict)
def self.Constructor(klass)
# DryTypes Constructor doesn't support Ruby 3.1 initialization
# this is temporary code to make it work.
#
# See more details at: https://github.com/dry-rb/dry-types/issues/459
super { |item| klass.new(**item) }
end
end
The docs don't have it there but based on the example here, I think it is the User definition.
This assumption is wrong, Types.Constructor
expects sequential arguments. The correct definition is
class User
def initialize(attributes)
@attributes = attributes
end
def name = @attributes.fetch(:name)
end
We should update the docs with a sample User
definition.
I did it as a temporary fix:
I would suggest using a different name
module Types
include Dry::Types(default: :strict)
def self.KwConstructor(klass)
# DryTypes Constructor doesn't support Ruby 3.1 initialization
# this is temporary code to make it work.
#
# See more details at: https://github.com/dry-rb/dry-types/issues/459
super { |item| klass.new(**item) }
end
end
but it's up to you.
The docs don't have it there but based on the example here, I think it is the User definition.
This assumption is wrong,
Types.Constructor
expects sequential arguments. The correct definition isclass User def initialize(attributes) @attributes = attributes end def name = @attributes.fetch(:name) end
We should update the docs with a sample
User
definition.
Hi @flash-gordon,
Thank you for your attention,
My case wasn't related to this User example, this example I copied from the original reported issue here
My case was using Dry Initializer like:
class User
extend Dry::Initializer[undefined: false]
option :id, type: Types::Integer
end
class Delete
extend Dry::Initializer[undefined: false]
option :user, type: Types.Constructor(::User)
end
# and using it like:
Delete.new(user: { id: 1 })
# `block in __dry_initializer_initialize__': User: option 'id' is required (KeyError)
So using only Dry Gems and only in Ruby 3.1+, I'm having this issue, what is weird. It seems like a bug. Since everyone using Ruby before 3.1 on this way, will have this issue when upgrading to Ruby 3.1
It's because dry-initializer uses keywords. Before 3.0 ruby was more permissive regarding passing hashes where keywords are expected. Once a clear separation was made in 3.0 it doesn't work magically anymore. I cannot see what dry-types or dry-initializer can/should do about that. Defining a custom constructor is a consistent and non-breaking solution.
To be honest, I'm trying to stay out of the subject, it is very-very-very likely if we dig deeper by trying to fix anything here we'll come up with more bugs. Also, performance may suffer.
Describe the bug
Make a way to
Types.Constructor
works without a Hack.This issue was copied from https://discourse.dry-rb.org/t/types-constructor-failing-on-ruby-3-1/1566 and originally created by eaylward8
To Reproduce
Given this class:
…the docs say I should be able to do this:
On Ruby 2.7.7, this works as expected and I get an instance of User with the given name.
On Ruby 3.1.2, I get:
Expected behavior
Doesn't raises an error like the Doc says.
My environment