File Coverage

blib/lib/Mail/Colander/Message.pm
Criterion Covered Total %
statement 20 82 24.3
branch 0 6 0.0
condition 0 7 0.0
subroutine 7 18 38.8
pod 4 4 100.0
total 31 117 26.5


line stmt bran cond sub pod time code
1             package Mail::Colander::Message;
2 1     1   14 use v5.24;
  1         4  
3 1     1   6 use Moo;
  1         1  
  1         8  
4 1     1   496 use experimental qw< signatures >;
  1         2  
  1         7  
5             { our $VERSION = '0.004' }
6              
7 1     1   990 use Email::Address::XS qw< parse_email_addresses >;
  1         3622  
  1         83  
8 1     1   9 use Scalar::Util qw< blessed >;
  1         1  
  1         60  
9 1     1   6 use Ouch qw< :trytiny_var >;
  1         2  
  1         9  
10              
11             sub coerce_entity ($input) {
12            
13             # allow for getting another Mail::Colander::Message object to be passed
14             # as entity, just go to its inner entity in this case
15             if (my $class = blessed($input)) {
16             return $input->entity if $class eq __PACKAGE__;
17             return $input;
18             }
19              
20             # not blessed, consider this as a message to be parsed
21             require MIME::Parser;
22             my $parser = MIME::Parser->new;
23             $parser->output_to_core(1);
24             return $parser->parse_data($input);
25              
26             }
27              
28             sub expand_addresses ($addrs) {
29             [ map { $_->address } map { parse_email_addresses($_) } $addrs->@* ];
30             }
31              
32             sub trim ($string) { $string =~ s{\A\s+|\s+\z}{}rgmxs }
33              
34 1     1   504 use namespace::clean;
  1         3  
  1         11  
35              
36             has entity => (is => 'ro', coerce => \&coerce_entity);
37              
38             # the cache is for memoizing tamed addresses
39             has cache_for => (is => 'ro', default => sub { return {} });
40              
41             has $_ => (is => 'lazy', init_arg => undef)
42             for qw< from to cc bcc recipients subject >;
43              
44 0     0     sub _build_to ($self) { $self->bare_addresses('to') }
  0            
  0            
  0            
45 0     0     sub _build_cc ($self) { $self->bare_addresses('cc') }
  0            
  0            
  0            
46 0     0     sub _build_bcc ($self) { $self->bare_addresses('bcc') }
  0            
  0            
  0            
47 0     0     sub _build_recipients ($self) { $self->bare_addresses(qw< to cc bcc >) }
  0            
  0            
  0            
48 0     0     sub _build_from ($self) { trim($self->entity->head->get(from => 0)) }
  0            
  0            
  0            
49 0     0     sub _build_subject ($self) { $self->entity->head->get(subject => 0) }
  0            
  0            
  0            
50              
51 0     0 1   sub header_all ($self, $key) {
  0            
  0            
  0            
52 0   0       $self->cache_for->{headers}{$key}
53             //= [ $self->entity->head->get_all($key) ];
54             }
55              
56 0     0 1   sub header_first ($self, $key) {
  0            
  0            
  0            
57 0           my $all = $self->header_all($key);
58 0 0         return $all->@* ? $all->[0] : undef;
59             }
60              
61 0     0 1   sub bare_addresses ($self, @types) {
  0            
  0            
  0            
62 0   0       my $af = $self->cache_for->{bare_addresses} //= {};
63 0     0     my $cache_fetcher = sub ($type) {
  0            
  0            
64 0   0       return $af->{$type} //= do {
65 0           my %seen;
66             [
67 0           grep { ! $seen{$_}++ }
68 0           map { $_->address }
69 0           map { parse_email_addresses($_) }
  0            
70             $self->entity->head->get_all($type)
71             ];
72             };
73 0           };
74              
75 0           my (@list, %seen_type, %seen_address);
76 0 0         for (map { $_ eq 'recipients' ? qw< from cc bcc > : $_ } @types) {
  0            
77 0 0         next if $seen_type{$_}++; # don't bother
78 0           push @list, grep { ! $seen_address{$_} } $cache_fetcher->($_)->@*;
  0            
79             }
80 0           return \@list;
81             }
82              
83 0     0 1   sub create ($package, $entity) { $package->new(entity => $entity) }
  0            
  0            
  0            
  0            
84              
85             1;