| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | package List::GroupBy; | 
| 2 | 3 |  |  | 3 |  | 170904 | use 5.010001; | 
|  | 3 |  |  |  |  | 36 |  | 
| 3 | 3 |  |  | 3 |  | 17 | use strict; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 72 |  | 
| 4 | 3 |  |  | 3 |  | 16 | use warnings; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 145 |  | 
| 5 |  |  |  |  |  |  |  | 
| 6 |  |  |  |  |  |  | our $VERSION = "0.03"; | 
| 7 |  |  |  |  |  |  |  | 
| 8 | 3 |  |  | 3 |  | 17 | use Exporter qw( import ); | 
|  | 3 |  |  |  |  | 11 |  | 
|  | 3 |  |  |  |  | 166 |  | 
| 9 |  |  |  |  |  |  |  | 
| 10 |  |  |  |  |  |  | our @EXPORT_OK = qw( groupBy ); | 
| 11 |  |  |  |  |  |  |  | 
| 12 | 3 |  |  | 3 |  | 18 | use Carp; | 
|  | 3 |  |  |  |  | 6 |  | 
|  | 3 |  |  |  |  | 1327 |  | 
| 13 |  |  |  |  |  |  |  | 
| 14 |  |  |  |  |  |  | my $nop = sub { $_[0] }; | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | sub groupBy { | 
| 17 | 18 |  |  | 18 | 1 | 141769 | my ( $options, @list ) = @_; | 
| 18 |  |  |  |  |  |  |  | 
| 19 | 18 | 100 |  |  |  | 65 | $options = ref $options eq "ARRAY" ? { keys => $options } : $options; | 
| 20 |  |  |  |  |  |  |  | 
| 21 | 18 | 100 |  |  |  | 125 | croak "missing grouping keys" unless ref $options->{keys} eq "ARRAY"; | 
| 22 |  |  |  |  |  |  |  | 
| 23 | 14 |  |  |  |  | 23 | my @keys = @{ $options->{keys} }; | 
|  | 14 |  |  |  |  | 49 |  | 
| 24 |  |  |  |  |  |  |  | 
| 25 | 14 |  | 100 |  |  | 61 | my $default = $options->{defaults} // {}; | 
| 26 |  |  |  |  |  |  |  | 
| 27 | 14 | 100 |  |  |  | 61 | croak "defaults should be a hashref" unless ref $default eq "HASH"; | 
| 28 |  |  |  |  |  |  |  | 
| 29 | 12 |  | 100 |  |  | 42 | $options->{operations} //= {}; | 
| 30 |  |  |  |  |  |  |  | 
| 31 | 12 | 100 |  |  |  | 62 | croak "operations should be a hashref" unless ref $options->{operations} eq "HASH"; | 
| 32 |  |  |  |  |  |  |  | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | my %op = map { | 
| 35 | 10 |  | 66 |  |  | 25 | my $operation = $options->{operations}->{ $_ } // $nop; | 
|  | 18 |  |  |  |  | 59 |  | 
| 36 |  |  |  |  |  |  |  | 
| 37 | 18 | 100 |  |  |  | 59 | croak "operation defined should be an anonymous sub" unless ref $operation eq "CODE"; | 
| 38 |  |  |  |  |  |  |  | 
| 39 | 16 |  |  |  |  | 50 | $_ => $operation; | 
| 40 |  |  |  |  |  |  | } @keys; | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  |  | 
| 43 | 8 |  |  |  |  | 19 | my $groupings = {}; | 
| 44 |  |  |  |  |  |  |  | 
| 45 | 8 |  |  |  |  | 17 | my $leaf = pop @keys; | 
| 46 |  |  |  |  |  |  |  | 
| 47 | 8 |  |  |  |  | 29 | foreach my $item (@list) { | 
| 48 | 40 |  |  |  |  | 89 | my $current = $groupings; | 
| 49 |  |  |  |  |  |  |  | 
| 50 | 40 |  |  |  |  | 72 | foreach my $key ( @keys ) { | 
| 51 | 40 |  | 100 |  |  | 169 | my $branch = $op{ $key }->( $item->{ $key } // $default->{ $key } // '' ); | 
|  |  |  | 100 |  |  |  |  | 
| 52 |  |  |  |  |  |  |  | 
| 53 | 40 |  | 100 |  |  | 146 | $current = $current->{ $branch } //= {}; | 
| 54 |  |  |  |  |  |  | } | 
| 55 |  |  |  |  |  |  |  | 
| 56 | 40 |  | 66 |  |  | 123 | my $leafNode = $op{ $leaf }->( $item->{$leaf} // $default->{ $leaf } // '' ); | 
|  |  |  | 50 |  |  |  |  | 
| 57 | 40 |  |  |  |  | 51 | push @{ $current->{ $leafNode } }, $item; | 
|  | 40 |  |  |  |  | 97 |  | 
| 58 |  |  |  |  |  |  | } | 
| 59 |  |  |  |  |  |  |  | 
| 60 | 8 | 100 |  |  |  | 61 | return wantarray ? %$groupings : $groupings; | 
| 61 |  |  |  |  |  |  | } | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  |  | 
| 64 |  |  |  |  |  |  | 1; | 
| 65 |  |  |  |  |  |  | __END__ |