timecop 0.9.8 → 0.9.9

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: ad1963ee820d4d3519b4e078879aaa3914b2e9802460480fd9ca3c4a239677e4
4
- data.tar.gz: 49a827fc02c8580d33d6861f51974dd046996e7281442c33f89c527d4d4c5af0
3
+ metadata.gz: 5ffc3899071434ff0ae8eb0a9e4a6ea4c2d8794547113c272bdc24a384d2eb45
4
+ data.tar.gz: e9333e4c2cf362558c432d7b954a724ff588e66c4dcce8d3af4a327dd6dcb894
5
5
  SHA512:
6
- metadata.gz: d18895efbc69f3768fcf68fa372759e727c30869e5ff1a77c8b7a2901e4a89dd49fe61df38c0a5c57dd9604250e0c49733c990c32757ac9a374a56fb3962d441
7
- data.tar.gz: 6938b5dfc45c545d8c0e83b757f1b99d9b69b2cfe23d5e1d0f9b4fc4ff56282af201a982bcf52084f05b0de88ea36256ecbe54e2988fc944693940f5179dcb97
6
+ metadata.gz: 692759ecf208cccb83f72d2cd2a3632d6fb6477e9ac1dbf1ca19d8c23a0b864093abdfdc1d51ee98078858dc2dd3eab50f1bd8b469cc84f0619c99bed242169f
7
+ data.tar.gz: 85fc3b65a8f415601a047d4189ff497a73f49d4d48647881a6579d82dc6f12ab9e6a088da0ca2b3c2a25693f220ce3c8f31b5f2847f6a5d4784c63ace77136ff
data/README.markdown CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  ## DESCRIPTION
7
7
 
8
- A gem providing "time travel" and "time freezing" capabilities, making it dead simple to test time-dependent code. It provides a unified method to mock `Time.now`, `Date.today`, and `DateTime.now` in a single call.
8
+ A gem providing "time travel" and "time freezing" capabilities, making it dead simple to test time-dependent code. It provides a unified method to mock `Time.now`, `Date.today`, `DateTime.now`, and `Process.clock_gettime` in a single call.
9
9
 
10
10
  ## INSTALL
11
11
 
@@ -143,8 +143,17 @@ class DateTime #:nodoc:
143
143
  DateTime.new(mocked_time_stack_item.year, date_hash[:mon], date_hash[:mday])
144
144
  when date_hash[:mday]
145
145
  DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, date_hash[:mday])
146
+ when date_hash[:wday] && date_hash[:hour] && date_hash[:min]
147
+ closest_date = Date.closest_wday(date_hash[:wday]).to_datetime
148
+
149
+ DateTime.new(
150
+ closest_date.year, closest_date.month, closest_date.day,
151
+ date_hash[:hour], date_hash[:min]
152
+ )
146
153
  when date_hash[:wday]
147
154
  Date.closest_wday(date_hash[:wday]).to_datetime
155
+ when date_hash[:hour] && date_hash[:min] && date_hash[:sec]
156
+ DateTime.new(mocked_time_stack_item.year, mocked_time_stack_item.month, mocked_time_stack_item.day, date_hash[:hour], date_hash[:min], date_hash[:sec])
148
157
  else
149
158
  parsed_date + mocked_time_stack_item.travel_offset_days
150
159
  end
@@ -158,3 +167,59 @@ class DateTime #:nodoc:
158
167
  end
159
168
  end
160
169
  end
170
+
171
+ if RUBY_VERSION >= '2.1.0'
172
+ module Process #:nodoc:
173
+ class << self
174
+ alias_method :clock_gettime_without_mock, :clock_gettime
175
+
176
+ def clock_gettime_mock_time(clock_id, unit = :float_second)
177
+ mock_time = case clock_id
178
+ when Process::CLOCK_MONOTONIC
179
+ mock_time_monotonic
180
+ when Process::CLOCK_REALTIME
181
+ mock_time_realtime
182
+ end
183
+
184
+ return clock_gettime_without_mock(clock_id, unit) unless mock_time
185
+
186
+ divisor = case unit
187
+ when :float_second
188
+ 1_000_000_000.0
189
+ when :second
190
+ 1_000_000_000
191
+ when :float_millisecond
192
+ 1_000_000.0
193
+ when :millisecond
194
+ 1_000_000
195
+ when :float_microsecond
196
+ 1000.0
197
+ when :microsecond
198
+ 1000
199
+ when :nanosecond
200
+ 1
201
+ end
202
+
203
+ (mock_time / divisor)
204
+ end
205
+
206
+ alias_method :clock_gettime, :clock_gettime_mock_time
207
+
208
+ private
209
+
210
+ def mock_time_monotonic
211
+ mocked_time_stack_item = Timecop.top_stack_item
212
+ mocked_time_stack_item.nil? ? nil : mocked_time_stack_item.monotonic
213
+ end
214
+
215
+ def mock_time_realtime
216
+ mocked_time_stack_item = Timecop.top_stack_item
217
+
218
+ return nil if mocked_time_stack_item.nil?
219
+
220
+ t = mocked_time_stack_item.time
221
+ t.to_i * 1_000_000_000 + t.nsec
222
+ end
223
+ end
224
+ end
225
+ end
@@ -9,6 +9,7 @@ class Timecop
9
9
  @travel_offset = @scaling_factor = nil
