time_travel 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +44 -0
- data/Rakefile +28 -0
- data/VERSION +1 -0
- data/init.rb +1 -0
- data/lib/time_travel.rb +16 -0
- data/lib/time_travel/date_extensions.rb +9 -0
- data/lib/time_travel/string_extensions.rb +13 -0
- data/lib/time_travel/time_extensions.rb +36 -0
- data/spec/time_travel_spec.rb +131 -0
- metadata +65 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
coverage
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Peter Yandell
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
= TimeTravel
|
2
|
+
|
3
|
+
Time Travel is a Rails plugin that makes it easy to write tests or specs for time-dependent code. It provides the at_time function:
|
4
|
+
|
5
|
+
at_time("9 March 2018 2:32") do
|
6
|
+
...
|
7
|
+
end
|
8
|
+
|
9
|
+
Inside the block, Time.now will return the given time. The time will
|
10
|
+
be restored to normal system time when the block exits.
|
11
|
+
|
12
|
+
The at_time function can take a Time object, a Date, or a String to parse them into a time.
|
13
|
+
|
14
|
+
If the time is given as a String, it is parsed using Time.zone.parse (in Rails 2.1)
|
15
|
+
or Time.parse (in Rails 2.0 and earlier). That means it will be interpreted as being
|
16
|
+
in the current timezone, unless you provide an explicit timezone in the string.
|
17
|
+
|
18
|
+
If the time is given as a Date, it is converted to a String and then parsed in the described way.
|
19
|
+
|
20
|
+
You can also access the current time inside of the block via a block parameter, eg:
|
21
|
+
|
22
|
+
at_time Time.now do |time|
|
23
|
+
...
|
24
|
+
end
|
25
|
+
|
26
|
+
== closest_second
|
27
|
+
|
28
|
+
The +closest_second+ method is useful when you need to compare an ActiveRecord datetime value with a Ruby Time.
|
29
|
+
|
30
|
+
Times are normally stored in your database with 1 second resolution, but Ruby's Time class has microsecond resolution. That means that this will usually fail:
|
31
|
+
|
32
|
+
at_time(Time.now) do # Freeze the time to a single value for the block.
|
33
|
+
@post = Post.create(:title => 'Example')
|
34
|
+
@post.reload
|
35
|
+
@post.created_at.should == Time.now # Time.now has some number of microseconds, but @post.created_at doesn't.
|
36
|
+
end
|
37
|
+
|
38
|
+
The +closest_second+ method returns the time without the microseconds, so the following will succeed:
|
39
|
+
|
40
|
+
@post.created_at.should == Time.now.closest_second
|
41
|
+
|
42
|
+
== Installation
|
43
|
+
|
44
|
+
ruby script/plugin install git://github.com/notahat/time_travel.git
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'spec/rake/spectask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc "Default: run specs"
|
6
|
+
task :default => :spec
|
7
|
+
|
8
|
+
desc "Run all the specs for the time_travel plugin."
|
9
|
+
Spec::Rake::SpecTask.new do |t|
|
10
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
11
|
+
t.spec_opts = ['--colour']
|
12
|
+
t.rcov = true
|
13
|
+
t.rcov_opts = ["--exclude \"spec/*,gems/*\""]
|
14
|
+
end
|
15
|
+
|
16
|
+
begin
|
17
|
+
require 'jeweler'
|
18
|
+
Jeweler::Tasks.new do |gemspec|
|
19
|
+
gemspec.name = "time_travel"
|
20
|
+
gemspec.summary = "A Rails plugin that makes it easy to write tests or specs for time-dependent code"
|
21
|
+
gemspec.email = "pete@notahat.com"
|
22
|
+
gemspec.homepage = "http://github.com/notahat/time_travel"
|
23
|
+
gemspec.authors = ["Pete Yandell"]
|
24
|
+
end
|
25
|
+
Jeweler::GemcutterTasks.new
|
26
|
+
rescue LoadError
|
27
|
+
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
28
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/init.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'time_travel' if ENV["RAILS_ENV"] == "test"
|
data/lib/time_travel.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'time_travel/time_extensions'
|
2
|
+
require 'time_travel/string_extensions'
|
3
|
+
require 'time_travel/date_extensions'
|
4
|
+
|
5
|
+
Time.send(:include, TimeTravel::TimeExtensions)
|
6
|
+
String.send(:include, TimeTravel::StringExtensions)
|
7
|
+
Date.send(:include, TimeTravel::DateExtensions)
|
8
|
+
|
9
|
+
def at_time(time)
|
10
|
+
Time.now = time
|
11
|
+
begin
|
12
|
+
yield Time.now
|
13
|
+
ensure
|
14
|
+
Time.now = nil
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module TimeTravel
|
4
|
+
module TimeExtensions
|
5
|
+
|
6
|
+
def self.included(base)
|
7
|
+
base.extend(ClassMethods)
|
8
|
+
base.class_eval do
|
9
|
+
class << self
|
10
|
+
alias_method :immutable_now, :now
|
11
|
+
alias_method :now, :mutable_now
|
12
|
+
end
|
13
|
+
end
|
14
|
+
base.now = nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def closest_second
|
18
|
+
Time.gm(year, month, day, hour, min, sec)
|
19
|
+
end
|
20
|
+
|
21
|
+
module ClassMethods
|
22
|
+
|
23
|
+
@@now = nil
|
24
|
+
|
25
|
+
def now=(value)
|
26
|
+
@@now = value.respond_to?(:parse_to_time) ? value.parse_to_time : value
|
27
|
+
end
|
28
|
+
|
29
|
+
def mutable_now #:nodoc:
|
30
|
+
@@now || immutable_now
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
require 'time_travel'
|
3
|
+
require 'time'
|
4
|
+
require 'active_support'
|
5
|
+
|
6
|
+
describe TimeTravel, "assigning to Time.now" do
|
7
|
+
|
8
|
+
before do
|
9
|
+
@future = Time.parse("1 April 2020")
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should set the time" do
|
13
|
+
Time.now = @future
|
14
|
+
Time.now.should == @future
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should return time to system time assigning nil" do
|
18
|
+
Time.now = @future
|
19
|
+
Time.now = nil
|
20
|
+
Time.now.should_not be_nil
|
21
|
+
Time.now.should_not == @future
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should accept a string" do
|
25
|
+
Time.now = "1 April 2020"
|
26
|
+
Time.now.should == Time.parse("1 April 2020")
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should accept a date" do
|
30
|
+
Time.now = @future.to_date
|
31
|
+
Time.now.should == Time.parse("1 April 2020")
|
32
|
+
end
|
33
|
+
|
34
|
+
context "in the current timezone as set in ActiveSupport" do
|
35
|
+
|
36
|
+
before do
|
37
|
+
Time.zone = "Perth"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should accept a date" do
|
41
|
+
Time.now = Date.civil(2020, 7, 1)
|
42
|
+
Time.now.should == Time.parse("30 June 2020 4:00 PM UTC")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should accept a string" do
|
46
|
+
Time.now = "1 July 2020 11:00 AM"
|
47
|
+
Time.now.should == Time.parse("1 July 2020 3:00 AM UTC")
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
context "in the current timezone as set in the environment" do
|
53
|
+
|
54
|
+
before do
|
55
|
+
Time.zone = nil
|
56
|
+
ENV['TZ'] = "Australia/Perth"
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should accept a date" do
|
60
|
+
Time.now = Date.civil(2020, 7, 1)
|
61
|
+
Time.now.should == Time.parse("30 June 2020 4:00 PM UTC")
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should accept a string" do
|
65
|
+
Time.now = "1 July 2020 11:00 AM"
|
66
|
+
Time.now.should == Time.parse("1 July 2020 3:00 AM UTC")
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
after do
|
72
|
+
Time.now = nil
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
describe TimeTravel, "at_time method" do
|
78
|
+
|
79
|
+
before do
|
80
|
+
@future = Time.parse("1 April 2020")
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should change the time within the block" do
|
84
|
+
at_time(@future) do
|
85
|
+
Time.now.should == @future
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should change the date within the block" do
|
90
|
+
at_time(@future.to_date) do
|
91
|
+
Date.today.should == @future.to_date
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should pass the time into the block" do
|
96
|
+
at_time(@future) do |time|
|
97
|
+
time.should == @future
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should pass the time into the block being given a date" do
|
102
|
+
at_time(@future.to_date) do |time|
|
103
|
+
time.should == @future
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should restore the system time after the block" do
|
108
|
+
at_time(@future) do
|
109
|
+
end
|
110
|
+
Time.now.should_not == @future
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should restore the system time after an exception" do
|
114
|
+
begin
|
115
|
+
at_time(@future) do
|
116
|
+
raise "Uh oh"
|
117
|
+
end
|
118
|
+
rescue
|
119
|
+
end
|
120
|
+
Time.now.should_not == @future
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
describe TimeTravel, "closest_second method" do
|
126
|
+
|
127
|
+
it "should return the time with no microseconds" do
|
128
|
+
Time.utc(2020, 4, 1, 9, 0, 0, 500).closest_second.should == Time.utc(2020, 4, 1, 9, 0, 0)
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: time_travel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Pete Yandell
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-08 00:00:00 +11:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: pete@notahat.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- VERSION
|
30
|
+
- init.rb
|
31
|
+
- lib/time_travel.rb
|
32
|
+
- lib/time_travel/date_extensions.rb
|
33
|
+
- lib/time_travel/string_extensions.rb
|
34
|
+
- lib/time_travel/time_extensions.rb
|
35
|
+
- spec/time_travel_spec.rb
|
36
|
+
has_rdoc: true
|
37
|
+
homepage: http://github.com/notahat/time_travel
|
38
|
+
licenses: []
|
39
|
+
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options:
|
42
|
+
- --charset=UTF-8
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.3.5
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: A Rails plugin that makes it easy to write tests or specs for time-dependent code
|
64
|
+
test_files:
|
65
|
+
- spec/time_travel_spec.rb
|