Is there any known reason for dry-struct not having the ability to define dependent attributes like FactoryBot dependent attributes?
class NewUser < Dry::Struct
attribute :email, Types::String
dependent_attribute :username, Types::String do
email.split('@').first
end
# or
attribute :username, Types::String, dependent: true do
email.split('@').first
end
# or
attribute! :username { Types::String.default(email.split('@').first) }
end
Wouldn’t it have the same reason as default values?
No, and there won’t be such a feature in dry-struct. Mostly because it’s not aligned with how the gem operates, there’s no simple way to implement it. This would also make the DSL more complex, both internally and externally for a small gain.
That said, in some cases, I override the constructor:
class NewUser < Dry::Struct
attribute :email, Types::String
attribute :username, Types::String
def self.new(values)
super(values.merge(username: values[:email].split('@', 2).first))
end
end
I don’t promise it’ll work in all cases but it does in simple ones.
If you do this, I would call it a code smell in dry-rb land. Structs are meant to be simple data capsules, they should not map data or construct values. Even coercion at a single value level is already a tiny, little code smell, but for now it’s fine since we’re not there yet with a full-stack, stand-alone data transformation solution.
In that case, defaults seem to be a similar code smell too🤔. What dry do you think is more appropiate to tackle this case? For now, I defined a method for that attribute and overrode #to_h to include it. I’m thinking also to a builder…