File Coverage

blib/lib/Minilla/Metadata.pm
Criterion Covered Total %
statement 30 113 26.5
branch 0 42 0.0
condition 0 6 0.0
subroutine 10 19 52.6
pod n/a
total 40 180 22.2


line stmt bran cond sub pod time code
1             package Minilla::Metadata;
2 1     1   8 use strict;
  1         1  
  1         30  
3 1     1   5 use warnings;
  1         2  
  1         23  
4 1     1   5 use utf8;
  1         2  
  1         6  
5 1     1   26 use Minilla::Util qw(slurp slurp_utf8 require_optional);
  1         2  
  1         66  
6 1     1   7 use Carp;
  1         2  
  1         57  
7 1     1   595 use Module::Metadata;
  1         5916  
  1         37  
8 1     1   463 use Minilla::License::Perl_5;
  1         3  
  1         31  
9 1     1   470 use Pod::Escapes;
  1         3392  
  1         64  
10              
11 1     1   7 use Moo;
  1         3  
  1         5  
12              
13             has [qw(abstract perl_version authors license)] => (
14             is => 'lazy',
15             );
16              
17             has '_license_name' => (
18             is => 'ro',
19             );
20              
21             has metadata => (
22             is => 'lazy',
23             handles => [qw(name version)],
24             );
25              
26             has source => (
27             is => 'rw',
28             isa => sub {
29             defined $_[0] or Carp::confess("source should not be undef");
30             -f $_[0] or Carp::confess("source file not found: '$_[0]'");
31             },
32             required => 1,
33             );
34              
35 1     1   422 no Moo;
  1         3  
  1         5  
