File Coverage

blib/lib/Time/Mock.pm
Criterion Covered Total %
statement 53 65 81.5
branch 15 24 62.5
condition n/a
subroutine 16 21 76.1
pod 8 8 100.0
total 92 118 77.9


line stmt bran cond sub pod time code
1             package Time::Mock;
2             $VERSION = v0.0.2;
3              
4 3     3   67025 use warnings;
  3         7  
  3         100  
5 3     3   20 use strict;
  3         6  
  3         319  
6 3     3   67 use Carp;
  3         6  
  3         495  
7              
8             =head1 NAME
9              
10             Time::Mock - shift and scale time
11              
12             =head1 SYNOPSIS
13              
14             Speed up your sleep(), alarm(), and time() calls.
15              
16             use Time::Mock throttle => 100;
17             use Your::Code;
18              
19             =head1 ABOUT
20              
21             Test::MockTime is nice, but doesn't allow you to accelerate the timestep
22             and doesn't deal with Time::HiRes or give you any way to change the time
23             across forks.
24              
25             TODO: replace Time::HiRes functions with wrappers
26              
27             TODO: finish the interfaces to real time/sleep/alarm
28              
29             =head1 Replaces
30              
31             These core functions are replaced.
32              
33             Eventually, much of the same bits from Time::HiRes will be
34             correspondingly overwritten.
35              
36             =over
37              
38             =item time
39              
40             =item localtime
41              
42             =item gmtime
43              
44             =item sleep
45              
46             Sleeps for 1/$throttle.
47              
48             =item alarm
49              
50             Alarm happens in 1/$throttle.
51              
52             =back
53              
54             =cut
55              
56             # TODO issue: anybody that said 'use Time::HiRes' before we arrived got
57             # imports of the original versions. Complain very loudly?
58              
59 3     3   4071 use Time::HiRes ();
  3         6963  
  3         371  
