File Coverage

lib/DateTimeX/Web.pm
Criterion Covered Total %
statement 170 175 97.1
branch 52 72 72.2
condition 14 21 66.6
subroutine 38 38 100.0
pod 18 18 100.0
total 292 324 90.1


line stmt bran cond sub pod time code
1             package DateTimeX::Web;
2              
3 11     11   232559 use strict;
  11         27  
  11         290  
4 11     11   53 use warnings;
  11         18  
  11         305  
5 11     11   53 use Carp;
  11         26  
  11         1059  
6              
7             our $VERSION = '0.07';
8              
9 11     11   13529 use DateTime;
  11         1633309  
  11         429  
10 11     11   106 use DateTime::Locale;
  11         19  
  11         199  
11 11     11   55 use DateTime::TimeZone;
  11         20  
  11         189  
12 11     11   10566 use DateTime::Format::Strptime;
  11         82493  
  11         635  
13 11     11   8874 use DateTime::Format::Mail;
  11         22454  
  11         375  
14 11     11   7884 use DateTime::Format::W3CDTF;
  11         7909  
  11         308  
15 11     11   7687 use DateTime::Format::MySQL;
  11         201436  
  11         393  
16 11     11   8106 use DateTime::Format::HTTP;
  11         60720  
  11         364  
17 11     11   79 use Scalar::Util qw( blessed );
  11         27  
  11         7447  
