timecop 0.6.1 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c86a01ea95f5019cb15a6a66c5668e68e7f1e293ca14b910a10cbe1cdd70d668
4
+ data.tar.gz: e5c6987d3a452fa9ead841021f93bf4ea6bac713c1f6cea38cfc1c1d49baf6ee
5
+ SHA512:
6
+ metadata.gz: 4abbcd2d37b9fdf6dfb1ed1f63f945a882cd62a47ae2ae237da003ccac0bc660572be0800933ea484fb1632707bdc2de457b96f9aad8a62b1dfd96d766220692
7
+ data.tar.gz: a19cc9026478a29161a832454edebf76105d56d3841575af71e9dbaa305a40a68af285d17b7473369ae913e463cadd7b67ab2e099d13d3162b713d2c3cd87d05
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2012 — Travis Jeffery, John Trupiano
3
+ Copyright (c) 2019 — Travis Jeffery, John Trupiano
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.markdown CHANGED
@@ -1,9 +1,7 @@
1
1
  # timecop
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/travisjeffery/timecop.png)](http://travis-ci.org/travisjeffery/timecop)
4
-
5
- - Source[http://github.com/travisjeffery/timecop]
6
- - Documentation[http://johntrupiano.rubyforge.org/timecop]
3
+ [![Gem Version](https://badge.fury.io/rb/timecop.svg)](https://rubygems.org/gems/timecop)
4
+ [![Build Status](https://github.com/travisjeffery/timecop/workflows/CI/badge.svg)](https://github.com/travisjeffery/timecop/actions?query=workflow%3ACI)
7
5
 
8
6
  ## DESCRIPTION
9
7
 
@@ -11,7 +9,7 @@ A gem providing "time travel" and "time freezing" capabilities, making it dead s
11
9
 
12
10
  ## INSTALL
13
11
 
14
- gem install timecop
12
+ `bundle add timecop`
15
13
 
16
14
  ## FEATURES
17
15
 
@@ -49,12 +47,13 @@ describe "some set of tests to mock" do
49
47
  before do
50
48
  Timecop.freeze(Time.local(1990))
51
49
  end
52
-
50
+
53
51
  after do
54
52
  Timecop.return
55
53
  end
56
54
 
57
- it "should do blah blah blah" {}
55
+ it "should do blah blah blah" do
56
+ end
58
57
  end
59
58
  ```
60
59
 
@@ -62,7 +61,7 @@ Set the time for the test environment of a rails app -- this is particularly
62
61
  helpful if your whole application is time-sensitive. It allows you to build
63
62
  your test data at a single point in time, and to move in/out of that time as
64
63
  appropriate (within your tests)
65
-
64
+
66
65
  in config/environments/test.rb
67
66
 
68
67
  ```ruby
@@ -106,24 +105,40 @@ being able to simulate activity via subsequent calls to your application.
106
105
  Timecop.scale(3600)
107
106
  Time.now
108
107
  # => 2012-09-20 21:23:25 -0500
109
- # seconds later, hours have past it's gone from 9pm at night to 6am in the morning
108
+ # seconds later, hours have passed and it's gone from 9pm at night to 6am in the morning
110
109
  Time.now
111
110
  # => 2012-09-21 06:22:59 -0500
112
111
  ```
113
112
 
114
- See #42 for more information, thanks to Ken Mayer, David Holcomb, and Pivotal Labs.
113
+ See [#42](https://github.com/travisjeffery/timecop/pull/42) for more information, thanks to Ken Mayer, David Holcomb, and Pivotal Labs.
114
+
115
+ ### Timecop.safe_mode
116
+
117
+ Safe mode forces you to use Timecop with the block syntax since it always puts time back the way it was. If you are running in safe mode and use Timecop without the block syntax `Timecop::SafeModeException` will be raised to tell the user they are not being safe.
118
+
119
+ ``` ruby
120
+ # turn on safe mode
121
+ Timecop.safe_mode = true
122
+
123
+ # check if you are in safe mode
124
+ Timecop.safe_mode?
125
+ # => true
126
+
127
+ # using method without block
128
+ Timecop.freeze
129
+ # => Timecop::SafeModeException: Safe mode is enabled, only calls passing a block are allowed.
130
+ ```
131
+
132
+ ### Rails v Ruby Date/Time libraries
115
133
 
116
- ## REFERENCES
134
+ Sometimes [Rails Date/Time methods don't play nicely with Ruby Date/Time methods.](https://rails.lighthouseapp.com/projects/8994/tickets/6410-dateyesterday-datetoday)
117
135
 
118
- * {0.3.4 release}[http://blog.smartlogicsolutions.com/2009/12/07/timecop-0-3-4-released/]
119
- * {0.3.0 release}[http://blog.smartlogicsolutions.com/2009/09/20/timecop-0-3-0-released/]
120
- * {0.2.0 release}[http://blog.smartlogicsolutions.com/2008/12/24/timecop-2-released-freeze-and-rebase-time-ruby/]
121
- * {0.1.0 release}[http://blog.smartlogicsolutions.com/2008/11/19/timecop-freeze-time-in-ruby-for-better-testing/]
136
+ Be careful mixing Ruby `Date.today` with Rails `Date.tomorrow` / `Date.yesterday` as things might break.
122
137
 
123
138
  ## Contribute
124
139
 
125
140
  timecop is maintained by [travisjeffery](http://github.com/travisjeffery), and
126
- was created by [jtrupiano](https://github.com/jtrupiano).
141
+ was created by [jtrupiano](https://github.com/jtrupiano).
127
142
 
128
143
  Here's the most direct way to get your work merged into the project.
129
144
 
data/Rakefile CHANGED
@@ -3,8 +3,6 @@ require 'bundler/gem_tasks'
3
3
  require 'rake/testtask'
4
4
  require 'rdoc/task'
5
5
 
6
- $LOAD_PATH.unshift("lib")
7
-
8
6
  Rake::RDocTask.new do |rdoc|
9
7
  if File.exist?('VERSION')
10
8
  version = File.read('VERSION')
@@ -20,8 +18,16 @@ Rake::RDocTask.new do |rdoc|
20
18
  rdoc.rdoc_files.include('lib/**/*.rb')
21
19
  end
22
20
 
23
- task :test do
24
- system "cd test && ./run_tests.sh"
21
+ task :test do
22
+ failed = Dir["test/*_test.rb"].map do |test|
23
+ command = "ruby #{test}"
24
+ puts
25
+ puts command
26
+ command unless system(command)
27
+ end.compact
28
+ if failed.any?
29
+ abort "#{failed.count} Tests failed\n#{failed.join("\n")}"
30
+ end
25
31
  end
26
32
 
27
33
  desc 'Default: run tests'
@@ -1,3 +1,5 @@
1
+ require 'time'
2
+ require 'date'
1
3
 
2
4
  class Time #:nodoc:
3
5
  class << self
@@ -5,77 +7,148 @@ class Time #:nodoc:
5
7
  mocked_time_stack_item = Timecop.top_stack_item
6
8
  mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.time(self)
7
9
  end
8
-
10
+
9
11
  alias_method :now_without_mock_time, :now
10
12
 
11
13
  def now_with_mock_time
12
14
  mock_time || now_without_mock_time
13
15
  end
14
-
16
+
15
17
  alias_method :now, :now_with_mock_time
16
18
 
17
19
  alias_method :new_without_mock_time, :new
18
20
 
19
21
  def new_with_mock_time(*args)
20
- begin
21
- raise ArgumentError.new if args.size <= 0
22
- new_without_mock_time(*args)
23
- rescue ArgumentError
24
- now
25
- end
22
+ args.size <= 0 ? now : new_without_mock_time(*args)
26
23
  end
27
24
 
25
+ ruby2_keywords :new_with_mock_time if Module.private_method_defined?(:ruby2_keywords)
26
+
28
27
  alias_method :new, :new_with_mock_time
29
28
  end
30
- end
31
-
32
- if Object.const_defined?(:Date) && Date.respond_to?(:today)
33
- class Date #:nodoc:
34
- class << self
35
- def mock_date
36
- mocked_time_stack_item = Timecop.top_stack_item
37
- mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.date(self)
29
+ end
30
+
31
+ class Date #:nodoc:
32
+ class << self
33
+ def mock_date
34
+ mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.date(self)
35
+ end
36
+
37
+ alias_method :today_without_mock_date, :today
38
+
39
+ def today_with_mock_date
40
+ mock_date || today_without_mock_date
41
+ end
42
+
43
+ alias_method :today, :today_with_mock_date
44
+
45
+ alias_method :strptime_without_mock_date, :strptime
46
+
47
+ def strptime_with_mock_date(str = '-4712-01-01', fmt = '%F', start = Date::ITALY)
48
+ #If date is not valid the following line raises
49
+ Date.strptime_without_mock_date(str, fmt, start)
50
+
51
+ d = Date._strptime(str, fmt)
52
+ now = Time.now.to_date
53
+ year = d[:year] || now.year
54
+ mon = d[:mon] || now.mon
55
+ if d.keys == [:year]
56
+ Date.new(year, 1, 1, start)
57
+ elsif d[:mday]
58
+ Date.new(year, mon, d[:mday], start)
59
+ elsif d[:wday]
60
+ Date.new(year, mon, now.mday, start) + (d[:wday] - now.wday)
61
+ elsif d[:yday]
62
+ Date.new(year, 1, 1, start).next_day(d[:yday] - 1)
63
+ elsif d[:cwyear] && d[:cweek]
64
+ if d[:cwday]
65
+ Date.commercial(d[:cwyear], d[:cweek], d[:cwday], start)
66
+ else
67
+ Date.commercial(d[:cwyear], d[:cweek], 1, start)
68
+ end
69
+ elsif d[:seconds]
70
+ Time.at(d[:seconds]).to_date
71
+ else
72
+ Date.new(year, mon, 1, start)
38
73
  end
39
-
40
- alias_method :today_without_mock_date, :today
41
-
42
- def today_with_mock_date
43
- mock_date || today_without_mock_date
74
+ end
75
+
76
+ alias_method :strptime, :strptime_with_mock_date
77
+
78
+ def parse_with_mock_date(*args)
79
+ parsed_date = parse_without_mock_date(*args)
80
+ return parsed_date unless mocked_time_stack_item
81
+ date_hash = Date._parse(*args)
82
+
83
+ case
84
+ when date_hash[:year] && date_hash[:mon]
85
+ parsed_date
86
+ when date_hash[:mon] && date_hash[:mday]
87
+ Date.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
88
+ when date_hash[:mday]
89
+ Date.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
90
+ when date_hash[:wday]
91
+ closest_wday(date_hash[:wday])
92
+ else
93
+ parsed_date + mocked_time_stack_item.travel_offset_days
44
94
  end
45
-
46
- alias_method :today, :today_with_mock_date
95
+ end
96
+
97
+ alias_method :parse_without_mock_date, :parse
98
+ alias_method :parse, :parse_with_mock_date
99
+
100
+ def mocked_time_stack_item
101
+ Timecop.top_stack_item
102
+ end
103
+
104
+ def closest_wday(wday)
105
+ today = Date.today
106
+ result = today - today.wday
107
+ result += 1 until wday == result.wday
108
+ result
47
109
  end
48
110
  end
49
111
  end
50
112
 
51
- if Object.const_defined?(:DateTime) && DateTime.respond_to?(:now)
52
- class DateTime #:nodoc:
53
- class << self
54
- def mock_time
55
- mocked_time_stack_item = Timecop.top_stack_item
56
- mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.datetime(self)
57
- end
58
-
59
- def now_without_mock_time
60
- Time.now_without_mock_time.to_datetime
61
- end
62
-
63
- def now_with_mock_time
64
- mock_time || now_without_mock_time
65
- end
113
+ class DateTime #:nodoc:
114
+ class << self
115
+ def mock_time
116
+ mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.datetime(self)
117
+ end
66
118
 
67
- alias_method :now, :now_with_mock_time
119
+ def now_with_mock_time
120
+ mock_time || now_without_mock_time
68
121
  end
69
- end
70
122
 
71
- # for ruby1.8
72
- unless Time::public_instance_methods.include? :to_datetime
73
- class DateTime
74
- class << self
75
- def now_without_mock_time
76
- Time.now_without_mock_time.send(:to_datetime)
77
- end
123
+ alias_method :now_without_mock_time, :now
124
+
125
+ alias_method :now, :now_with_mock_time
126
+
127
+ def parse_with_mock_date(*args)
128
+ date_hash = Date._parse(*args)
129
+ parsed_date = parse_without_mock_date(*args)
130
+ return parsed_date unless mocked_time_stack_item
131
+ date_hash = DateTime._parse(*args)
132
+
133
+ case
134
+ when date_hash[:year] && date_hash[:mon]
135
+ parsed_date
136
+ when date_hash[:mon] && date_hash[:mday]
137
+ DateTime.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
138
+ when date_hash[:mday]
139
+ DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
140
+ when date_hash[:wday]
141
+ Date.closest_wday(date_hash[:wday]).to_datetime
142
+ else
143
+ parsed_date + mocked_time_stack_item.travel_offset_days
78
144
  end
79
145
  end
146
+
147
+ alias_method :parse_without_mock_date, :parse
148
+ alias_method :parse, :parse_with_mock_date
149
+
150
+ def mocked_time_stack_item
151
+ Timecop.top_stack_item
152
+ end
80
153
  end
81
154
  end
@@ -1,158 +1,140 @@
1
1
  class Timecop
2
- # A data class for carrying around "time movement" objects. Makes it easy to keep track of the time
3
- # movements on a simple stack.
4
- class TimeStackItem #:nodoc:
5
- attr_reader :mock_type
6
-
7
- def initialize(mock_type, *args)
8
- raise "Unknown mock_type #{mock_type}" unless [:freeze, :travel, :scale].include?(mock_type)
9
- @scaling_factor = args.shift if mock_type == :scale
10
- @mock_type = mock_type
11
- @time = parse_time(*args)
12
- @time_was = Time.now_without_mock_time
13
- @travel_offset = compute_travel_offset
14
- @dst_adjustment = compute_dst_adjustment(@time)
15
- end
16
-
17
- def year
18
- time.year
19
- end
2
+ # A data class for carrying around "time movement" objects. Makes it easy to keep track of the time
3
+ # movements on a simple stack.
4
+ class TimeStackItem #:nodoc:
5
+ attr_reader :mock_type
6
+
7
+ def initialize(mock_type, *args)
8
+ raise "Unknown mock_type #{mock_type}" unless [:freeze, :travel, :scale].include?(mock_type)
9
+ @travel_offset = @scaling_factor = nil
10
+ @scaling_factor = args.shift if mock_type == :scale
11
+ @mock_type = mock_type
12
+ @time = parse_time(*args)
13
+ @time_was = Time.now_without_mock_time
14
+ @travel_offset = compute_travel_offset
15
+ end
20
16
 
21
- def month
22
- time.month
23
- end
17
+ def year
18
+ time.year
19
+ end
24
20
 
25
- def day
26
- time.day
27
- end
21
+ def month
22
+ time.month
23
+ end
28
24
 
29
- def hour
30
- time.hour
31
- end
25
+ def day
26
+ time.day
27
+ end
32
28
 
33
- def min
34
- time.min
35
- end
29
+ def hour
30
+ time.hour
31
+ end
36
32
 
37
- def sec
38
- time.sec
39
- end
33
+ def min
34
+ time.min
35
+ end
40
36
 
41
- def utc_offset
42
- time.utc_offset
43
- end
37
+ def sec
38
+ time.sec
39
+ end
44
40
 
45
- def travel_offset
46
- @travel_offset
47
- end
41
+ def utc_offset
42
+ time.utc_offset
43
+ end
48
44
 
49
- def scaling_factor
50
- @scaling_factor
51
- end
45
+ def travel_offset
46
+ @travel_offset unless mock_type == :freeze
47
+ end
52
48
 
53
- def time(klass = time_klass) #:nodoc:
54
- begin
55
- actual_time = klass.at(@time)
56
- calculated_time = klass.at(@time.to_f)
57
- time = times_are_equal_within_epsilon(actual_time, calculated_time, 1) ? actual_time : calculated_time
58
- rescue
59
- time = klass.at(@time.to_f)
60
- end
49
+ def travel_offset_days
50
+ (@travel_offset / 60 / 60 / 24).round
51
+ end
61
52
 
62
- if travel_offset.nil?
63
- time
64
- elsif scaling_factor.nil?
65
- klass.at(Time.now_without_mock_time + travel_offset)
66
- else
67
- klass.at(scaled_time)
68
- end
69
- end
53
+ def scaling_factor
54
+ @scaling_factor
55
+ end
70
56
 
71
- def scaled_time
72
- (@time + (Time.now_without_mock_time - @time_was) * scaling_factor).to_f
57
+ def time(time_klass = Time) #:nodoc:
58
+ if @time.respond_to?(:in_time_zone)
59
+ time = time_klass.at(@time.dup.localtime)
60
+ else
61
+ time = time_klass.at(@time)
73
62
  end
74
63
 
75
- def date(date_klass = Date)
76
- date_klass.jd(time.__send__(:to_date).jd)
64
+ if travel_offset.nil?
65
+ time
66
+ elsif scaling_factor.nil?
67
+ time_klass.at(Time.now_without_mock_time + travel_offset)
68
+ else
69
+ time_klass.at(scaled_time)
77
70
  end
71
+ end
78
72
 
79
- def datetime(datetime_klass = DateTime)
80
- our_offset = utc_offset + dst_adjustment
73
+ def scaled_time
74
+ (@time + (Time.now_without_mock_time - @time_was) * scaling_factor).to_f
75
+ end
81
76
 
82
- if Float.method_defined?(:to_r)
83
- fractions_of_a_second = time.to_f % 1
84
- datetime_klass.new(year, month, day, hour, min, sec + fractions_of_a_second, utc_offset_to_rational(our_offset))
85
- else
86
- our_offset = utc_offset + dst_adjustment
87
- datetime_klass.new(year, month, day, hour, min, sec, utc_offset_to_rational(our_offset))
88
- end
89
- end
77
+ def date(date_klass = Date)
78
+ date_klass.jd(time.__send__(:to_date).jd)
79
+ end
90
80
 
91
- def dst_adjustment
92
- @dst_adjustment
81
+ def datetime(datetime_klass = DateTime)
82
+ if Float.method_defined?(:to_r)
83
+ fractions_of_a_second = time.to_f % 1
84
+ datetime_klass.new(year, month, day, hour, min, (fractions_of_a_second + sec), utc_offset_to_rational(utc_offset))
85
+ else
86
+ datetime_klass.new(year, month, day, hour, min, sec, utc_offset_to_rational(utc_offset))
93
87
  end
88
+ end
94
89
 
95
- private
90
+ private
96
91
 
97
- def rational_to_utc_offset(rational)
98
- ((24.0 / rational.denominator) * rational.numerator) * (60 * 60)
99
- end
92
+ def rational_to_utc_offset(rational)
93
+ ((24.0 / rational.denominator) * rational.numerator) * (60 * 60)
94
+ end
100
95
 
101
- def utc_offset_to_rational(utc_offset)
102
- Rational(utc_offset, 24 * 60 * 60)
103
- end
96
+ def utc_offset_to_rational(utc_offset)
97
+ Rational(utc_offset, 24 * 60 * 60)
98
+ end
104
99
 
105
- def parse_time(*args)
106
- arg = args.shift
107
- if arg.is_a?(Time)
108
- if Timecop.active_support != false && arg.respond_to?(:in_time_zone)
109
- arg.in_time_zone
110
- else
111
- arg.getlocal
112
- end
113
- elsif Object.const_defined?(:DateTime) && arg.is_a?(DateTime)
114
- expected_time = time_klass.local(arg.year, arg.month, arg.day, arg.hour, arg.min, arg.sec)
115
- expected_time += expected_time.utc_offset - rational_to_utc_offset(arg.offset)
116
- expected_time + compute_dst_adjustment(expected_time)
117
- elsif Object.const_defined?(:Date) && arg.is_a?(Date)
118
- time_klass.local(arg.year, arg.month, arg.day, 0, 0, 0)
119
- elsif args.empty? && arg.kind_of?(Integer)
120
- Time.now + arg
121
- elsif arg.nil?
122
- Time.now
100
+ def parse_time(*args)
101
+ arg = args.shift
102
+ if arg.is_a?(Time)
103
+ arg
104
+ elsif Object.const_defined?(:DateTime) && arg.is_a?(DateTime)
105
+ time_klass.at(arg.to_time.to_f).getlocal
106
+ elsif Object.const_defined?(:Date) && arg.is_a?(Date)
107
+ time_klass.local(arg.year, arg.month, arg.day, 0, 0, 0)
108
+ elsif args.empty? && (arg.kind_of?(Integer) || arg.kind_of?(Float))
109
+ time_klass.now + arg
110
+ elsif arg.nil?
111
+ time_klass.now
112
+ else
113
+ if arg.is_a?(String) && Time.respond_to?(:parse)
114
+ time_klass.parse(arg)
123
115
  else
124
- if arg.is_a?(String) && Timecop.active_support != false && Time.respond_to?(:parse)
125
- Time.parse(arg)
126
- else
127
- # we'll just assume it's a list of y/m/d/h/m/s
128
- year = arg || 2000
129
- month = args.shift || 1
130
- day = args.shift || 1
131
- hour = args.shift || 0
132
- minute = args.shift || 0
133
- second = args.shift || 0
134
- time_klass.local(year, month, day, hour, minute, second)
135
- end
116
+ # we'll just assume it's a list of y/m/d/h/m/s
117
+ year = arg || 2000
118
+ month = args.shift || 1
119
+ day = args.shift || 1
120
+ hour = args.shift || 0
121
+ minute = args.shift || 0
122
+ second = args.shift || 0
123
+ time_klass.local(year, month, day, hour, minute, second)
136
124
  end
137
125
  end
126
+ end
138
127
 
139
- def compute_dst_adjustment(time)
140
- return 0 if !(time.dst? ^ Time.now.dst?)
141
- return -1 * 60 * 60 if time.dst?
142
- return 60 * 60
143
- end
144
-
145
- def compute_travel_offset
146
- return nil if mock_type == :freeze
147
- time - Time.now_without_mock_time
148
- end
128
+ def compute_travel_offset
129
+ time - Time.now_without_mock_time
130
+ end
149
131
 
150
- def times_are_equal_within_epsilon t1, t2, epsilon_in_seconds
151
- (t1 - t2).abs < epsilon_in_seconds
152
- end
132
+ def times_are_equal_within_epsilon t1, t2, epsilon_in_seconds
133
+ (t1 - t2).abs < epsilon_in_seconds
134
+ end
153
135
 
154
- def time_klass
155
- Time.respond_to?(:zone) && Time.zone ? Time.zone : Time
156
- end
136
+ def time_klass
137
+ Time.respond_to?(:zone) && Time.zone ? Time.zone : Time
157
138
  end
158
139
  end
140
+ end