File Coverage

lib/Mojolicious/Plugin/Human.pm
Criterion Covered Total %
statement 120 121 99.1
branch 28 46 60.8
condition 25 58 43.1
subroutine 22 22 100.0
pod 4 4 100.0
total 199 251 79.2


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Human;
2              
3 2     2   385491 use strict;
  2         28  
  2         206  
4 2     2   26 use warnings;
  2         14  
  2         156  
5 2     2   15 use utf8;
  2         3  
  2         304  
6 2     2   151 use 5.10.0;
  2         11  
  2         235  
7              
8 2     2   1762 use Mojo::Base 'Mojolicious::Plugin';
  2         11706  
  2         16  
9 2     2   2733 use Carp;
  2         5  
  2         100  
10              
11 2     2   2537 use DateTime;
  2         366317  
  2         41  
12 2     2   1650 use DateTime::Format::DateParse;
  2         15070  
  2         1508  
13              
14             our $VERSION = '0.7';
15              
16             =encoding utf-8
17              
18             =head1 NAME
19              
20             Mojolicious::Plugin::Human - Helpers to print values as human readable form.
21              
22             =head1 SYNOPSIS
23              
24             $self->plugin('Human', {
25              
26             # Set money parameters if you need
27             money_delim => ",",
28             money_digit => " ",
29              
30             # Or change date and time strings
31             datetime => '%d.%m.%Y %H:%M',
32             time => '%H:%M:%S',
33             date => '%d.%m.%Y',
34              
35             phone_country => 1,
36             phone_region => 123,
37             });
38              
39             =head1 DESCRIPTION
40              
41             You can use this module in Mojo template engine to make you users happy.
42              
43             =head1 CONFIGURATION
44              
45             =over
46              
47             =item money_delim
48              
49             Set format for human readable delimiter of money. Default: <.>
50              
51             =item money_digit
52              
53             Set format for human readable digits of money. Default: <,>
54              
55             =item datetime
56              
57             Set format for human readable date and time. Default: %F %H:%M
58              
59             =item time
60              
61             Set format for human readable time. Default: %H:%M:%S
62              
63             =item datetime
64              
65             Set format for human readable date. Default: %F
66              
67             =item phone_country
68              
69             Set country code for phones functions. Default: 7
70              
71             =item phone_region
72              
73             Set region code for phones functions. Default: 495
74              
75             =back
76              
77             =head1 DATE AND TIME HELPERS
78              
79             =head2 str2time
80              
81             Get string, return timestamp
82              
83             =head2 strftime
84              
85             Get string, return formatted string
86              
87             =head2 human_datetime
88              
89             Get string, return date and time string in human readable form.
90              
91             =head2 human_time
92              
93             Get string, return time string in human readable form.
94              
95             =head2 human_date
96              
97             Get string, return date string in human readable form.
98              
99             =head1 MONEY HELPERS
100              
101             =head2 human_money
102              
103             Get number, return money string in human readable form with levels.
104              
105             =head1 PHONE HELPERS
106              
107             =head2 human_phones
108              
109             Get srtring, return phones (if many) string in human readable form.
110              
111             =head2 flat_phone
112              
113             Get srtring, return flat phone string.
114              
115             =head1 TEXT HELPERS
116              
117             =head2 human_suffix $str, $count, $one, $two, $many
118              
119             Get word base form and add some of suffix ($one, $two, $many) depends of $count
120              
121             =head1 DISTANCE HELPERS
122              
123             =head2 human_distance
124              
125             Return distance, without fractional part if possible.
126              
127             =cut
128              
129             # Compiled regexp for placement level in the money functions
130             my $REGEXP_DIGIT = qr{^(-?\d+)(\d{3})};
131              
132             sub clean_phone($$$);
133             sub human_phone($$$);
134             sub date_parse($;$);
135              
136              
137             sub register {
138 1     1 1 18047 my ($self, $app, $conf) = @_;
139              
140             # Configuration
141 1   50     4 $conf ||= {};
142 1   50     8 $conf->{money_delim} //= '.';
143 1   50     9 $conf->{money_digit} //= ',';
144              
145 1   50     5 $conf->{datetime} //= '%F %H:%M';
146 1   50     8 $conf->{time} //= '%H:%M:%S';
147 1   50     6 $conf->{date} //= '%F';
148 1   50     5 $conf->{tz} //= 'local';
149              
150 1   50     5 $conf->{phone_country} //= 7;
151 1   50     6 $conf->{phone_region} //= 495;
152              
153             # Datetime
154              
155             $app->helper(str2time => sub {
156 1     1   53375 my ($self, $str, $tz) = @_;
157 1   33     13 my $datetime = date_parse( $str, $tz // $conf->{tz} );
158 1 50       5 return $str unless $datetime;
159 1         69 return $datetime->epoch;
160 1         11 });
161              
162             $app->helper(strftime => sub {
163 1     1   1138 my ($self, $format, $str, $tz) = @_;
164 1 50       5 return unless defined $str;
165 1   33     12 my $datetime = date_parse( $str, $tz // $conf->{tz} );
166 1 50       3 return $str unless $datetime;
167 1         45 return $datetime->strftime( $format );
168 1         72 });
169              
170             $app->helper(human_datetime => sub {
171 2     2   2153 my ($self, $str, $tz) = @_;
172 2   33     21 my $datetime = date_parse( $str, $tz // $conf->{tz} );
173 2 50       6 return $str unless $datetime;
174 2         69 return $datetime->strftime($conf->{datetime});
175 1         71 });
176              
177             $app->helper(human_time => sub {
178 2     2   1754 my ($self, $str, $tz) = @_;
179 2   33     17 my $datetime = date_parse( $str, $tz // $conf->{tz} );
180 2 50       6 return $str unless $datetime;
181 2         64 return $datetime->strftime($conf->{time});
182 1         87 });
183              
184             $app->helper(human_date => sub {
185 2     2   1701 my ($self, $str, $tz) = @_;
186 2   33     18 my $datetime = date_parse( $str, $tz // $conf->{tz} );
187 2 50       9 return $str unless $datetime;
188 2         109 return $datetime->strftime($conf->{date});
189 1         79 });
190              
191             # Money
192              
193             $app->helper(human_money => sub {
194 3     3   2387 my ($self, $str) = @_;
195 3 100 66     38 return $str if !defined($str) || !length($str);
196 1         5 my $delim = $conf->{money_delim};
197 1         4 my $digit = $conf->{money_digit};
198 1         24 $str = sprintf '%.2f', $str;
199 1         6 $str =~ s{\.}{$delim};
200 1         41 1 while $str =~ s{$REGEXP_DIGIT}{$1$digit$2};
201 1         10 return $str;
202 1         99 });
203              
204             # Phones
205              
206             $app->helper(human_phones => sub {
207 2     2   340 my ($self, $str) = @_;
208 2 50       12 return '' unless $str;
209 2         16 my @phones = split /[\s,;:]+/, $str;
210 3         25 return join ', ' => grep { $_ } map {
  3         17  
211 2         7 human_phone $_, $conf->{phone_country}, $conf->{phone_region}
212             } @phones;
213 1         67 });
214              
215             $app->helper(flat_phone => sub {
216 1     1   104 my ($self, $phone) = @_;
217 1   50     4 return clean_phone(
218             $phone, $conf->{phone_country}, $conf->{phone_region}
219             ) || '';
220 1         69 });
221              
222             # Text
223              
224             $app->helper(human_suffix => sub {
225 6     6   3476 my ($self, $str, $count, $one, $two, $many) = @_;
226              
227 6 50       20 return unless defined $str;
228 6 50       14 return $str unless defined $count;
229              
230             # Last digit
231 6         15 my $tail = abs( $count ) % 10;
232              
233             # Default suffix
234 6   33     15 $one //= $str;
235 6   33     16 $two //= $str . 'a';
236 6   33     12 $many //= $str . 'ов';
237              
238             # Get right suffix
239 6 100 66     40 my $result =
    100          
    100          
240             ( $tail == 0 ) ?$many :
241             ( $tail == 1 ) ?$one :
242             ( $tail >= 2 and $tail < 5 ) ?$two :$many;
243              
244             # For 10 - 20 get special suffix
245 6         9 $tail = abs( $count ) % 100;
246 6 50 33     20 $result =
247             ( $tail >= 10 and $tail < 21 ) ?$many :$result;
248              
249 6         43 return $result;
250 1         69 });
251              
252             # Distance
253              
254             $app->helper(human_distance => sub {
255 7     7   759 my ($self, $dist) = @_;
256 7         161 $dist = sprintf '%3.2f', $dist;
257 7         27 $dist =~ s{\.?0+$}{};
258 7         39 return $dist;
259 1         65 });
260             }
261              
262             =head1 INTERNAL FUNCIONS
263              
264             =head2 clean_phone $phone, $country, $region
265              
266             Clear phones. Fix first local digit 8 problem.
267              
268             Return if phome not correct
269              
270             =cut
271              
272             sub clean_phone($$$) {
273 4     4 1 9 my ($phone, $country, $region) = @_;
274 4 50       12 return undef unless $phone;
275 4         12 for ($phone) {
276 4         12 s/\D+//g;
277              
278 4 50       17 $_ = $region . $_ if 7 == length;
279              
280 4 50       12 return undef unless 10 <= length $phone;
281              
282 4 50       21 if (11 == length $_) { # have a country code
    50          
283 0         0 s/^8/$country/;
284             } elsif (10 == length $_) { # havn`t country code
285 4         23 s/^/$country/;
286             }
287              
288 4         23 s/^/+/;
289             }
290 4         19 return $phone;
291             }
292              
293             =head2 human_phone
294              
295             Make phone string in human readable form.
296              
297             =cut
298              
299             sub human_phone($$$) {
300 3     3 1 8 my ($phone, $country, $region) = @_;
301 3         13 $phone = clean_phone $phone, $country, $region;
302 3 50       11 return $phone unless $phone;
303 3         35 $phone =~ s/(...)(...)(....)$/-$1-$2-$3/;
304 3         15 return $phone;
305             }
306              
307             =head2 date_parse $str
308              
309             Get a string and return DateTime or undef.
310              
311             =cut
312              
313             sub date_parse($;$) {
314 8     8 1 17 my ($str, $tz) = @_;
315              
316 8 50       24 return unless $str;
317              
318 8   50     21 $tz //= 'local';
319              
320 8         13 my $dt = eval {
321 8 100       36 if( $str =~ m{^\d+$} ) {
322 3         20 DateTime->from_epoch( epoch => $str, time_zone => $tz );
323             } else {
324 5         50 DateTime::Format::DateParse->parse_datetime( $str, $tz );
325             }
326             };
327 8 50 33     77800 return if !$dt or $@;
328              
329 8         303 return $dt;
330             }
331              
332             1;
333              
334             =head1 AUTHORS
335              
336             Dmitry E. Oboukhov ,
337             Roman V. Nikolaev
338              
339             =head1 COPYRIGHT
340              
341             Copyright (C) 2011 Dmitry E. Oboukhov
342             Copyright (C) 2011 Roman V. Nikolaev
343              
344             This library is free software; you can redistribute it and/or modify
345             it under the same terms as Perl itself, either Perl version 5.8.8 or,
346             at your option, any later version of Perl 5 you may have available.
347              
348             =cut