File Coverage

blib/lib/DateTime/Fiscal/Retail454.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


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