timecop 0.9.4 → 0.9.5

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e107de03899173505259909d8ec9e008082d8fa4cf551a2326a6bc98890285e
4
- data.tar.gz: e50a9c462cafa4feb5a1b47fc720f853c1a7ac62bd5d404ecad3f2b749be0ef4
3
+ metadata.gz: 681f52d846b808b06ff833f3fbfc21e3c7c4c1bf426baa03f101c0a2c3b79ce8
4
+ data.tar.gz: b95b6d4a3c357e7f11f046d82dad3badd81d4903c96ef2b8e77762f241eeb66e
5
5
  SHA512:
6
- metadata.gz: 427b83dd2d0506193c3c4d947cb1281817a531a64f09f73f004d97c17339665311774e775bc7506e4447ed2c66636e0df2cd954447e079409aef347262ab3e30
7
- data.tar.gz: 631df874968afa111e81b255d665972085ec64a6c315b424304148a75c3226eb7e0f259ed7d149c6829950394f340b4cd595fa21720149104b2c4c8e2448b586
6
+ metadata.gz: e62e48939fb924a78d59199222688ae7692a2f6649c16daac296375ac1e537fa1c85e6a34d1a5cbd64b209e643ffa08d180ce3d933905f91284ce4c819873c1e
7
+ data.tar.gz: f6f5ef32ee1bfadfd43a5a8899bb521873d61eafd2f242942df6e80a3ed11f80a170d074ada23a61eb3b92009eeaf3a1046b126c802dc9a1c014c77d32acb3ab
data/README.markdown CHANGED
@@ -1,6 +1,7 @@
1
1
  # timecop
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/travisjeffery/timecop.svg)](http://travis-ci.org/travisjeffery/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)
4
5
 
5
6
  ## DESCRIPTION
6
7
 
@@ -50,11 +50,16 @@ class Date #:nodoc:
50
50
  "supports Date::ITALY for the start argument."
51
51
  end
52
52
 
53
- d = Date._strptime(str, fmt) || Date.strptime_without_mock_date(str, fmt)
53
+ #If date is not valid the following line raises
54
+ Date.strptime_without_mock_date(str, fmt)
55
+
56
+ d = Date._strptime(str, fmt)
54
57
  now = Time.now.to_date
55
58
  year = d[:year] || now.year
56
59
  mon = d[:mon] || now.mon
57
- if d[:mday]
60
+ if d.keys == [:year]
61
+ Date.new(year)
62
+ elsif d[:mday]
58
63
  Date.new(year, mon, d[:mday])
59
64
  elsif d[:wday]
60
65
  Date.new(year, mon, now.mday) + (d[:wday] - now.wday)
@@ -85,6 +90,8 @@ class Date #:nodoc:
85
90
  parsed_date
86
91
  when date_hash[:mon] && date_hash[:mday]
87
92
  Date.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
93
+ when date_hash[:mday]
94
+ Date.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
88
95
  when date_hash[:wday]
89
96
  closest_wday(date_hash[:wday])
90
97
  else
@@ -133,6 +140,8 @@ class DateTime #:nodoc:
133
140
  parsed_date
134
141
  when date_hash[:mon] && date_hash[:mday]
135
142
  DateTime.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
143
+ when date_hash[:mday]
144
+ DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
136
145
  when date_hash[:wday]
137
146
  Date.closest_wday(date_hash[:wday]).to_datetime
138
147
  else
@@ -1,140 +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
- @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
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 unless mock_type == :freeze
47
- end
41
+ def utc_offset
42
+ time.utc_offset
43
+ end
48
44
 
49
- def travel_offset_days
50
- (@travel_offset / 60 / 60 / 24).round
51
- end
45
+ def travel_offset
46
+ @travel_offset unless mock_type == :freeze
47
+ end
52
48
 
53
- def scaling_factor
54
- @scaling_factor
55
- end
49
+ def travel_offset_days
50
+ (@travel_offset / 60 / 60 / 24).round
51
+ end
56
52
 
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)
62
- end
53
+ def scaling_factor
54
+ @scaling_factor
55
+ end
63
56
 
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)
70
- end
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)
71
62
  end
72
63
 
