File Coverage

blib/lib/DateTime/Format/Flexible/lang.pm
Criterion Covered Total %
statement 198 200 99.0
branch 78 100 78.0
condition 12 12 100.0
subroutine 18 18 100.0
pod 1 1 100.0
total 307 331 92.7


line stmt bran cond sub pod time code
1             package DateTime::Format::Flexible::lang;
2              
3 22     22   177 use strict;
  22         58  
  22         816  
4 22     22   161 use warnings;
  22         69  
  22         867  
5              
6 22     22   10808 use Module::Pluggable require => 1 , search_path => [__PACKAGE__];
  22         190534  
  22         187  
7 22     22   2072 use List::MoreUtils 'any';
  22         78  
  22         277  
8              
9             sub new
10             {
11 6355     6355 1 1564039 my ( $class , %params ) = @_;
12 6355         16088 my $self = bless \%params , $class;
13              
14 6355 100 100     18841 if ($self->{lang} and not ref($self->{lang}) eq 'ARRAY')
15             {
16 137         356 $self->{lang} = [$self->{lang}];
17             }
18              
19 6355         16188 return $self;
20             }
21              
22             sub _cleanup
23             {
24 3808     3808   8702 my ( $self , $date , $p ) = @_;
25 3808         12619 foreach my $plug ( $self->plugins )
26             {
27 11424 100       9090681 if ( $self->{lang} )
28             {
29 417         1659 my ( $lang ) = $plug =~ m{(\w{2}\z)}mx;
30 417 100   417   1656 if ( not any { $_ eq $lang } @{ $self->{lang} } )
  417         1258  
  417         1457  
31             {
32 278 50       691 printf( "# skipping %s\n", $plug ) if $ENV{DFF_DEBUG};
33 278         1109 next;
34             }
35             }
36 11146 50       23806 printf( "# not skipping %s\n", $plug ) if $ENV{DFF_DEBUG};
37              
38 11146 50       25224 printf( "# before math: %s\n", $date ) if $ENV{DFF_DEBUG};;
39 11146         24152 $date = $self->_do_math( $plug , $date );
40 11146 50       26991 printf( "# before string_dates: %s\n", $date ) if $ENV{DFF_DEBUG};;
41 11146         25994 $date = $self->_string_dates( $plug , $date );
42 11146 50       33066 printf( "# before fix_alpha_month: %s\n", $date ) if $ENV{DFF_DEBUG};;
43 11146         29452 ( $date , $p ) = $self->_fix_alpha_month( $plug , $date , $p );
44 11146 50       28848 printf( "# before remove_day_names: %s\n", $date ) if $ENV{DFF_DEBUG};;
45 11146         26475 $date = $self->_remove_day_names( $plug , $date );
46 11146 50       27740 printf( "# before fix_hours: %s\n", $date ) if $ENV{DFF_DEBUG};;
47 11146         26730 $date = $self->_fix_hours( $plug , $date );
48 11146 50       25853 printf( "# before remove_strings: %s\n", $date ) if $ENV{DFF_DEBUG};;
49 11146         23501 $date = $self->_remove_strings( $plug , $date );
50 11146 50       26455 printf( "# before locate_time: %s\n", $date ) if $ENV{DFF_DEBUG};;
51 11146         23043 $date = $self->_locate_time( $plug , $date );
52 11146 50       22092 printf( "# before fix_internal_tz: %s\n", $date ) if $ENV{DFF_DEBUG};;
53 11146         22863 ( $date , $p ) = $self->_fix_internal_tz( $plug , $date , $p );
54 11146 50       28443 printf( "# finished: %s\n", $date ) if $ENV{DFF_DEBUG};;
55             }
56 3808         13340 return ( $date , $p );
57             }
58              
59             sub _fix_internal_tz
60             {
61 11146     11146   23202 my ( $self , $plug , $date , $p ) = @_;
62 11146         26493 my %tzs = $plug->timezone_map;
63 11146         38470 while( my( $orig_tz , $new_tz ) = each ( %tzs ) )
64             {
65 93512 100       581014 if( $date =~ m{$orig_tz}mxi )
66             {
67 4         13 $p->{ time_zone } = $new_tz;
68 4         21 $date =~ s{$orig_tz}{}mxi;
69 4         24 return ( $date , $p );
70             }
71             }
72 11142         39399 return ( $date , $p );
73             }
74              
75             sub _do_math
76             {
77 11146     11146   21824 my ( $self , $plug , $date ) = @_;
78              
79 11146         64736 my %relative_strings = $plug->relative;
80 11146         33649 my %day_strings = $plug->days;
81 11146         44971 my %month_strings = $plug->months;
82              
83 11146         80740 my $instructions = {
84             ago => {direction => 'past', units => 1},
85             from => {direction => 'future', units => 1},
86             last => {direction => 'past'},
87             next => {direction => 'future'},
88             };
89              
90 11146         31358 foreach my $keyword (keys %relative_strings)
91             {
92 44584         70589 my $rx = $relative_strings{$keyword};
93              
94 44584 50       77962 next if not (exists $instructions->{$keyword});
95              
96 44584         62887 my $has_units = $instructions->{$keyword}->{units};
97 44584         60297 my $direction = $instructions->{$keyword}->{direction};
98              
99 44584 100       214402 if ( $date =~ m{$rx}mix )
100             {
101 101         478 $date =~ s{$rx}{}mx;
102 101 100       286 if ($has_units)
103             {
104 24         81 $date = $self->_set_units( $plug , $date, $direction );
105             }
106             else
107             {
108 77         224 foreach my $day (keys %day_strings)
109             {
110 539 100       4856 if ($date =~ m{$day}mix)
111             {
112 29         99 $date = $self->_set_day( $plug , $date , $day , $direction );
113 29         544 $date =~ s{$day}{}mx;
114             }
115             }
116 77         316 foreach my $month (keys %month_strings)
117             {
118 924 100       6842 if ($date =~ m{$month}mix)
119             {
120 48         168 $date = $self->_set_month( $plug , $date , $month , $direction );
121 48         736 $date =~ s{$month}{}mx;
122             }
123             }
124             }
125 101 50       373 printf("# after removing rx (%s): [%s]\n", $rx, $date) if $ENV{DFF_DEBUG};
126              
127 101         466 $date =~ s{$keyword}{}mx;
128 101         495 $date =~ s{\s+}{ }gm;
129 101         423 $date =~ s{\s+\z}{}gm;
130 101 50       382 printf("# after removing keyword (%s): [%s]\n", $keyword, $date) if $ENV{DFF_DEBUG};
131             }
132              
133             }
134              
135 11146         77522 return $date;
136             }
137              
138             sub _set_units
139             {
140 24     24   102 my ( $self , $plug , $date , $direction ) = @_;
141              
142 24         83 my %strings = $plug->math_strings;
143 24 100       164 if ( my ( $amount , $unit ) = $date =~ m{(\d+)\s+([^\s]+)}mx )
144             {
145 21 50       74 printf( "# %s => %s\n", $amount, $unit ) if $ENV{DFF_DEBUG};
146 21 50       58 if ( exists( $strings{$unit} ) )
147             {
148 21         104 my $base_dt = DateTime::Format::Flexible->base->clone;
149              
150 21 100       1286 if ( $direction eq 'past' )
151             {
152 13         63 $base_dt->subtract( $strings{$unit} => $amount );
153             }
154 21 100       16763 if ( $direction eq 'future' )
155             {
156 8         38 $base_dt->add( $strings{$unit} => $amount );
157             }
158 21         8808 $date =~ s{\s{0,}$amount\s+$unit\s{0,}}{}mx;
159              
160 21 50       101 if ($ENV{DFF_DEBUG})
161             {
162 0         0 printf("# found: %s\n", $strings{$unit}) ;
163 0         0 printf("# after removing amount, unit: [%s]\n", $date);
164             }
165              
166 21         73 $date = $base_dt->datetime . ' ' . $date;
167             }
168             }
169              
170 24         737 return $date;
171             }
172              
173             sub _set_day
174             {
175 29     29   76 my ( $self , $plug , $date , $day , $direction ) = @_;
176              
177 29         89 my %day_strings = $plug->days;
178              
179 29         200 my $base_dt = DateTime::Format::Flexible->base->clone;
180 29         597 my $dow = $base_dt->day_of_week;
181 29         122 my $date_dow = $day_strings{$day};
182 29 100       85 if ( $direction eq 'past' )
183             {
184 14         31 my $amount = $dow - $date_dow;
185 14 100       32 if ($amount < 1) {$amount = 7 + $amount}
  12         71  
186 14 50       35 printf("# subtracting %s days\n", $amount) if $ENV{DFF_DEBUG};
187              
188 14         45 my $ret = $base_dt->subtract( 'days' => $amount )->truncate( to => 'day' );
189 14         20325 $date = $ret->datetime . ' ' . $date;
190              
191             }
192 29 100       445 if ( $direction eq 'future' )
193             {
194 15         31 my $amount = $date_dow - $dow;
195 15 100       34 if ($amount < 1) {$amount = 7 + $amount}
  4         6  
196 15 50       39 printf("# adding %s days\n", $amount) if $ENV{DFF_DEBUG};
197              
198 15         48 my $ret = $base_dt->add( 'days' => $amount )->truncate( to => 'day' );
199 15         19670 $date = $ret->datetime . ' ' . $date;
200             }
201              
202              
203 29         585 return $date;
204             }
205              
206             sub _set_month
207             {
208 48     48   124 my ( $self , $plug , $date , $month , $direction ) = @_;
209              
210 48         149 my %month_strings = $plug->months;
211              
212 48         377 my $base_dt = DateTime::Format::Flexible->base->clone;
213 48         901 my $mon = $base_dt->month;
214 48         277 my $date_mon = $month_strings{$month};
215              
216 48 50       125 printf("# setting month to: %s\n", $date_mon) if $ENV{DFF_DEBUG};
217              
218 48         148 $base_dt->set_month($date_mon);
219 48 100 100     22754 if ($direction eq 'past' and $date_mon >= $mon)
220             {
221 15         48 $base_dt->set_year($base_dt->year - 1);
222             }
223 48 100 100     6924 if ($direction eq 'future' and $date_mon <= $mon)
224             {
225 11         33 $base_dt->set_year($base_dt->year + 1);
226             }
227 48         5187 $base_dt->truncate( to => 'month' );
228 48 50       12281 printf("# set year to: %s\n", $base_dt->year) if $ENV{DFF_DEBUG};
229              
230 48         124 $date = $base_dt->datetime . ' ' . $date;
231              
232 48         1872 return $date;
233             }
234              
235             sub _string_dates
236             {
237 11146     11146   22517 my ( $self , $plug , $date ) = @_;
238 11146         30945 my %strings = $plug->string_dates;
239 11146         43780 foreach my $key ( keys %strings )
240             {
241 96645 100       548968 if ( $date =~ m{\Q$key\E}mxi )
242             {
243 45         177 my $new_value = $strings{$key}->();
244 45         20052 $date =~ s{\Q$key\E}{$new_value}mix;
245             }
246             }
247              
248 11146         42311 my %day_numbers = $plug->day_numbers;
249 11146         107217 foreach my $key ( keys %day_numbers )
250             {
251 378547 100       2660870 if ( $date =~ m{$key}mxi )
252             {
253 8         25 my $new_value = $day_numbers{$key};
254 8         75 $date =~ s{$key}{n${new_value}n}mix;
255             }
256             }
257 11146         205969 return $date;
258             }
259              
260             # turn month names into month numbers with surrounding X
261             # Sep => X9X
262             sub _fix_alpha_month
263             {
264 11146     11146   27378 my ( $self , $plug , $date , $p ) = @_;
265 11146         33991 my %months = $plug->months;
266 11146         63827 while( my( $month_name , $month_number ) = each ( %months ) )
267             {
268 134531 100       3217364 if( $date =~ m{\b$month_name\b}mxi )
    100          
    100          
269             {
270 2408         6674 $p->{ month } = $month_number;
271 2408         18999 $date =~ s{\b$month_name\b}{X${month_number}X}mxi;
272              
273 2408         15105 return ( $date , $p );
274             }
275             elsif ( $date =~ m{\d$month_name}mxi )
276             {
277 11         30 $p->{ month } = $month_number;
278 11         446 $date =~ s{(\d)$month_name}{$1X${month_number}X}mxi;
279              
280 11         74 return ( $date , $p );
281             }
282              
283             elsif( $date =~ m{\b$month_name\d.*\b}mxi )
284             {
285 4         13 $p->{ month } = $month_number;
286 4         37 $date =~ s{\b$month_name(\d.*)\b}{X${month_number}X$1}mxi;
287              
288 4         24 return ( $date , $p );
289             }
290             }
291 8723         43914 return ( $date , $p );
292             }
293              
294             # remove any day names, we do not need them
295             sub _remove_day_names
296             {
297 11146     11146   21864 my ( $self , $plug , $date ) = @_;
298 11146         30189 my %days = $plug->days;
299 11146         47379 foreach my $day_name ( keys %days )
300             {
301             # if the day name is by itself, make it the upcoming day
302             # eg: monday = next monday
303 80975 100 100     1205258 if ( $date =~ m{\A$day_name\z}mx or
304             $date =~ m{$day_name\sat}mx )
305             {
306 16         74 my $dt = $self->{base}->clone->truncate( to => 'day' );
307 16 100       4683 if ( $days{$day_name} == $dt->dow )
    100          
308             {
309 2         13 my $str = $dt->ymd;
310 2         52 $date =~ s{$day_name}{$str};
311 2         17 return $date;
312             }
313             elsif ( $days{$day_name} > $dt->dow )
314             {
315 12         125 $dt->add( days => $days{$day_name} - $dt->dow );
316 12         12597 my $str = $dt->ymd;
317 12         368 $date =~ s{$day_name}{$str};
318 12         93 return $date;
319             }
320             else
321             {
322 2         22 $dt->add( days => $days{$day_name} - $dt->dow + 7 );
323 2         2091 my $str = $dt->ymd;
324 2         57 $date =~ s{$day_name}{$str};
325 2         17 return $date;
326             }
327             }
328             # otherwise, just strip it out
329 80959 100       613994 if ( $date =~ m{$day_name}mxi )
330             {
331 233         1421 $date =~ s{$day_name,?}{}gmix;
332 233         1022 return $date;
333             }
334             }
335 10897         42535 return $date;
336             }
337              
338             # fix noon and midnight, named hours
339             sub _fix_hours
340             {
341 11146     11146   22611 my ( $self , $plug , $date ) = @_;
342 11146         32583 my %hours = $plug->hours;
343 11146         33801 foreach my $hour ( keys %hours )
344             {
345 75112 100       400825 if ( $date =~ m{$hour}mxi )
346             {
347 34         97 my $realtime = $hours{ $hour };
348 34         91 $date =~ s{T[^\s]+}{};
349 34         215 $date =~ s{$hour}{${realtime}}gmix;
350 34         182 return $date;
351             }
352             }
353 11112         38516 return $date;
354             }
355              
356             sub _remove_strings
357             {
358 11146     11146   21210 my ( $self , $plug , $date ) = @_;
359 11146         27259 my @rs = $plug->remove_strings;
360 11146         21613 foreach my $rs ( @rs )
361             {
362 26100 100       108683 if ( $date =~ m{$rs}mxi )
363             {
364 162 50       470 printf( "# removing string: %s\n", $rs ) if $ENV{DFF_DEBUG};
365              
366 162         1113 $date =~ s{$rs}{ }gmix;
367             }
368             }
369 11146         27512 $date =~ s{\A\s+}{};
370 11146         23749 $date =~ s{\s+\z}{};
371              
372 11146         30646 return $date;
373             }
374              
375             sub _locate_time
376             {
377 11146     11146   20527 my ( $self , $plug , $date ) = @_;
378 11146         28317 $date = $plug->parse_time( $date );
379 11146         21829 return $date;
380             }
381              
382             1;
383              
384             __END__
385              
386             =encoding utf-8
387              
388             =head1 NAME
389              
390             DateTime::Format::Flexible::lang - base language module to handle plugins for DateTime::Format::Flexible.
391              
392             =head1 DESCRIPTION
393              
394             You should not need to use this module directly
395              
396             =head2 new
397              
398             Instantiate a new instance of this module.
399              
400             =head1 AUTHOR
401              
402             Tom Heady
403             CPAN ID: thinc
404             Punch, Inc.
405             cpan@punch.net
406             http://www.punch.net/
407              
408             =head1 COPYRIGHT & LICENSE
409              
410             Copyright 2011 Tom Heady.
411              
412             This program is free software; you can redistribute it and/or
413             modify it under the terms of either:
414              
415             =over 4
416              
417             =item * the GNU General Public License as published by the Free
418             Software Foundation; either version 1, or (at your option) any
419             later version, or
420              
421             =item * the Artistic License.
422              
423             =back
424              
425             =head1 SEE ALSO
426              
427             F<DateTime::Format::Flexible>
428              
429             =cut