From: "Molitor, Stephen L" Date: 2006-05-25T07:10:07+09:00 Subject: Re: Overriding Time.now Correction, I should probably wrap the user code in an ensure block to ensure that the constant gets reset: class Module def inject_constant(constant, value) old_value = const_get(constant) const_set(constant, value) if block_given? begin yield ensure const_set(constant, old_value) end end end end Steve -----Original Message----- From: Molitor, Stephen L Sent: Wednesday, May 24, 2006 4:21 PM To: ruby-talk ML Subject: Re: Overriding Time.now Very nice! If I understand correctly, I could do something like this: class Module def inject_constant(constant, value) old_value = const_get(constant) const_set(constant, value) if block_given? yield const_set(constant, old_value) end end end Then in a test, I could do this: def test_my_app MyApp::inject_constant(:Time, MockTime) end If all of my code is in the module MyApp, then all of my code uses MockTime whenever it refers to Time. Forever in this case, which might be fine in a test. Or I could pass a block to limit the duration. Or use setup / teardown. If I want to be more fine grained I can just inject into one class. In any case, I can mock out the current time without messing up external code, and without changing my original code. All without a fancy DI or AOP framework. Wow! Is this the cleanest implementation of this technique? I went through all your DI presentation slides. Looks like it was a fantastic presentation. Steve -----Original Message----- From: list-bounce@example.com [mailto:list-bounce@example.com] On Behalf Of Jim Weirich Sent: Wednesday, May 24, 2006 12:01 PM To: ruby-talk ML Subject: Re: Overriding Time.now Molitor, Stephen L wrote: >> I believe that you can redefine Time.now in the scope where you need >> it without interfering with Test::Unit > > There's only one instance of the Time class object, and any changes > you make to it are in effect 'global'. You can use a technique called "Constant Injection" where you temporarily change the definition of a constant within the scope of a single class. See http://onestepback.org/articles/depinj/classesarejustobjects.html for an example. This allows you to say something like: def test_my_class MyClass.use_class(:Time, MockTime) do mc = MyClass.new # Any calls to Time.now within MyClass will be routed to MockTime.now end # Calls to Time.now are now back to normal. end -- Jim Weirich -- Posted via http://www.ruby-forum.com/.