2
require File.join(File.dirname(__FILE__), "time_extensions")
3
require File.join(File.dirname(__FILE__), "time_stack_item")
6
# * Wrapper class for manipulating the extensions to the Time, Date, and DateTime objects
7
# * Allows us to "freeze" time in our Ruby applications.
8
# * Optionally allows time travel to simulate a running clock, such time is not technically frozen.
10
# This is very useful when your app's functionality is dependent on time (e.g.
11
# anything that might expire). This will allow us to alter the return value of
12
# Date.today, Time.now, and DateTime.now, such that our application code _never_ has to change.
17
attr_accessor :active_support
19
# Allows you to run a block of code and "fake" a time throughout the execution of that block.
20
# This is particularly useful for writing test methods where the passage of time is critical to the business
21
# logic being tested. For example:
25
# assert !joe.mortgage_due?
26
# Timecop.freeze(2008, 10, 5) do
27
# assert joe.mortgage_due?
30
# freeze and travel will respond to several different arguments:
31
# 1. Timecop.freeze(time_inst)
32
# 2. Timecop.freeze(datetime_inst)
33
# 3. Timecop.freeze(date_inst)
34
# 4. Timecop.freeze(offset_in_seconds)
35
# 5. Timecop.freeze(year, month, day, hour=0, minute=0, second=0)
37
# When a block is also passed, Time.now, DateTime.now and Date.today are all reset to their
38
# previous values after the block has finished executing. This allows us to nest multiple
39
# calls to Timecop.travel and have each block maintain it's concept of "now."
41
# * Note: Timecop.freeze will actually freeze time. This can cause unanticipated problems if
42
# benchmark or other timing calls are executed, which implicitly expect Time to actually move
45
# * Rails Users: Be especially careful when setting this in your development environment in a
46
# rails project. Generators will load your environment, including the migration generator,
47
# which will lead to files being generated with the timestamp set by the Timecop.freeze call
48
# in your dev environment
50
# Returns the value of the block if one is given, or the mocked time.
51
def freeze(*args, &block)
52
send_travel(:freeze, *args, &block)
55
# Allows you to run a block of code and "fake" a time throughout the execution of that block.
56
# See Timecop#freeze for a sample of how to use (same exact usage syntax)
58
# * Note: Timecop.travel will not freeze time (as opposed to Timecop.freeze). This is a particularly
59
# good candidate for use in environment files in rails projects.
61
# Returns the value of the block if one is given, or the mocked time.
62
def travel(*args, &block)
63
send_travel(:travel, *args, &block)
66
# Allows you to run a block of code and "scale" a time throughout the execution of that block.
67
# The first argument is a scaling factor, for example:
69
# ... time will 'go' twice as fast here
71
# See Timecop#freeze for exact usage of the other arguments
73
# Returns the value of the block if one is given, or the mocked time.
74
def scale(*args, &block)
75
send_travel(:scale, *args, &block)
79
instance.send(:baseline)
82
def baseline=(baseline)
83
instance.send(:baseline=, baseline)
86
# Reverts back to system's Time.now, Date.today and DateTime.now (if it exists) permamently when
87
# no block argument is given, or temporarily reverts back to the system's time temporarily for
91
instance.send(:return, &block)
93
instance.send(:unmock!)
98
def return_to_baseline
99
instance.send(:return_to_baseline)
103
def top_stack_item #:nodoc:
104
instance.instance_variable_get(:@_stack).last
108
def send_travel(mock_type, *args, &block)
109
val = instance.send(:travel, mock_type, *args, &block)
110
block_given? ? val : Time.now
116
def baseline=(baseline)
118
@_stack << TimeStackItem.new(:travel, baseline)
121
def initialize #:nodoc:
125
def travel(mock_type, *args, &block) #:nodoc:
126
stack_item = TimeStackItem.new(mock_type, *args)
128
@_stack << stack_item
132
yield stack_item.time
140
current_stack = @_stack
141
current_baseline = @baseline
144
@_stack = current_stack
145
@baseline = current_baseline
153
def return_to_baseline
155
@_stack = [@_stack.shift]