10
10
  @scaling_factor = args.shift if mock_type == :scale
11
11
  @mock_type = mock_type
12
+ @monotonic = parse_monotonic_time(*args) if RUBY_VERSION >= '2.1.0'
12
13
  @time = parse_time(*args)
13
14
  @time_was = Time.now_without_mock_time
14
15
  @travel_offset = compute_travel_offset
@@ -54,6 +55,26 @@ class Timecop
54
55
  @scaling_factor
55
56
  end
56
57
 
58
+ if RUBY_VERSION >= '2.1.0'
59
+ def monotonic
60
+ if travel_offset.nil?
61
+ @monotonic
62
+ elsif scaling_factor.nil?
63
+ current_monotonic + travel_offset * (10 ** 9)
64
+ else
65
+ (@monotonic + (current_monotonic - @monotonic) * scaling_factor).to_i
66
+ end
67
+ end
68
+
69
+ def current_monotonic
70
+ Process.clock_gettime_without_mock(Process::CLOCK_MONOTONIC, :nanosecond)
71
+ end
72
+
73
+ def current_monotonic_with_mock
74
+ Process.clock_gettime_mock_time(Process::CLOCK_MONOTONIC, :nanosecond)
75
+ end
76
+ end
77
+
57
78
  def time(time_klass = Time) #:nodoc:
58
79
  if @time.respond_to?(:in_time_zone)
59
80
  time = time_klass.at(@time.dup.localtime)
@@ -97,6 +118,16 @@ class Timecop
97
118
  Rational(utc_offset, 24 * 60 * 60)
98
119
  end
99
120
 
121
+ def parse_monotonic_time(*args)
122
+ arg = args.shift
123
+ offset_in_nanoseconds = if args.empty? && (arg.kind_of?(Integer) || arg.kind_of?(Float))
124
+ arg * 1_000_000_000
125
+ else
126
+ 0
127
+ end
128
+ current_monotonic_with_mock + offset_in_nanoseconds
129
+ end
130
+
100
131
  def parse_time(*args)
101
132
  arg = args.shift
102
133
  if arg.is_a?(Time)
@@ -38,6 +38,12 @@ class Timecop
38
38
  # previous values after the block has finished executing. This allows us to nest multiple
39
39
  # calls to Timecop.travel and have each block maintain it's concept of "now."
40
40
  #
41
+ # The Process.clock_gettime call mocks both CLOCK::MONOTIC and CLOCK::REALTIME
42
+ #
43
+ # CLOCK::MONOTONIC works slightly differently than other clocks. This clock cannot move to a
44
+ # particular date/time. So the only option that changes this clock is #4 which will move the
45
+ # clock the requested offset. Otherwise the clock is frozen to the current tick.
46
+ #
41
47
  # * Note: Timecop.freeze will actually freeze time. This can cause unanticipated problems if
42
48
  # benchmark or other timing calls are executed, which implicitly expect Time to actually move
43
49
  # forward.
@@ -126,6 +132,16 @@ class Timecop
126
132
  !instance.stack.empty? && instance.stack.last.mock_type == :freeze
127
133
  end
128
134
 
135
+ # Returns whether or not Timecop is currently travelled
136
+ def travelled?
137
+ !instance.stack.empty? && instance.stack.last.mock_type == :travel
138
+ end
139
+
140
+ # Returns whether or not Timecop is currently scaled
141
+ def scaled?
142
+ !instance.stack.empty? && instance.stack.last.mock_type == :scale
143
+ end
144
+
129
145
  private
130
146
  def send_travel(mock_type, *args, &block)
131
147
  val = instance.travel(mock_type, *args, &block)
@@ -1,3 +1,3 @@
1
1
  class Timecop
2
- VERSION = "0.9.8"
2
+ VERSION = "0.9.9"
3
3
  end
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.8
4
+ version: 0.9.9
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: 2023-08-14 00:00:00.000000000 Z
12
+ date: 2024-06-01 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