-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Dependency Injection Fails with mixed classes and structs when depending on an interface #512
Comments
@syeopite What version are you on to produce this? I just tried to reproduce and got |
Oops I messed up in my report. Looks like the bug only applies when Dependency is a |
Okay, yea I think this is a bug in that the last usage should always "win" being the default implementation. But is there a specific use case you're wanting to solve? I'd say it's somewhat unexpected to have Dev Note This seems to be a result of |
Am I not supposed to use Anyways, my use case is for mocking a struct service and needing to pass a @[ADI::Register(public: true)]
@[ADI::AsAlias(ServiceInterface)]
class Mock
include ServiceInterface
property retrieve_mock_data_from : String = ""
def get(uri)
return JSON.parse(File.read(@retrieve_mock_data_from))["uri"]
end
end
it "Test" do
ADI.container.mock.retrieve_mock_data_from = "spec/mocks/response.json"
response = ADI.container.fetch_data.fetch()
response.should eq "data"
end Real world example here https://github.com/syeopite/instances-api/blob/6301642b7e7353214d77e791d8016616bcb04386/spec/populate-spec/populate_spec_helper.cr#L74 |
No, the purpose of module Interface; end
@[ADI::Register]
class One
include Interface
end
@[ADI::Register]
class Two
include Interface
end
@[ADI::Register(public: true)]
class Service
getter service : Interface
def initialize(@service : Interface); end
end
puts ADI.container.service.service.class # => "???" There is no real way to know what service should be used for the If there is a case where you may want an implementation that isn't the default, you can still do something like this: # Assume `One` is the configured alias of `Interface`.
# Having the constructor parameter name match the service ID of `two` makes it provide that one instead.
# Using a local var such that the name of ivar in the type
# can be kept separate if we want to change it to `Three` for example.
def initialize(two : Interface)
@service = two
end
Hmm okay, I'll have to read thru this code more closely. I think there are some changes you'll want to make to take the most advantage of this design pattern compared to your current approach. EDIT: @syeopite I DM'd you on gitter. |
The original `FetchInstancesFromDocs` service was a struct preventing the mock service, `MockFetchInstances` which is a class from being used due to athena-framework/athena#512
A service that depends on an interface cannot receive additional injected implementations of the interface when the first implementation is a
Struct
and the additional implementation is aClass
The text was updated successfully, but these errors were encountered: