Is there any way to do dependency injection in crystal, I only found it with some frameworks(like athena and shivneri) but not by itself
Dependency injection is a generic technique and it is supported in Crystal, for instance, via constructor injection. The following example could have been written similar in almost any object oriented languages. It defines an interface (an abstract class), and passes it to the constructor. Later, you can choose what implementation you want to provide:
record Email, subject : String, to : String
abstract class EmailSender
abstract def send(email)
end
class RealEmailSender < EmailSender
def send(email)
# some code to send an email
# ...
end
end
class StubEmailSender < EmailSender
def send(email)
# some test code to log the email without sending
puts "STUB: sending email #{email}"
end
end
class CheckoutService
def initialize(@email_sender : EmailSender)
end
def process_order
email = Email.new(subject: "Received order", to: "john.doe@abc.test")
@email_sender.send(email)
end
end
# inject the stub to skip sending a real email
email_service = StubEmailSender.new
checkout_service = CheckoutService.new(email_service)
checkout_service.process_order
Constructor injection demonstrates that dependency injection is possible. Another option would be to use generics. But perhaps you were not asking about manually arranging the services, but on how to use a dependency injection framework for the wiring?
To the best of my knowledge, no popular dependency injection framework exists for Crystal. It should be possible to write one, but it is not clear to me whether it is needed. Note that dependency frameworks see broad usage in some languages (like Java) but not in all. Ruby is one example where dependency frameworks exist but remain controversial.