File Coverage

blib/lib/DateTime/Fiscal/Retail454.pm
Criterion Covered Total %
statement 141 143 98.6
branch 59 86 68.6
condition 13 36 36.1
subroutine 21 21 100.0
pod 14 14 100.0
total 248 300 82.6


line stmt bran cond sub pod time code
1             package DateTime::Fiscal::Retail454;
2              
3 7     7   128243 use strict;
  7         16  
  7         169  
4 7     7   34 use warnings;
  7         10  
  7         311  
5              
6             our $VERSION = '0.03';
7              
8             our $R454DEBUG = 0;
9              
10 7     7   31 use Carp;
  7         14  
  7         588  
11              
12 7     7   8401 use DateTime;
  7         1057269  
  7         262  
13 7     7   62 use base qw(DateTime);
  7         15  
  7         12935  
14              
15             my $pkg = __PACKAGE__;
16              
17             my @periodmonths = qw(
18             February
19             March
20             April
21             May
22             June
23             July
24             August
25             September
26             October
27             November
28             December
29             January
30             );
31              
32             # This code ref builds a cache that can be used as long as the value in
33             # the _R454_basedate attribute remains unchanged.
34             my $_r454_build_periods = sub {
35             my $self = shift;
36              
37             return
38             if ref($self->{_R454_periods}) && $self->{_R454_basedate} eq $self->ymd;
39              
40             my @pweeks = (0, 4, 5, 4, 4, 5, 4, 4, 5, 4, 4, 5, 4);
41             $pweeks[$#pweeks] = 5 if $self->is_r454_leap_year;
42              
43             my $pdata = {};
44             my $pstart = $pkg->_454_start($self->r454_year);
45              
46             for (1 .. 12) {
47             $pdata->{$_} = {
48             pstart => $pstart->clone,
49             weeks => $pweeks[$_],
50             r454year => $self->r454_year,
51             month => $periodmonths[$_ - 1]
52             };
53             my $pend =
54             $pstart->clone->add(weeks => $pweeks[$_])->subtract(seconds => 1);
55             $pdata->{$_}->{pend} = $pend;
56             my $ppub = $pend->clone->truncate(to => 'day')->add(days => 5);
57             $pdata->{$_}->{ppub} = $ppub;
58              
59             $pstart = $pstart->clone->add(weeks => $pweeks[$_]);
60             }
61              
62             $self->{_R454_periods} = $pdata;
63             $self->{_R454_basedate} = $self->ymd;
64              
65             };
66              
67             # this code ref is used with versions of DateTime prior to 0.64
68             my $_454_allocate = sub {
69             my $self = shift;
70              
71             $self->{_R454_year} = undef;
72             $self->{_R454_periods} = undef;
73              
74             return;
75             };
76              
77             # this override is required for versions of DateTime starting with 0.64
78             # and serves the same purpose as the above code reference, but in a
79             # much nicer way.
80             sub _new
81             {
82 1368     1368   136820 my $proto = shift;
83 1368         4793 my %params = @_;
84              
85 1368   33     5202 my $class = ref($proto) || $proto;
86              
87 1368         5641 my $self = $class->SUPER::_new(%params);
88 1368         162181 $self->{_R454_year} = undef;
89 1368         1871 $self->{_R454_periods} = undef;
90              
91 1368         7416 return $self;
92             }
93              
94             sub _454_start
95             {
96 150     150   277 my $proto = shift;
97 150         178 my $cyr = shift;
98              
99 150         1191 my ($package, $filename, $line) = caller;
100 150 100       1235 confess "FORBIDDEN private method call" unless $package->isa($pkg);
101              
102 149   66     551 my $class = ref($proto) || $proto;
103              
104             # my $r454tmp = $pkg->SUPER::new( year => $cyr, month => 1, day => 31 );
105 149         695 my $r454tmp = $class->SUPER::new(year => $cyr, month => 1, day => 31);
106 149         515 my $jan31dow = $r454tmp->dow;
107 149 100       1047 if ($jan31dow < 3) {
    100          
108 43         135 $r454tmp->subtract(days => $jan31dow);
109             } elsif ($jan31dow < 7) {
110 94         527 $r454tmp->add(days => (7 - $jan31dow));
111             }
112              
113 149         13932 return $r454tmp;
114             }
115              
116             sub from_r454year
117             {
118 18     18 1 20655 my $proto = shift;
119 18         62 my %params = @_;
120              
121             croak "Mandatory parameter 'r454year' missing"
122 18 50       70 unless defined($params{r454year});
123              
124 18   33     347 my $class = ref($proto) || $proto;
125              
126             #return( bless $pkg->_454_start($params{r454year}), $proto )
127 18         80 return $class->_454_start($params{r454year});
128             }
129              
130             # These have to be overloaded here in order to properly setup any attributes
131             # used by this module. In addition, 'from_day_of_year' has to be here
132             # because it does not ever call the normal 'new' constructor.
133             #
134             # NOTE!!!
135             # It appears that DateTime calls new any time a change is made to the object's
136             # value, through actions such as date math or the 'set' functions.
137             # OTOH, the object is left alone for any of the 'get' functions.
138             #
139             # Because of this, care must be taken to ensure a recursive loop isn't
140             # created, hence the need for a seperate constructor for 'from_r454year'.
141             #
142             # NOTE!!!
143             # The internals of DateTime have changed in version 0.64 which makes
144             # sub-classing much easier. This code has been changed accordingly to
145             # try to pick up which style is being used in DateTime.
146             #
147             # Even so, I am poking around under the hood and can be bit in the future.
148              
149             sub new
150             {
151 1000     1000 1 247067 my $proto = shift;
152 1000         4232 my %params = @_;
153              
154 1000   33     3547 my $class = ref($proto) || $proto;
155              
156 1000         4178 my $self = $class->SUPER::new(%params);
157              
158             # &{$_454_allocate}($self);
159 1000 50       3319 &{$_454_allocate}($self) unless exists($self->{_R454_year});
  0         0  
160              
161 1000         3509 return ($self);
162             }
163              
164             # this override is needed because the constructor in earlier versions of
165             # DateTime did not propagate sub-classing.
166             sub from_day_of_year
167             {
168 2     2 1 1910 my $proto = shift;
169 2         7 my %params = @_;
170              
171 2   33     10 my $class = ref($proto) || $proto;
172              
173             # my $self = bless $pkg->SUPER::from_day_of_year(%params), $proto;
174 2         33 my $self = $class->SUPER::from_day_of_year(%params);
175 2 50       9 bless $self, $class unless ref($self) eq $class;
176              
177             # &{$_454_allocate}($self);
178 2 50       6 &{$_454_allocate}($self) unless exists($self->{_R454_year});
  0         0  
179              
180 2         5 return ($self);
181             }
182              
183             sub r454_year
184             {
185 498     498 1 64977 my $self = shift;
186              
187 498 100       1259 if (!defined($self->{_R454_year})) {
188 21         72 my $r454tmp = $pkg->_454_start($self->year);
189             $self->{_R454_year} =
190 21 50       94 $r454tmp > $self ? $self->year - 1 : $r454tmp->year;
191             }
192              
193 498         5092 return ($self->{_R454_year});
194             }
195              
196             sub is_r454_leap_year
197             {
198 31     31 1 4735 my $self = shift;
199              
200 31         123 my $tmpnext = $pkg->_454_start($self->r454_year)->add(days => 364);
201 31         2913 my $realnext = $pkg->_454_start($self->r454_year + 1);
202              
203 31 100       101 return ($realnext > $tmpnext ? 1 : 0);
204             }
205              
206             sub r454_start
207             {
208 16     16 1 5262 my $self = shift;
209 16         33 my %params = @_;
210              
211 16 100       50 my $asobj = (defined($params{as_obj}) ? $params{as_obj} : 0);
212              
213 16         61 my $r454start = $pkg->_454_start($self->r454_year);
214              
215 16 100       154 return ($asobj ? $r454start : "" . $r454start);
216             }
217              
218             sub r454_end
219             {
220 14     14 1 4603 my $self = shift;
221 14         35 my %params = @_;
222              
223 14 50       38 my $asobj = (defined($params{as_obj}) ? $params{as_obj} : 0);
224              
225 14         36 my $r454end =
226             $pkg->_454_start($self->r454_year + 1)->subtract(seconds => 1);
227              
228 14 50       1325 return ($asobj ? $r454end : "" . $r454end);
229             }
230              
231             sub r454_period
232             {
233 170     170 1 53005 my $self = shift;
234 170         514 my %params = @_;
235              
236 170 50       404 my $asobj = defined($params{as_obj}) ? $params{as_obj} : 0;
237 170 50 33     471 carp "objects requested in non-array context" if $asobj && !wantarray;
238              
239 170 100       380 my $pnum = defined($params{period}) ? 0 + $params{period} : 0;
240              
241 170         203 &{$_r454_build_periods}($self);
  170         351  
242              
243 170 100       2794 if (!$pnum) {
244 2         4 $pnum = 1;
245 2         11 while ($self->{_R454_periods}->{$pnum}->{pstart} < $self) {
246 16 100       2199 last if $self->{_R454_periods}->{$pnum + 1}->{pstart} > $self;
247 14 50       1957 last if ++$pnum == 12;
248             }
249             }
250 170 50 33     1035 croak "Invalid Period specified" unless $pnum > 0 && $pnum < 13;
251              
252 170 100       338 return ($pnum) unless wantarray;
253              
254 168         364 my $phash = $self->{_R454_periods}->{$pnum};
255             my @pdata = (
256             $pnum,
257             $phash->{weeks},
258             ($asobj ? $phash->{pstart}->clone : "" . $phash->{pstart}),
259             ($asobj ? $phash->{pend}->clone : "" . $phash->{pend}),
260             ($asobj ? $phash->{ppub}->clone : "" . $phash->{ppub}),
261             $phash->{r454year}
262 168 50       873 );
    50          
    50          
263              
264 168         10916 return (@pdata);
265             }
266              
267             sub r454_period_weeks
268             {
269 168     168 1 320939 my $self = shift;
270 168         482 my %params = @_;
271              
272             my $pnum =
273 168 50       449 defined($params{period}) ? 0 + $params{period} : $self->r454_period;
274 168 50 33     1074 croak "Invalid Period specified" unless $pnum > 0 && $pnum < 13;
275              
276 168         212 &{$_r454_build_periods}($self);
  168         573  
277              
278 168         3255 return ($self->{_R454_periods}->{$pnum}->{weeks});
279             }
280              
281             sub r454_period_start
282             {
283 170     170 1 61108 my $self = shift;
284 170         463 my %params = @_;
285              
286 170 100       383 my $asobj = defined($params{as_obj}) ? $params{as_obj} : 0;
287             my $pnum =
288 170 100       426 defined($params{period}) ? 0 + $params{period} : $self->r454_period;
289 170 50 33     834 croak "Invalid Period specified" unless $pnum > 0 && $pnum < 13;
290              
291 170         206 &{$_r454_build_periods}($self);
  170         360  
292 170         2903 my $pobj = $self->{_R454_periods}->{$pnum}->{pstart};
293              
294 170 100       921 return ($asobj ? $pobj : "" . $pobj);
295             }
296              
297             sub r454_period_end
298             {
299 168     168 1 69462 my $self = shift;
300 168         467 my %params = @_;
301              
302 168 50       385 my $asobj = defined($params{as_obj}) ? $params{as_obj} : 0;
303             my $pnum =
304 168 50       642 defined($params{period}) ? 0 + $params{period} : $self->r454_period;
305 168 50 33     976 croak "Invalid Period specified" unless $pnum > 0 && $pnum < 13;
306              
307 168         219 &{$_r454_build_periods}($self);
  168         363  
308 168         3547 my $pobj = $self->{_R454_periods}->{$pnum}->{pend}->clone;
309              
310 168 50       3716 return ($asobj ? $pobj : "" . $pobj);
311             }
312              
313             sub r454_period_publish
314             {
315 168     168 1 64729 my $self = shift;
316 168         444 my %params = @_;
317              
318 168 50       370 my $asobj = defined($params{as_obj}) ? $params{as_obj} : 0;
319             my $pnum =
320 168 50       356 defined($params{period}) ? 0 + $params{period} : $self->r454_period;
321 168 50 33     955 croak "Invalid Period specified" unless $pnum > 0 && $pnum < 13;
322              
323 168         225 &{$_r454_build_periods}($self);
  168         346  
324 168         2793 my $pobj = $self->{_R454_periods}->{$pnum}->{ppub}->clone;
325              
326 168 50       3310 return ($asobj ? $pobj : "" . $pobj);
327             }
328              
329             sub r454_period_month
330             {
331 12     12 1 4446 my $self = shift;
332 12         29 my %params = @_;
333              
334             my $pnum =
335 12 50       33 defined($params{period}) ? 0 + $params{period} : $self->r454_period;
336 12 50 33     56 croak "Invalid Period specified" unless $pnum > 0 && $pnum < 13;
337              
338 12         21 &{$_r454_build_periods}($self);
  12         25  
339              
340 12         236 return ($self->{_R454_periods}->{$pnum}->{month});
341             }
342              
343             sub truncate
344             {
345 208     208 1 2065 my $self = shift;
346 208         446 my %params = @_;
347              
348 208 100       857 if ($params{to} eq 'r454year') {
    100          
349 1         4 my $tmp = $self->r454_start(as_obj => 1);
350 1         2 %{$self} = %{$tmp};
  1         8  
  1         4  
351             } elsif ($params{to} eq 'period') {
352 1         4 my $tmp = $self->r454_period_start(as_obj => 1);
353 1         2 %{$self} = %{$tmp};
  1         79  
  1         3  
354             } else {
355 206         591 $self->SUPER::truncate(%params);
356             }
357              
358 208         3976 return ($self);
359             }
360              
361             1;
362              
363             __END__