60             BEGIN {
61             package Time::Mock::Original;
62 3     3   11 *time = \&Time::HiRes::time;
63 3         7 *sleep = \&Time::HiRes::sleep;
64 3         450 *alarm = \&Time::HiRes::alarm;
65             }
66              
67             sub time ();
68             sub localtime (;$);
69             sub gmtime (;$);
70             sub sleep (;$);
71             sub alarm (;$);
72             BEGIN {
73 3     3   13 *CORE::GLOBAL::time = \&time;
74 3         5 *CORE::GLOBAL::localtime = \&localtime;
75 3         7 *CORE::GLOBAL::gmtime = \&gmtime;
76 3         6 *CORE::GLOBAL::sleep = \&sleep;
77 3         7 *CORE::GLOBAL::alarm = \&alarm;
78              
79 3     3   23 no warnings 'redefine';
  3         6  
  3         380  
80 3     0   17 *Time::HiRes::time = sub () {goto &_hitime};
  0         0  
81 3     0   13 *Time::HiRes::sleep = sub (;@) {goto &sleep};
  0         0  
82 3     0   989 *Time::HiRes::alarm = sub ($;$) {goto &alarm};
  0         0  
83             }
84              
85             sub import {
86 5     5   2225 my $class = shift;
87 5 100       163 (@_ % 2) and croak("odd number of elements in argument list");
88 4         15 my (%args) = @_;
89 4         1927 foreach my $k (keys(%args)) {
90 3 100       223 $class->can($k) or croak("unknown method '$k'");
91 2         7 $class->$k($args{$k});
92             }
93             }
94              
95             =head1 Class Methods
96              
97             These are the knobs on your time machine, but note that it is probably
98             best to adjust them only once: see L. For convenience,
99             import() takes will call these methods with each key in its argument
100             list.
101              
102             perl -MTime::Mock=throttle,600,set,"2009-11-01 00:59" dst_bug.pl
103              
104             =head2 throttle
105              
106             Get or set the throttle.
107              
108             Time::Mock->throttle(10_000);
109              
110             =head2 offset
111              
112             Get or set the offset.
113              
114             Time::Mock->offset(120);
115              
116             =head2 set
117              
118             Set the time to a given value. This may be a numeric time or anything
119             parseable by Date::Parse::str2time() (you need to install Date::Parse to
120             enable this.)
121              
122             Time::Mock->set("2009-11-01 00:59");
123              
124             =head1 Caveats
125              
126             This package remembers the actual system time when it was loaded and
127             makes adjustments from there.
128              
129             Future versions might change this behavior if I can think of a good
130             reason and scheme for that.
131              
132             =head2 forks and threads
133              
134             The throttle value will hold across forks, but there is no support for
135             propagating changes to child processes. So, set the knobs only before
136             you fork!
137              
138             Don't ask about threads unless you're asking about me applying your
139             patch thanks.
140              
141             =head2 Networking and System stuff
142              
143             We're only lying about the clock inside of Perl, not magically messing
144             with the universe.
145              
146             =head2 Time Travel is Dangerous
147              
148             I suggest that you set the knobs at import() and don't mess with them
149             after that unless you're well aware of how your code is using time.
150              
151             Messing with the throttle during runtime could also give your code the
152             illusion of time going backwards. If your code tries to do math with
153             the return values of time() before and after a slow-down, there could be
154             trouble.
155              
156             Changing the throttle while an alarm() is set won't change the original
157             alarm time. There would be a similar caveat about sleep() if I hadn't already mentioned forks ;-)
158              
159             Finally, don't ever let your past self see your future self.
160              
161             =cut
162              
163             our $accel = 1;
164             sub throttle {
165 8     8 1 3074 my $class = shift;
166 8 100       44 return $accel unless(@_);
167              
168 5         10 my $v = shift(@_);
169 5 50       18 $v or croak("cannot set throttle to zero");
170 5         14 $accel = $v;
171             }
172              
173             our $offset = 0;
174             sub offset {
175 2     2 1 4 my $class = shift;
176 2 100       9 return $offset unless(@_);
177 1         2354 $offset = shift(@_);
178             }
179              
180 3     3   1653 BEGIN { *_realtime = \&Time::Mock::Original::time};
181             our $otime = _realtime;
182              
183             sub set {
184 0     0 1 0 my $class = shift;
185 0 0       0 my $set = shift(@_) or croak("must have time to set");
186 0 0       0 unless($set =~ m/^\d+$/) {
187 0         0 require Date::Parse;
188 0         0 $set = Date::Parse::str2time($set);
189             }
190 0         0 $offset = $set - $otime;
191             }
192              
193             sub _hitime () {
194 7     7   160 return(($otime + $offset) + (_realtime - $otime) * $accel);
195             }
196              
197             sub time () {
198 7     7 1 40 return sprintf("%0.0f", _hitime);
199             }
200              
201             sub localtime (;$) {
202 2     2 1 8 my ($time) = @_;
203              
204 2 100       10 $time = time unless(defined $time);
205 2         218 return CORE::localtime($time);
206             }
207              
208             sub gmtime (;$) {
209 0     0 1 0 my ($time) = @_;
210              
211 0 0       0 $time = time unless(defined $time);
212 0         0 return CORE::gmtime($time);;
213             }
214             sub sleep (;$) {
215 2     2 1 459 my ($length) = @_;
216              
217 2 50       8 return CORE::sleep unless($length);
218 2         410474 return Time::Mock::Original::sleep($length / $accel);
219             }
220             sub alarm (;$) {
221 2     2 1 19 my ($length) = @_;
222              
223 2 50       9 $length = $_ unless(defined($length));
224 2 100       28 return CORE::alarm(0) unless($length);
225 1         19 return Time::Mock::Original::alarm($length / $accel);
226             }
227              
228              
229              
230              
231             =head1 AUTHOR
232              
233             Eric Wilhelm @
234              
235             http://scratchcomputing.com/
236              
237             =head1 BUGS
238              
239             If you found this module on CPAN, please report any bugs or feature
240             requests through the web interface at L. I will be
241             notified, and then you'll automatically be notified of progress on your
242             bug as I make changes.
243              
244             If you pulled this development version from my /svn/, please contact me
245             directly.
246              
247             =head1 COPYRIGHT
248              
249             Copyright (C) 2008 Eric L. Wilhelm, All Rights Reserved.
250              
251             =head1 NO WARRANTY
252              
253             Absolutely, positively NO WARRANTY, neither express or implied, is
254             offered with this software. You use this software at your own risk. In
255             case of loss, no person or entity owes you anything whatsoever. You
256             have been warned.
257              
258             =head1 LICENSE
259              
260             This program is free software; you can redistribute it and/or modify it
261             under the same terms as Perl itself.
262              
263             =cut
264              
265             # vi:ts=2:sw=2:et:sta
266             1;