36              
37             sub _build_metadata {
38 0     0     my $self = shift;
39 0           Module::Metadata->new_from_file($self->source, collect_pod => 1);
40             }
41              
42             # Taken from Module::Install::Metadata
43             sub _build_abstract {
44 0     0     my ($self) = @_;
45              
46             # find by EU::MM
47             {
48 0           require ExtUtils::MM_Unix;
49 0           my $abstract = bless( { DISTNAME => $self->name }, 'ExtUtils::MM_Unix' )->parse_abstract($self->source);
50 0 0         return $abstract if $abstract;
51             }
52             # Parsing pod with Module::Metadata
53             {
54 0           my $name = $self->metadata->pod('NAME');
  0            
55 0 0         if (defined $name) {
56 0           $name =~ s/^\s+//gxsm;
57 0           $name =~ s/\s+$//gxsm;
58 0           my ($pkg, $abstract) = split /\s+-\s+/, $name, 2;
59 0 0         return $abstract if $abstract;
60             }
61             }
62             # find dzil style '# ABSTRACT: '
63             {
64 0 0         if (slurp($self->source) =~ /^\s*#+\s*ABSTRACT:\s*(.+)$/m) {
  0            
  0            
65 0           return $1;
66             }
67             }
68 0           return;
69             }
70              
71             sub _extract_perl_version {
72 0 0   0     if (
73             $_[0] =~ m/
74             ^\s*
75             (?:use|require) \s*
76             (v?[\d_\.]+)
77             \s* ;
78             /ixms
79             ) {
80 0           my $perl_version = $1;
81 0           $perl_version =~ s{_}{}g;
82 0           return $perl_version;
83             } else {
84 0           return;
85             }
86             }
87              
88             sub _build_perl_version {
89 0     0     my ($self) = @_;
90              
91 0           my $perl_version = _extract_perl_version(slurp($self->source));
92 0 0         if ($perl_version) {
93 0           return $perl_version;
94             } else {
95 0           return;
96             }
97             }
98              
99             sub _build_authors {
100 0     0     my ($self) = @_;
101              
102 0           my $content = slurp_utf8($self->source);
103 0 0 0       if ($content =~ m/
104             ^=head1 \s+ (?:authors?)\b \s*
105             ([^\n]+)
106             /ixm || $content =~ m/
107             ^=head \d \s+ (?:licen[cs]e|licensing|copyright|legal)\b \s*
108             .*? copyright .*? \d\d\d[\d.]+ \s* (?:\bby\b)? \s*
109             ([^\n]+)
110             /ixms) {
111 0           my $author = $1;
112              
113 0           $author =~ s{ E<( (\d+) | ([A-Za-z]+) )> }{
114             defined $2
115             ? chr($2)
116             : defined $Pod::Escapes::Name2character_number{$1}
117             ? chr($Pod::Escapes::Name2character_number{$1})
118 0 0         : do {
    0          
119 0           warn "Unknown escape: E<$1>";
120 0           "E<$1>";
121             };
122             }gex;
123              
124 0           my @authors;
125 0           for (split /\n/, $author) {
126 0           chomp;
127 0 0         next unless /\S/;
128 0           push @authors, $_;
129             }
130 0           return \@authors;
131             } else {
132 0           warn "Cannot determine author info from @{[ $_[0]->source ]}\n";
  0            
133 0           return undef;
134             }
135             }
136              
137              
138             #Stolen from M::B
139             sub _is_perl5_license {
140 0     0     my $pod = shift;
141 0           my $matched;
142 0   0       return __extract_license(
143             ($matched) = $pod =~ m/
144             (=head \d \s+ L(?i:ICEN[CS]E|ICENSING)\b.*?)
145             (=head \d.*|=cut.*|)\z
146             /xms
147             ) || __extract_license(
148             ($matched) = $pod =~ m/
149             (=head \d \s+ (?:C(?i:OPYRIGHTS?)|L(?i:EGAL))\b.*?)
150             (=head \d.*|=cut.*|)\z
151             /xms
152             );
153             }
154              
155             sub __extract_license {
156 0 0   0     my $license_text = shift or return;
157 0           my @phrases = (
158             '(?:under )?the same (?:terms|license) as (?:perl|the perl (?:\d )?programming language)',
159             '(?:under )?the terms of (?:perl|the perl programming language) itself',
160             'Artistic and GPL'
161             );
162 0           for my $pattern (@phrases) {
163 0           $pattern =~ s#\s+#\\s+#gs;
164 0 0         if ( $license_text =~ /\b$pattern\b/i ) {
165 0           return 1;
166             }
167             }
168 0           return 0;
169             }
170              
171             sub _guess_license_class_by_name {
172 0     0     my ($name) = @_;
173              
174 0 0         if ($name eq 'Perl_5') {
175 0           return 'Minilla::License::Perl_5'
176             } else {
177 0           my %license_map = (
178             'agpl_3' => 'Software::License::AGPL_3',
179             'apache_1_1' => 'Software::License::Apache_1_1',
180             'apache_2_0' => 'Software::License::Apache_2_0',
181             'artistic_1' => 'Software::License::Artistic_1_0',
182             'artistic_2' => 'Software::License::Artistic_2_0',
183             'bsd' => 'Software::License::BSD',
184             'unrestricted' => 'Software::License::CC0_1_0',
185             'custom' => 'Software::License::Custom',
186             'freebsd' => 'Software::License::FreeBSD',
187             'gfdl_1_2' => 'Software::License::GFDL_1_2',
188             'gfdl_1_3' => 'Software::License::GFDL_1_3',
189             'gpl_1' => 'Software::License::GPL_1',
190             'gpl_2' => 'Software::License::GPL_2',
191             'gpl_3' => 'Software::License::GPL_3',
192             'lgpl_2_1' => 'Software::License::LGPL_2_1',
193             'lgpl_3_0' => 'Software::License::LGPL_3_0',
194             'mit' => 'Software::License::MIT',
195             'mozilla_1_0' => 'Software::License::Mozilla_1_0',
196             'mozilla_1_1' => 'Software::License::Mozilla_1_1',
197             'open_source' => 'Software::License::Mozilla_2_0',
198             'restricted' => 'Software::License::None',
199             'openssl' => 'Software::License::OpenSSL',
200             'perl_5' => 'Software::License::Perl_5',
201             'open_source' => 'Software::License::PostgreSQL',
202             'qpl_1_0' => 'Software::License::QPL_1_0',
203             'ssleay' => 'Software::License::SSLeay',
204             'sun' => 'Software::License::Sun',
205             'zlib' => 'Software::License::Zlib',
206             );
207 0 0         if (my $klass = $license_map{lc $name}) {
208 0 0         eval "require $klass; 1" or die "$klass is required for supporting $name license. But: $@"; ## no critic.
209 0           return $klass;
210             } else {
211 0           die "'$name' is not supported yet. Supported licenses are: " . join(', ', keys %license_map);
212             }
213             }
214             }
215              
216             sub _build_license {
217 0     0     my ($self) = @_;
218              
219 0           my $pm_text = slurp($self->source);
220 0 0         my $holder = $self->authors ? $self->authors->[0] : 'Unknown';
221 0 0         if ($self->_license_name) {
    0          
222 0           _guess_license_class_by_name($self->_license_name)->new({
223             holder => $holder,
224             });
225             } elsif (_is_perl5_license($pm_text)) {
226 0           require Minilla::License::Perl_5;
227 0           return Minilla::License::Perl_5->new({
228             holder => $holder,
229             });
230             } else {
231 0 0         if (eval "require Software::LicenseUtils; 1") {
232 0           my (@guesses) = Software::LicenseUtils->guess_license_from_pod($pm_text);
233 0 0         if (@guesses) {
234 0           my $klass = $guesses[0];
235 0 0         eval "require $klass; 1" or die $@; ## no critic.
236 0           $klass->new({
237             holder => $holder,
238             });
239             } else {
240 0           warn "Cannot determine license info from @{[ $_[0]->source ]}\n";
  0            
241 0           require Minilla::License::Unknown;
242 0           return Minilla::License::Unknown->new({
243             holder => $holder,
244             });
245             }
246             } else {
247 0           warn "Software::License is needed when you want to use non Perl_5 license.\n";
248 0           require Minilla::License::Unknown;
249 0           return Minilla::License::Unknown->new({
250             holder => $holder,
251             });
252             }
253             }
254             }
255              
256             1;
257