73
- def scaled_time
74
- (@time + (Time.now_without_mock_time - @time_was) * scaling_factor).to_f
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)
75
70
  end
71
+ end
76
72
 
77
- def date(date_klass = Date)
78
- date_klass.jd(time.__send__(:to_date).jd)
79
- end
73
+ def scaled_time
74
+ (@time + (Time.now_without_mock_time - @time_was) * scaling_factor).to_f
75
+ end
80
76
 
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))
87
- end
77
+ def date(date_klass = Date)
78
+ date_klass.jd(time.__send__(:to_date).jd)
79
+ end
80
+
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))
88
87
  end
88
+ end
89
89
 
90
- private
90
+ private
91
91
 
92
- def rational_to_utc_offset(rational)
93
- ((24.0 / rational.denominator) * rational.numerator) * (60 * 60)
94
- end
92
+ def rational_to_utc_offset(rational)
93
+ ((24.0 / rational.denominator) * rational.numerator) * (60 * 60)
94
+ end
95
95
 
96
- def utc_offset_to_rational(utc_offset)
97
- Rational(utc_offset, 24 * 60 * 60)
98
- end
96
+ def utc_offset_to_rational(utc_offset)
97
+ Rational(utc_offset, 24 * 60 * 60)
98
+ end
99
99
 
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
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)
112
115
  else
113
- if arg.is_a?(String) && Time.respond_to?(:parse)
114
- time_klass.parse(arg)
115
- else
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)
124
- 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)
125
124
  end
126
125
  end
126
+ end
127
127
 
128
- def compute_travel_offset
129
- time - Time.now_without_mock_time
130
- end
128
+ def compute_travel_offset
129
+ time - Time.now_without_mock_time
130
+ end
131
131
 
132
- def times_are_equal_within_epsilon t1, t2, epsilon_in_seconds
133
- (t1 - t2).abs < epsilon_in_seconds
134
- end
132
+ def times_are_equal_within_epsilon t1, t2, epsilon_in_seconds
133
+ (t1 - t2).abs < epsilon_in_seconds
134
+ end
135
135
 
136
- def time_klass
137
- Time.respond_to?(:zone) && Time.zone ? Time.zone : Time
138
- end
136
+ def time_klass
137
+ Time.respond_to?(:zone) && Time.zone ? Time.zone : Time
139
138
  end
139
+ end
140
140
  end
@@ -13,6 +13,8 @@ class Timecop
13
13
  include Singleton
14
14
 
15
15
  class << self
16
+ private :instance
17
+
16
18
  # Allows you to run a block of code and "fake" a time throughout the execution of that block.
17
19
  # This is particularly useful for writing test methods where the passage of time is critical to the business
18
20
  # logic being tested. For example:
@@ -74,11 +76,11 @@ class Timecop
74
76
  end
75
77
 
76
78
  def baseline
77
- instance.send(:baseline)
79
+ instance.baseline
78
80
  end
79
81
 
80
82
  def baseline=(baseline)
81
- instance.send(:baseline=, baseline)
83
+ instance.baseline = baseline
82
84
  end
83
85
 
84
86
  # Reverts back to system's Time.now, Date.today and DateTime.now (if it exists) permamently when
@@ -86,21 +88,21 @@ class Timecop
86
88
  # the given block.
87
89
  def return(&block)
88
90
  if block_given?
89
- instance.send(:return, &block)
91
+ instance.return(&block)
90
92
  else
91
- instance.send(:unmock!)
93
+ instance.unmock!
92
94
  nil
93
95
  end
94
96
  end
95
97
  alias :unfreeze :return
96
98
 
97
99
  def return_to_baseline
98
- instance.send(:return_to_baseline)
100
+ instance.return_to_baseline
99
101
  Time.now
100
102
  end
101
103
 
102
104
  def top_stack_item #:nodoc:
103
- instance.send(:stack).last
105
+ instance.stack.last
104
106
  end
105
107
 
106
108
  def safe_mode=(safe)
@@ -112,27 +114,25 @@ class Timecop
112
114
  end
113
115
 
114
116
  def thread_safe=(t)
115
- instance.send(:thread_safe=, t)
117
+ instance.thread_safe = t
116
118
  end
