File Coverage

blib/lib/Mail/Box/Search/Grep.pm
Criterion Covered Total %
statement 80 84 95.2
branch 27 46 58.7
condition 9 13 69.2
subroutine 16 18 88.8
pod 6 7 85.7
total 138 168 82.1


line stmt bran cond sub pod time code
1             # This code is part of Perl distribution Mail-Box version 4.01.
2             # The POD got stripped from this file by OODoc version 3.05.
3             # For contributors see file ChangeLog.
4              
5             # This software is copyright (c) 2001-2025 by Mark Overmeer.
6              
7             # This is free software; you can redistribute it and/or modify it under
8             # the same terms as the Perl 5 programming language system itself.
9             # SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
10              
11              
12             package Mail::Box::Search::Grep;{
13             our $VERSION = '4.01';
14             }
15              
16 2     2   4262 use parent 'Mail::Box::Search';
  2         4  
  2         17  
17              
18 2     2   94 use strict;
  2         4  
  2         33  
19 2     2   8 use warnings;
  2         4  
  2         96  
20              
21 2     2   7 use Log::Report 'mail-box', import => [ qw/__x error info/ ];
  2         4  
  2         10  
22              
23             #--------------------
24              
25             sub init($)
26 12     12 0 10526 { my ($self, $args) = @_;
27              
28 12 0 33     57 $args->{in} ||= ($args->{field} ? 'HEAD' : 'BODY');
29              
30 12   66     61 my $deliver = $args->{deliver} || $args->{details}; # details is old name
31             $args->{deliver}
32             = !defined $deliver ? undef
33             : ref $deliver eq 'CODE' ? $deliver
34 14     14   41 : $deliver eq 'PRINT' ? sub { $_[0]->printMatch($_[1]) }
35 504     504   1081 : ref $deliver eq 'ARRAY' ? sub { push @$deliver, $_[1] }
36 12 50       156 : $deliver;
    100          
    50          
    100          
37              
38 12         72 $self->SUPER::init($args);
39              
40 12         27 my $take = $args->{field};
41             $self->{MBSG_field_check}
42 3865     3865   17855 = !defined $take ? sub {1}
43 0     0   0 : !ref $take ? do {$take = lc $take; sub { $_[1] eq $take }}
  0         0  
  0         0  
44 0     0   0 : ref $take eq 'Regexp' ? sub { $_[1] =~ $take }
45 12 0       72 : ref $take eq 'CODE' ? $take
    0          
    0          
    50          
46             : error __x"unsupported field selector {take UNKNOWN}.", take => $take;
47              
48             my $match = $args->{match}
49 12 50       44 or error __x"grep requires a match pattern.";
50              
51             $self->{MBSG_match_check}
52 2251     2251   4070 = !ref $match ? sub { index("$_[1]", $match) >= $[ }
53 14939     14939   57102 : ref $match eq 'Regexp' ? sub { "$_[1]" =~ $match }
54 12 0       73 : ref $match eq 'CODE' ? $match
    50          
    100          
55             : error __x"unsupported match pattern {match UNKNOWN}.", match => $match;
56              
57 12         44 $self;
58             }
59              
60             sub search(@)
61 14     14 1 2912 { my ($self, $object, %args) = @_;
62 14         34 delete $self->{MBSG_last_printed};
63 14         61 $self->SUPER::search($object, %args);
64             }
65              
66             sub inHead(@)
67 231     231 1 2500 { my ($self, $part, $head, $args) = @_;
68              
69 231         539 my @details = (message => $part->toplevel, part => $part);
70 231         1322 my ($field_check, $match_check, $deliver) = @$self{ qw/MBSG_field_check MBSG_match_check MBS_deliver/ };
71              
72 231         299 my $matched = 0;
73             LINES:
74 231         617 foreach my $field ($head->orderedFields)
75 3865 100 66     104966 { $field_check->($head, $field->name) && $match_check->($head, $field) or next;
76 122         3164 $matched++;
77 122 50       232 $deliver or last LINES; # no deliver: only one match needed
78 122         530 $deliver->( {@details, field => $field} );
79             }
80              
81 231         5285 $matched;
82             }
83              
84             sub inBody(@)
85 326     326 1 897 { my ($self, $part, $body, $args) = @_;
86              
87 326         1187 my @details = (message => $part->toplevel, part => $part);
88 326         2180 my ($field_check, $match_check, $deliver) = @$self{ qw/MBSG_field_check MBSG_match_check MBS_deliver/ };
89              
90 326         496 my $matched = 0;
91 326         514 my $linenr = 0;
92              
93             LINES:
94 326         930 foreach my $line ($body->lines)
95 13325         21028 { $linenr++;
96 13325 100       19356 $match_check->($body, $line) or next;
97              
98 397         588 $matched++;
99 397 100       854 $deliver or last LINES; # no deliver: only one match needed
100 396         1771 $deliver->( +{ @details, linenr => $linenr, line => $line } );
101             }
102              
103 326         1717 $matched;
104             }
105              
106             #--------------------
107              
108             sub printMatch($;$)
109 14     14 1 22 { my $self = shift;
110 14 50       52 my ($out, $match) = @_==2 ? @_ : (select, shift);
111              
112             $match->{field}
113 14 100       70 ? $self->printMatchedHead($out, $match)
114             : $self->printMatchedBody($out, $match)
115             }
116              
117              
118             sub printMatchedHead($$)
119 5     5 1 26 { my ($self, $out, $match) = @_;
120 5         8 my $message = $match->{message};
121 5         11 my $msgnr = $message->seqnr;
122 5         10 my $folder = $message->folder->name;
123 5   100     11 my $lp = $self->{MBSG_last_printed} || '';
124              
125 5 100       14 unless($lp eq "$folder $msgnr") # match in new message
126 4         8 { my $subject = $message->subject;
127 4         163 $out->print("$folder, message $msgnr: $subject\n");
128 4         84 $self->{MBSG_last_printed} = "$folder $msgnr";
129             }
130              
131 5         19 my @lines = $match->{field}->string;
132 5 50       87 my $inpart = $match->{part}->isPart ? 'p ' : ' ';
133 5         17 $out->print($inpart, join $inpart, @lines);
134 5         78 $self;
135             }
136              
137              
138             sub printMatchedBody($$)
139 9     9 1 21 { my ($self, $out, $match) = @_;
140 9         22 my $message = $match->{message};
141 9         37 my $msgnr = $message->seqnr;
142 9         32 my $folder = $message->folder->name;
143 9   100     40 my $lp = $self->{MBSG_last_printed} || '';
144              
145 9 50       35 unless($lp eq "$folder $msgnr") # match in new message
146 9         50 { my $subject = $message->subject;
147 9         626 $out->print("$folder, message $msgnr: $subject\n");
148 9         286 $self->{MBSG_last_printed} = "$folder $msgnr";
149             }
150              
151 9 100       42 my $inpart = $match->{part}->isPart ? 'p ' : ' ';
152 9         64 $out->print(sprintf "$inpart %2d: %s", $match->{linenr}, $match->{line});
153 9         187 $self;
154             }
155              
156             1;