I'm less certain that DI is "wrong" in Ruby, although it's definitely unidiomatic.
I'm less certain that DI is "wrong" in Ruby, although it's definitely unidiomatic.
For example, I use factories to create test objects that are complicated to set up (using a gem named factory_girl, actually).
Also, in Ruby, every class is a factory for its own instances. If I define a class called User, I can assign the class object User to a variable:
factory = User
Then I can call
factory.new
and receive a new User instance.
As for DI, it's not wrong, nor is it unidiomatic. Plenty of folks in the community use it, and often.
A commenter elsewhere in this thread says that DI is unnecessary in Ruby because you can just reopen or redefine a class whenever you want. That's technically true, but isn't a good practice, as it can lead to some rather rapid foot shootery.
If you want to swap in different-behaving dependencies, DI is a straightforward choice. Reopening an existing class and mangling it can cause very confusing behavior, and is generally avoided by experienced Rubyists.
Regarding DI: Jamis Buck infamously used DI for net/ssh and posted that he regretted doing so, because DI felt out of place in Ruby. I'm not spoiling for an argument about its virtues.
Regarding "experienced Rubyists" and reopening classes, I think you should have a look at activesupport/core_ext.
It's been said that every programming pattern is a programming language design flaw. This is evidence in favor of that.
Have't tested it yet but it makes a lot of sense.
Redefining a class isn't dependency injection it's a hack to get the compiler to stop complaining. It works but it's very unclear to the person reading the program that a class your code depends on was actually redefined somewhere else.
For testing purposes placing this mock class somewhere at the start of your code is clear but only ever practical in that scenario.
I can also imagine that some programmers might not even think of the possibility that some code they depend on was overridden somewhere else.
In real maintainable code where you want to swap out behaviours it's nice if there was a special way of defining your dependencies. This is the same for all languages.
Deject offers a way so you don't have to fiddle with constructors but instead you have handles in your classes that you can override with different behavior if needed.
TL;DR: Yes, Ruby is powerful and you technically don't need IoC containers. But to make it maintainable for everyone it's a good idea to do so anyway.
I must have blinked and missed whatever happened that made everyone think global variables are now all the rage.
Most Ruby books I've read that have been published in the past couple of years seem to disagree.