117
119
 
118
120
  def thread_safe
119
- instance.send(:thread_safe)
121
+ instance.thread_safe
120
122
  end
121
123
 
122
124
  # Returns whether or not Timecop is currently frozen/travelled
123
125
  def frozen?
124
- !instance.send(:stack).empty?
126
+ !instance.stack.empty?
125
127
  end
126
128
 
127
129
  private
128
130
  def send_travel(mock_type, *args, &block)
129
- val = instance.send(:travel, mock_type, *args, &block)
131
+ val = instance.travel(mock_type, *args, &block)
130
132
  block_given? ? val : Time.now
131
133
  end
132
134
  end
133
135
 
134
- private
135
-
136
136
  def baseline=(b)
137
137
  set_baseline(b)
138
138
  stack << TimeStackItem.new(:travel, b)
@@ -1,3 +1,3 @@
1
1
  class Timecop
2
- VERSION = "0.9.4"
2
+ VERSION = "0.9.5"
3
3
  end
data/test/timecop_test.rb CHANGED
@@ -289,6 +289,17 @@ class TestTimecop < Minitest::Test
289
289
  t = Time.local(2008, 10, 10, 10, 10, 10)
290
290
  assert_times_effectively_equal t, Timecop.scale(4, t)
291
291
  end
292
+
293
+ def test_scaling_returns_now_if_nil_supplied
294
+ assert_times_effectively_equal Time.now, Timecop.scale(nil)
295
+ end
296
+
297
+ def test_scaling_raises_when_empty_string_supplied
298
+ err = assert_raises(TypeError) do
299
+ Timecop.scale("")
300
+ end
301
+ assert_match /String can't be coerced into Float/, err.message
302
+ end
292
303
 
293
304
  def test_freeze_with_utc_time
294
305
  each_timezone do
@@ -394,6 +405,10 @@ class TestTimecop < Minitest::Test
394
405
  end
395
406
  assert_times_effectively_equal(time_after_travel, Time.now)
396
407
  end
408
+
409
+ def test_travel_returns_now_if_nil_supplied
410
+ assert_times_effectively_equal Time.now, Timecop.travel(nil)
411
+ end
397
412
 
398
413
  def test_travel_time_with_block_returns_the_value_of_the_block
399
414
  t_future = Time.local(2030, 10, 10, 10, 10, 10)
@@ -402,6 +417,13 @@ class TestTimecop < Minitest::Test
402
417
 
403
418
  assert_equal expected, actual
404
419
  end
420
+
421
+ def test_travel_raises_when_empty_string_supplied
422
+ err = assert_raises(ArgumentError) do
423
+ Timecop.travel("")
424
+ end
425
+ assert_match /no time information in \"\"/, err.message
426
+ end
405
427
 
406
428
  def test_freeze_time_returns_now_if_no_block_given
407
429
  t_future = Time.local(2030, 10, 10, 10, 10, 10)
@@ -428,6 +450,17 @@ class TestTimecop < Minitest::Test
428
450
  end
429
451
  end
430
452
  end
453
+
454
+ def test_freeze_returns_now_if_nil_supplied
455
+ assert_times_effectively_equal Time.now, Timecop.freeze(nil)
456
+ end
457
+
458
+ def test_freeze_raises_when_empty_string_supplied
459
+ err = assert_raises(ArgumentError) do
460
+ Timecop.freeze("")
461
+ end
462
+ assert_match /no time information in \"\"/, err.message
463
+ end
431
464
 
432
465
  def test_freeze_with_new_date
433
466
  date = Date.new(2012, 6, 9)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timecop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.4
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Travis Jeffery
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-02-09 00:00:00.000000000 Z
12
+ date: 2022-03-07 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: A gem providing "time travel" and "time freezing" capabilities, making
15
15
  it dead simple to test time-dependent code. It provides a unified method to mock
@@ -54,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
54
54
  - !ruby/object:Gem::Version
55
55
  version: '0'
56
56
  requirements: []
57
- rubygems_version: 3.0.8
57
+ rubygems_version: 3.2.22
58
58
  signing_key:
59
59
  specification_version: 3
60
60
  summary: A gem providing "time travel" and "time freezing" capabilities, making it