File Coverage

blib/lib/Sort/Sub/by_date_in_text.pm
Criterion Covered Total %
statement 58 77 75.3
branch 18 32 56.2
condition 8 15 53.3
subroutine 11 14 78.5
pod 0 1 0.0
total 95 139 68.3


line stmt bran cond sub pod time code
1             package Sort::Sub::by_date_in_text;
2              
3             our $DATE = '2017-04-25'; # DATE
4             our $VERSION = '0.008'; # VERSION
5              
6 1     1   1839 use 5.010001;
  1         4  
7 1     1   5 use strict;
  1         2  
  1         22  
8 1     1   4 use warnings;
  1         2  
  1         27  
9              
10 1     1   675 use DateTime;
  1         417305  
  1         336  
11              
12             our $DATE_EXTRACT_MODULE = $ENV{PERL_DATE_EXTRACT_MODULE} // "Date::Extract";
13              
14             sub gen_sorter {
15 3     3 0 2059 my ($is_reverse, $is_ci) = @_;
16              
17 3         35 my $re_is_num = qr/\A
18             [+-]?
19             (?:\d+|\d*(?:\.\d*)?)
20             (?:[Ee][+-]?\d+)?
21             \z/x;
22              
23 3         9 my ($parser, $code_parse);
24 3         7 my $module = $DATE_EXTRACT_MODULE;
25 3 50       17 $module = "Date::Extract::$module" unless $module =~ /::/;
26 3 50       11 if ($module eq 'Date::Extract') {
    0          
    0          
    0          
27 3         561 require Date::Extract;
28 3         44202 $parser = Date::Extract->new();
29 3     42   83 $code_parse = sub { $parser->extract($_[0]) };
  42         173  
30             } elsif ($module eq 'Date::Extract::ID') {
31 0         0 require Date::Extract::ID;
32 0         0 $parser = Date::Extract::ID->new();
33 0     0   0 $code_parse = sub { $parser->extract($_[0]) };
  0         0  
34             } elsif ($module eq 'DateTime::Format::Alami::EN') {
35 0         0 require DateTime::Format::Alami::EN;
36 0         0 $parser = DateTime::Format::Alami::EN->new();
37 0     0   0 $code_parse = sub { my $h; eval { $h = $parser->parse_datetime($_[0]) }; $h };
  0         0  
  0         0  
  0         0  
  0         0  
38             } elsif ($module eq 'DateTime::Format::Alami::ID') {
39 0         0 require DateTime::Format::Alami::ID;
40 0         0 $parser = DateTime::Format::Alami::ID->new();
41 0     0   0 $code_parse = sub { my $h; eval { $h = $parser->parse_datetime($_[0]) }; $h };
  0         0  
  0         0  
  0         0  
  0         0  
42             } else {
43 0         0 die "Invalid date extract module '$module'";
44             }
45 1 50   1   9 eval "use $module"; die if $@;
  1     1   3  
  1     1   21  
  1         6  
  1         3  
  1         27  
  1         6  
  1         3  
  1         16  
  3         463  
  3         17  
46              
47             sub {
48 1     1   9 no strict 'refs';
  1         3  
  1         253  
49              
50 21     21   297 my $caller = caller();
51 21 50       80 my $a = @_ ? $_[0] : ${"$caller\::a"};
  21         110  
52 21 50       68 my $b = @_ ? $_[1] : ${"$caller\::b"};
  21         93  
53              
54 21         48 my $cmp;
55              
56             # XXX cache
57              
58 21         63 my $dt_a = $code_parse->($a);
59 21 50 33     404422 warn "Found date $dt_a in $a\n" if $ENV{DEBUG} && $dt_a;
60 21         83 my $dt_b = $code_parse->($b);
61 21 50 33     512122 warn "Found date $dt_b in $b\n" if $ENV{DEBUG} && $dt_b;
62              
63             {
64 21 100 100     61 if ($dt_a && $dt_b) {
  21 100 66     143  
    50 33        
65 12         1361 $cmp = DateTime->compare($dt_a, $dt_b);
66 12 100       1158 last if $cmp;
67             } elsif ($dt_a && !$dt_b) {
68 2         193 $cmp = -1;
69 2         5 last;
70             } elsif (!$dt_a && $dt_b) {
71 7         565 $cmp = 1;
72 7         15 last;
73             }
74              
75 3 100       15 if ($is_ci) {
76 2         11 $cmp = lc($a) cmp lc($b);
77             } else {
78 1         4 $cmp = $a cmp $b;
79             }
80             }
81              
82 21 100       228 $is_reverse ? -1*$cmp : $cmp;
83 3         31 };
84             }
85              
86             1;
87             # ABSTRACT: Sort by date found in text or (if no date is found) ascibetically
88              
89             __END__
90              
91             =pod
92              
93             =encoding UTF-8
94              
95             =head1 NAME
96              
97             Sort::Sub::by_date_in_text - Sort by date found in text or (if no date is found) ascibetically
98              
99             =head1 VERSION
100              
101             This document describes version 0.008 of Sort::Sub::by_date_in_text (from Perl distribution Sort-Sub-by_date_in_text), released on 2017-04-25.
102              
103             =head1 SYNOPSIS
104              
105             Generate sorter (accessed as variable) via L<Sort::Sub> import:
106              
107             use Sort::Sub '$by_date_in_text'; # use '$by_date_in_text<i>' for case-insensitive sorting, '$by_date_in_text<r>' for reverse sorting
108             my @sorted = sort $by_date_in_text ('item', ...);
109              
110             Generate sorter (accessed as subroutine):
111              
112             use Sort::Sub 'by_date_in_text<ir>';
113             my @sorted = sort {by_date_in_text} ('item', ...);
114              
115             Generate directly without Sort::Sub:
116              
117             use Sort::Sub::by_date_in_text;
118             my $sorter = Sort::Sub::by_date_in_text::gen_sorter(
119             ci => 1, # default 0, set 1 to sort case-insensitively
120             reverse => 1, # default 0, set 1 to sort in reverse order
121             );
122             my @sorted = sort $sorter ('item', ...);
123              
124             Use in shell/CLI with L<sortsub> (from L<App::sortsub>):
125              
126             % some-cmd | sortsub by_date_in_text
127             % some-cmd | sortsub by_date_in_text --ignore-case -r
128              
129             =head1 DESCRIPTION
130              
131             The generated sort routine will sort by date found in text (extracted using
132             L<Date::Extract>) or (f no date is found in text) ascibetically. Items that have
133             a date will sort before items that do not.
134              
135             =for Pod::Coverage ^(gen_sorter)$
136              
137             =head1 ENVIRONMENT
138              
139             =head2 DEBUG => bool
140              
141             If set to true, will print stuffs to stderr.
142              
143             =head2 PERL_DATE_EXTRACT_MODULE => str
144              
145             Can be set to L<Date::Extract>, L<Date::Extract::ID>, or
146             L<DateTime::Format::Alami::EN>, L<DateTime::Format::Alami::ID>.
147              
148             =head1 HOMEPAGE
149              
150             Please visit the project's homepage at L<https://metacpan.org/release/Sort-Sub-by_date_in_text>.
151              
152             =head1 SOURCE
153              
154             Source repository is at L<https://github.com/perlancar/perl-Sort-Sub-by_date_in_text>.
155              
156             =head1 BUGS
157              
158             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Sort-Sub-by_date_in_text>
159              
160             When submitting a bug or request, please include a test-file or a
161             patch to an existing test-file that illustrates the bug or desired
162             feature.
163              
164             =head1 SEE ALSO
165              
166             L<Sort::Sub>
167              
168             =head1 AUTHOR
169              
170             perlancar <perlancar@cpan.org>
171              
172             =head1 COPYRIGHT AND LICENSE
173              
174             This software is copyright (c) 2017, 2016 by perlancar@cpan.org.
175              
176             This is free software; you can redistribute it and/or modify it under
177             the same terms as the Perl 5 programming language system itself.
178              
179             =cut