I would like to figure how to inject a dependency into a Dry::Struct descendant class.
Here’s the code:
require 'dry-struct'
module Types
include Dry::Types.module
end
class User < Dry::Struct
attribute :name, Types::Strict::String
attribute :age, Types::Strict::Int.constrained(gteq: 18)
end
Now I want to inject a logger in the simplest way possible. I would not like to use dry-container partly because I didn’t grasp it yet, and partly because I still adhere to ‘you don’t need a dependency injection framework for dependency injection’ opinion. I’d like to keep it simple.
So, without dry-struct, I’d go with:
class User
def initialize logger
@logger = logger
end
end
User.new(Logger.new(STDOUT))
But sure enough, this approach doesn’t work for Dry::Struct successors.
require 'dry-struct'
module Types
include Dry::Types.module
end
class User < Dry::Struct
attribute :name, Types::Strict::String
attribute :age, Types::Strict::Int.constrained(gteq: 18)
attribute :logger, Types::Any
def log_info(message)
logger.info message
end
end
My struct got a bit beefy, because I added a whole bunch of methods to it. So, I took the wrong way? In the case above, where do I put user's methods, the things user can do?
@solnic As far as I understand, I shouldn’t name the dry-struct class a User, but rather UserData. And I should have have a separate User class with all the methods.
And then… do I inject UserData instance into User constructor? If so, what’s the benefit of separation of the two classes?
If you call it UserData then what User is supposed to do? Usually, operations that should be logged are located in places of a different kind, e.g. service objects, functional objects and alike. You might want to rearrange your code according to these concepts.