18              
19             sub _parse_options {
20 83     83   126 my $self = shift;
21              
22 83 100       293 if ( @_ == 1 ) {
23 7 100       27 return %{$_[0]} if ref $_[0] eq 'HASH';
  3         18  
24 4 100       12 return @{$_[0]} if ref $_[0] eq 'ARRAY';
  2         9  
25             }
26 78 100       485 croak "Odd number of elements in hash assignment" if @_ % 2;
27 76         279 return @_;
28             }
29              
30             sub new {
31 31     31 1 11342 my $class = shift;
32              
33 31         116 my %config = $class->_parse_options(@_);
34              
35 31   100     360 $config{on_error} ||= 'croak';
36              
37 31         254 my $self = bless {
38             config => \%config,
39             format => {
40             mail => DateTime::Format::Mail->new( loose => 1 ),
41             wwwc => DateTime::Format::W3CDTF->new,
42             mysql => DateTime::Format::MySQL->new,
43             http => 'DateTime::Format::HTTP', # ::HTTP has no 'new'
44             },
45             parser => {},
46             }, $class;
47              
48 31   100     3324 $self->time_zone( $config{time_zone} || delete $config{timezone} || 'UTC' );
49 31   100     204 $self->locale( $config{locale} || 'en-US' );
50              
51 31         80 $self;
52             }
53              
54             sub format {
55 43     43 1 741 my ($self, $name, $package) = @_;
56              
57 43 100       93 if ( $package ) {
58 5 100       11 if ( ref $package ) {
59 1         4 $self->{format}->{lc $name} = $package;
60             }
61             else {
62 4 100       17 unless ( $package =~ s/^\+// ) {
63 3         8 $package =~ s/^DateTime::Format:://;
64 3         6 $package = "DateTime::Format\::$package";
65             }
66 4         278 eval "require $package;";
67 4 50       132 croak $@ if $@;
68 4 100       45 $self->{format}->{lc $name} =
69             ( $package->can('new') ) ? $package->new : $package;
70             }
71             }
72 43         256 $self->{format}->{lc $name};
73             }
74              
75             sub time_zone {
76 49     49 1 12007 my ($self, $zone) = @_;
77              
78 49 100       131 if ( $zone ) {
79             $self->{config}->{time_zone} =
80 37 100 66     426 ( blessed $zone && $zone->isa('DateTime::TimeZone') )
81             ? $zone
82             : DateTime::TimeZone->new( name => $zone );
83             }
84 46         2065 $self->{config}->{time_zone};
85             }
86              
87             sub locale {
88 42     42 1 7904 my ($self, $locale) = @_;
89              
90 42 100       107 if ( $locale ) {
91             $self->{config}->{locale} =
92 36 100 66     382 ( blessed $locale && ($locale->isa('DateTime::Locale::root') || $locale->isa('DateTime::Locale::FromData') ) )
93             ? $locale
94             : DateTime::Locale->load( $locale );
95             }
96 39         694 $self->{config}->{locale};
97             }
98              
99             {
100             my @constructors = qw(now today last_day_of_month from_day_of_year);
101             for my $method (@constructors) {
102             my $code = sub {
103 13     13   3570 my $self = shift;
104              
105 13         44 my %options = $self->_parse_options(@_);
106              
107 13         44 $self->_merge_config( \%options );
108              
109 13         25 my $dt = eval { DateTime->$method( %options ) };
  13         87  
110 13 50       5160 $self->_error( $@ ) if $@;
111 13         40 return $dt;
112             };
113              
114 11     11   72 no strict 'refs';
  11         32  
  11         13729  
115             *{$method} = $code;
116             }
117             }
118              
119             sub from {
120 15     15 1 2766 my $self = shift;
121              
122 15         45 my %options = $self->_parse_options(@_);
123              
124 13 100       65 return $self->from_epoch( %options ) if $options{epoch};
125 8 100       33 return $self->from_object( %options ) if $options{object};
126              
127 7         23 $self->_merge_config( \%options );
128              
129 7         12 my $dt = eval { DateTime->new( %options ) };
  7         45  
130 7 50       1310 $self->_error( $@ ) if $@;
131 7         23 return $dt;
132             }
133              
134             sub from_epoch {
135 7     7 1 17 my $self = shift;
136 7         11 my $epoch = shift;
137 7 100       20 $epoch = shift if $epoch eq 'epoch';
138 7         22 my %options = $self->_parse_options(@_);
139              
140 7         18 $self->_merge_config( \%options );
141              
142 7         11 my $dt = eval { DateTime->from_epoch( epoch => $epoch, %options ) };
  7         43  
143 7 50       2006 $self->_error( $@ ) if $@;
144              
145 7         42 return $dt;
146             }
147              
148             sub from_object {
149 3     3 1 389 my $self = shift;
150 3         4 my $object = shift;
151 3 100       11 $object = shift if $object eq 'object';
152 3         55 my %options = $self->_parse_options(@_);
153              
154 3         8 $self->_merge_config( \%options );
155              
156 3         3 my $orig_time_zone;
157 3 50       9 if (my $time_zone = delete $options{time_zone}) {
158 3 50       83 if ($object->can('set_time_zone')) {
159 3         11 $orig_time_zone = $object->time_zone;
160 3         19 $object->set_time_zone($time_zone);
161             }
162             }
163              
164 3         22 my $dt = eval { DateTime->from_object( object => $object, %options ) };
  3         15  
165 3 50       866 $self->_error( $@ ) if $@;
166              
167 3 50       12 if ($orig_time_zone) {
168 3         8 $object->set_time_zone($orig_time_zone);
169             }
170              
171 3         23 return $dt;
172             }
173              
174 3     3 1 2962 sub from_rss { shift->parse_as( wwwc => @_ ); }
175 6     6 1 2759 sub from_mail { shift->parse_as( mail => @_ ); }
176 2     2 1 2595 sub from_mysql { shift->parse_as( mysql => @_ ); }
177 2     2 1 2548 sub from_http { shift->parse_as( http => @_ ); }
178              
179             *from_wwwc = \&from_rss;
180             *from_rss20 = \&from_mail;
181              
182             sub parse_as {
183 13     13 1 30 my ($self, $formatter, $string, @args) = @_;
184              
185 13         33 my %options = $self->_parse_options(@args);
186              
187 13         42 $self->_load( $formatter );
188              
189 13         19 my $dt = eval { $self->format($formatter)->parse_datetime( $string ) };
  13         31  
190 13 100       6638 if ( $@ ) {
191 4         20 $self->_error( $@ );
192             }
193             else {
194 9         37 $self->_merge_config( \%options );
195 9         30 $self->_set_config( $dt, \%options );
196 9         276 return $dt;
197             }
198             }
199              
200             sub parse {
201 1     1 1 7 my ($self, $pattern, $string, @args) = @_;
202              
203 1         3 my %options = $self->_parse_options(@args);
204              
205 1 50       6 unless ( $self->{parser}->{$pattern} ) {
206 1         5 $self->_merge_config( \%options );
207 1         3 $options{pattern} = $pattern;
208 1         11 my $parser = DateTime::Format::Strptime->new( %options );
209 1         352 $self->{parser}->{$pattern} = $parser;
210             }
211 1         3 my $dt = eval { $self->{parser}->{$pattern}->parse_datetime( $string ) };
  1         6  
212 1 50       819 if ( $@ ) {
213 0         0 $self->_error( $@ );
214             }
215             else {
216 1         4 $self->_set_config( $dt, \%options );
217 1         23 return $dt;
218             }
219             }
220              
221             *strptime = \&parse;
222              
223 1     1 1 250 sub for_rss { shift->render_as( wwwc => @_ ); }
224 1     1 1 294 sub for_mail { shift->render_as( mail => @_ ); }
225 1     1 1 306 sub for_mysql { shift->render_as( mysql => @_ ); }
226 1     1 1 245 sub for_http { shift->render_as( http => @_ ); }
227              
228             *for_wwwc = \&for_rss;
229             *for_rss20 = \&for_mail;
230              
231             sub render_as {
232 4     4 1 15 my ($self, $formatter, @args) = @_;
233              
234 4         13 $self->_load( $formatter );
235              
236 4         15 my $dt = $self->_datetime( @args );
237              
238 4         7 my $str = eval { $self->format($formatter)->format_datetime( $dt ) };
  4         13  
239 4 50       984 $self->_error( $@ ) if $@;
240 4         25 return $str;
241             }
242              
243             sub _merge_config {
244 40     40   77 my ($self, $options) = @_;
245              
246 40         83 foreach my $key (qw( time_zone locale )) {
247 80 50       224 next unless defined $self->{config}->{$key};
248 80 50       177 next if defined $options->{$key};
249 80         224 $options->{$key} = $self->{config}->{$key};
250             }
251             }
252              
253             sub _datetime {
254 7     7   1678 my $self = shift;
255              
256 7 50       29 return $self->now unless @_;
257 7 50 66     46 return $_[0] if @_ == 1 && blessed $_[0] && $_[0]->isa('DateTime');
      33        
258 7         29 return $self->from( @_ );
259             }
260              
261             sub _load {
262 17     17   29 my ($self, $formatter) = @_;
263              
264 17 50       42 unless ( $self->format($formatter) ) {
265 0         0 $self->format( $formatter => "DateTime::Format\::$formatter" );
266             }
267             }
268              
269             sub _set_config {
270 10     10   23 my ($self, $dt, $options) = @_;
271              
272 10   33     27 $options ||= $self->{config};
273              
274 10         23 foreach my $key (qw( time_zone locale )) {
275 20         967 my $func = "set_$key";
276 20 50       224 $dt->$func( $options->{$key} ) if $options->{$key};
277             }
278             }
279              
280             sub _error {
281 4     4   11 my ($self, $message) = @_;
282              
283 4         10 my $on_error = $self->{config}->{on_error};
284              
285 4 50       27 return if $on_error eq 'ignore';
286 0 0         return $on_error->( $message ) if ref $on_error eq 'CODE';
287              
288 0           local $Carp::CarpLevel = 1;
289 0           croak $message;
290             }
291              
292             1;
293              
294             __END__