File Coverage

blib/lib/Sort/Sub.pm
Criterion Covered Total %
statement 46 46 100.0
branch 10 12 83.3
condition 4 4 100.0
subroutine 6 6 100.0
pod 1 1 100.0
total 67 69 97.1


line stmt bran cond sub pod time code
1             package Sort::Sub;
2              
3             our $AUTHORITY = 'cpan:PERLANCAR'; # AUTHORITY
4             our $DATE = '2020-02-28'; # DATE
5             our $DIST = 'Sort-Sub'; # DIST
6             our $VERSION = '0.117'; # VERSION
7              
8 14     14   679 use 5.010001;
  14         41  
9 14     14   65 use strict 'subs', 'vars';
  14         28  
  14         325  
10 14     14   57 use warnings;
  14         27  
  14         6699  
11              
12             our $re_spec = qr/\A(\$)?(\w+)(?:<(\w*)>)?\z/;
13              
14             our %argsopt_sortsub = (
15             sort_sub => {
16             summary => 'Name of a Sort::Sub::* module (without the prefix)',
17             schema => ['sortsub::spec*'],
18             },
19             sort_args => {
20             summary => 'Arguments to pass to the Sort::Sub::* routine',
21             schema => ['hash*', of=>'str*'],
22             },
23             );
24              
25             sub get_sorter {
26 37     37 1 1069 my ($spec, $args, $with_meta) = @_;
27              
28 37 50       373 my ($is_var, $name, $opts) = $spec =~ $re_spec
29             or die "Invalid sorter spec '$spec', please use: ".
30             '[$]NAME [ <OPTS> ]';
31 37         6546 require "Sort/Sub/$name.pm";
32 37   100     176 $opts //= "";
33 37         89 my $is_reverse = $opts =~ /r/;
34 37         72 my $is_ci = $opts =~ /i/;
35 37         46 my $gen_sorter = \&{"Sort::Sub::$name\::gen_sorter"};
  37         131  
36 37   100     148 my $sorter = $gen_sorter->($is_reverse, $is_ci, $args // {});
37 37 100       95 if ($with_meta) {
38 1         3 my $meta = {};
39 1         1 eval { $meta = &{"Sort::Sub::$name\::meta"}() };
  1         2  
  1         4  
40 1 50       3 warn if $@;
41 1         5 return ($sorter, $meta);
42             } else {
43 36         88 return $sorter;
44             }
45             }
46              
47             sub import {
48 35     35   893 my $class = shift;
49 35         68 my $caller = caller;
50              
51 35         57 my $i = -1;
52 35         47 while (1) {
53 70         101 $i++;
54 70 100       201 last if $i >= @_;
55 35         59 my $import = $_[$i];
56 35         56 my $args = {};
57 35 100       103 if (ref $_[$i+1] eq 'HASH') {
58 13         24 $args = $_[$i+1];
59 13         19 $i++;
60             }
61 35         139 my $sorter = get_sorter($import, $args);
62 35         251 my ($is_var, $name) = $import =~ $re_spec; # XXX double matching
63 35 100       100 if ($is_var) {
64 1         2 ${"$caller\::$name"} = \&$sorter;
  1         3  
65             } else {
66 14     14   100 no warnings 'redefine';
  14         30  
  14         1311  
67 34         56 *{"$caller\::$name"} = \&$sorter;
  34         289  
68             }
69             }
70             }
71              
72             1;
73             # ABSTRACT: Collection of sort subroutines
74              
75             __END__
76              
77             =pod
78              
79             =encoding UTF-8
80              
81             =head1 NAME
82              
83             Sort::Sub - Collection of sort subroutines
84              
85             =head1 VERSION
86              
87             This document describes version 0.117 of Sort::Sub (from Perl distribution Sort-Sub), released on 2020-02-28.
88              
89             =head1 SYNOPSIS
90              
91             use Sort::Sub qw($naturally);
92              
93             my @sorted = sort $naturally ('track1.mp3', 'track10.mp3', 'track2.mp3', 'track1b.mp3', 'track1a.mp3');
94             # => ('track1.mp3', 'track1a.mp3', 'track1b.mp3', 'track2.mp3', 'track10.mp3')
95              
96             Request as subroutine:
97              
98             use Sort::Sub qw(naturally);
99              
100             my @sorted = sort {naturally} (...);
101              
102             Request a reverse sort:
103              
104             use Sort::Sub qw($naturally<r>);
105              
106             my @sorted = sort $naturally (...);
107             # => ('track10.mp3', 'track2.mp3', 'track1b.mp3', 'track1a.mp3', 'track1.mp3')
108              
109             Request a case-insensitive sort:
110              
111             use Sort::Sub qw($naturally<i>);
112              
113             my @sorted = sort $naturally (...);
114              
115             Request a case-insensitive, reverse sort:
116              
117             use Sort::Sub qw($naturally<ir>);
118              
119             my @sorted = sort $naturally ('track2.mp3', 'Track1.mp3', 'Track10.mp3');
120             => ('Track10.mp3', 'track2.mp3', 'Track1.mp3')
121              
122             Pass arguments to sort generator routine:
123              
124             use Sort::Sub '$by_num_of_colons', {pattern=>':'};
125              
126             my @sorted = sort $by_num_of_colons ('a::','b:','c::::','d:::');
127             => ('b:','a::','d:::','c::::')
128              
129             Request a coderef directly, without using the import interface:
130              
131             use Sort::Sub;
132              
133             my $naturally = Sort::Sub::get_sorter('naturally');
134             my $naturally = Sort::Sub::get_sorter('$naturally');
135             my $rev_naturally = Sort::Sub::get_sorter('naturally<r>');
136              
137             =head1 DESCRIPTION
138              
139             L<Sort::Sub> and C<Sort::Sub::*> are a convenient packaging of any kind of
140             subroutine which you can use for C<sort()>.
141              
142             To use Sort::Sub, you import a list of:
143              
144             ["$"]NAME [ "<" [i][r] ">" ]
145              
146             Where NAME is actually searched under C<Sort::Sub::*> namespace. For example:
147              
148             naturally
149              
150             will attempt to load C<Sort::Sub::naturally> module and call its C<gen_sorter>
151             subroutine.
152              
153             You can either request a subroutine name like the above or a variable name (e.g.
154             C<$naturally>).
155              
156             After the name, you can add some options, enclosed with angle brackets C<< <>
157             >>. There are some known options, e.g. C<i> (for case-insensitive sort) or C<r>
158             (for reverse sort). Some examples:
159              
160             naturally<i>
161             naturally<r>
162             naturally<ri>
163              
164             =head1 GUIDELINES FOR WRITING A SORT::SUB::* MODULE
165              
166             The name should be in lowercase. It should be an adverb (e.g. C<naturally>) or a
167             phrase with words separated by underscore (C<_>) and the phrase begins with
168             C<by> (e.g. C<by_num_and_non_num_parts>).
169              
170             The module must contain a C<gen_sorter> subroutine. It will be called with:
171              
172             ($is_reverse, $is_ci, $args)
173              
174             Where C<$is_reserve> will be set to true if user requests a reverse sort,
175             C<$is_ci> will be set to true if user requests a case-insensitive sort. C<$args>
176             is hashref to pass additional arguments to the C<gen_sorter()> routine. The
177             subroutine should return a code reference.
178              
179             The module should also contain a C<meta> subroutine which returns a metadata
180             L<DefHash>. Known properties (keys) include: C<v> (currently at 1), C<summary>.
181             Other metadata properties will be added in the future.
182              
183             =head1 FUNCTIONS
184              
185             =head2 get_sorter
186              
187             Usage:
188              
189             my $coderef = Sort::Sub::get_sorter('SPEC' [ , \%args [ , $with_meta ] ]);
190              
191             Example:
192              
193             my $rev_naturally = Sort::Sub::get_sorter('naturally<r>');
194              
195             This is an alternative to using the import interface. This function is not
196             imported.
197              
198             If C<$with_meta> is set to true, will return this:
199              
200             ($sorter, $meta)
201              
202             instead of just the C<$sorter> subroutine.
203              
204             =head1 HOMEPAGE
205              
206             Please visit the project's homepage at L<https://metacpan.org/release/Sort-Sub>.
207              
208             =head1 SOURCE
209              
210             Source repository is at L<https://github.com/perlancar/perl-Sort-Sub>.
211              
212             =head1 BUGS
213              
214             Please report any bugs or feature requests on the bugtracker website L<https://rt.cpan.org/Public/Dist/Display.html?Name=Sort-Sub>
215              
216             When submitting a bug or request, please include a test-file or a
217             patch to an existing test-file that illustrates the bug or desired
218             feature.
219              
220             =head1 SEE ALSO
221              
222             Other additional C<Sort::Sub::*> not bundled in this distribution.
223              
224             Supporting CLI's: L<sortsub> (from L<App::sortsub>), L<sorted> (from
225             L<App::sorted>), CLI's from L<App::SortSubUtils>.
226              
227             =head1 AUTHOR
228              
229             perlancar <perlancar@cpan.org>
230              
231             =head1 COPYRIGHT AND LICENSE
232              
233             This software is copyright (c) 2020, 2019, 2018, 2016, 2015 by perlancar@cpan.org.
234              
235             This is free software; you can redistribute it and/or modify it under
236             the same terms as the Perl 5 programming language system itself.
237              
238             =cut