What he's really arguing against here is more basic: Composition.
Pragmatically the examples makes some sense. Why not stub out any global like this though? Because it breaks encapsulation and makes the program harder to understand.
Instead of lifting dependencies up to the level of method parameters with good composition, now you have to truly grok the entire method before you can have any confidence you even know what to stub out, and wether that's actually going to produce the expected results.
So while I fully endorse this specific, localized, easy to understand example, the poor composition of many Ruby libraries is what tends to make working with Ruby code so damn hard (IMO, see: Bundler). It's not enough to read method signatures. There are no explicit interfaces. Only implicit ones you devine by understanding the full breadth and scope of how parameter A is used in method B, all the way down the stack trace.
Fundamentally here DHH isn't talking about "Dependency Injection". He's talking about Composition and a pragmatic example of breaking Encapsulation. While sure there are 101 ways in which breaking Encapsulation can be a useful, pragmatic technique to employ for the seasoned code-slinger in the small, in the large it makes for more difficult to understand, and therefore less maintainable code.
I find many of these recent posts by DHH a bit ironic considering the subtext of a guy who read the PoEAA, then went off and wrote an MVC web-framework, packed with a nice Table Data Gateway, then proceeded to confuse Unit for Integration tests, and soap-box on the evils of Design Patterns in general.
[EDIT]
PS: The obvious example for making it easy to test, without breaking encapsulation, would simply be to avoid globals and use a default parameter.
def publish!(current_time = Time::now)
self.update published_at: current_time
end
TA-DA. So trivial examples might show how a very shallow example of monkey-patching can be a nice convenience, you also have simple "fixes" that actually take _less_ code to implement.You could easily come up with deeper stacks, presenting more difficult problems, but then you're not really making a great case for the beauty and simplicity of monkey patching if I have to have such a deep understanding of the side-effects in your code before I can even start making sense of your tests.