Skip to content

Instantly share code, notes, and snippets.

@d11wtq
Created June 19, 2011 07:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d11wtq/1033857 to your computer and use it in GitHub Desktop.
Save d11wtq/1033857 to your computer and use it in GitHub Desktop.
class Time
class << self
attr_accessor :mock_time
def now_with_mock_time
@mock_time || now_without_mock_time
end
alias_method_chain :now, :mock_time
# Freeze Time.now, DateTime.now and Date.today to the given Time
# This method operates only in the context of a provided block.
#
# Example Usage:
#
# Time.be(:utc, 2007, 5, 2) do
# puts Time.now
# end
# # => 2007-05-02 00:00:00 UTC
#
# Time.be(:local, 2007, 5, 2, 17, 31, 2) do
# puts Time.now
# end
# # => 2007-05-02 17:31:02 +1000
#
# It works with DateTime.now too:
#
# Time.be(Time.utc(2012, 1, 1)) do
# puts DateTime.now
# end
# # => 2012-01-01T00:00:00+00:00
#
# And also with Date.today:
#
# Time.be(:utc, 2000, 2, 14) do
# puts Date.today
# end
# # => 2000-02-14
#
# Blocks can be nested together:
#
# Time.be(:utc, 2007, 5, 2) do
# Time.be(:local, 2007, 5, 2, 17, 31, 2) do
# puts Time.now
# end
# puts Time.now
# end
# # => 2007-05-02 17:31:02 +1000
# # => 2007-05-02 00:00:00 UTC
#
# And lastly, you can take advantage of ActiveSupport's Numeric helpers:
#
# Time.be(:utc, 2000, 1, 1) do
# Time.be(4.days.from_now.utc) do
# puts Time.now
# Time.be(3.minutes.ago.utc) do
# puts Time.now
# end
# end
# end
# # => 2000-01-05 00:00:00 UTC
# # => 2000-01-04 23:57:00 UTC
#
def be(a_time_or_type, *args)
raise ArgumentError, "Time.be requires a block, but none was given" unless block_given?
a_time = if a_time_or_type.kind_of?(Time)
a_time_or_type
else
unless [:utc, :local].include?(a_time_or_type)
raise ArgumentError, "First argument must either by a Time, :utc or :local"
end
Time.send(a_time_or_type, *args)
end
original_mock_time = @mock_time
@mock_time = a_time
yield
ensure
@mock_time = original_mock_time
end
end
end
require 'spec_helper'
describe "Time.be" do
it "sets the current time for the scope of a block" do
Time.be(Time.utc(2009, 3, 9)) { Time.now.should == Time.utc(2009, 3, 9) }
end
it "supports nesting blocks" do
Time.be(Time.utc(2009, 3, 9)) do
Time.be(Time.utc(2007, 1, 1)) { Time.now.should == Time.utc(2007, 1, 1) }
end
end
it "restores the time after the block has executed" do
Time.be(Time.utc(2009, 3, 9)) do
Time.be(Time.utc(2007, 1, 1)) { }
Time.now.should == Time.utc(2009, 3, 9)
end
end
it "supports passing time values as arguments" do
Time.be(:local, 2009, 3, 9, 17, 37, 59) do
Time.now.should == Time.local(2009, 3, 9, 17, 37, 59)
end
end
it "allows travelling through relative time" do
Time.be(:utc, 2009, 3, 9) do
Time.be(2.hours.from_now) do
Time.now.should == Time.utc(2009, 3, 9, 2, 0, 0)
Time.be(4.days.ago) do
Time.now.should == Time.utc(2009, 3, 5, 2, 0, 0)
end
end
end
end
it "affects DateTime" do
Time.be(:utc, 2009, 3, 9) do
date_time = DateTime.now
date_time.year.should == 2009
date_time.month.should == 3
date_time.day.should == 9
date_time.hour.should == 0
date_time.minute.should == 0
end
end
it "affects Date" do
Time.be(:utc, 2009, 3, 9) do
date = Date.today
date.year.should == 2009
date.month.should == 3
date.day.should == 9
end
end
end
@d11wtq
Copy link
Author

d11wtq commented Jun 19, 2011

Comment no longer makes sense. Should have really used a new gist. Meh.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment