File Coverage

blib/lib/Pod/Weaver/Section/Legal/Complicated.pm
Criterion Covered Total %
statement 78 79 98.7
branch 12 18 66.6
condition 3 6 50.0
subroutine 14 14 100.0
pod 0 1 0.0
total 107 118 90.6


line stmt bran cond sub pod time code
1             package Pod::Weaver::Section::Legal::Complicated;
2             $Pod::Weaver::Section::Legal::Complicated::VERSION = '1.23';
3 1     1   7259 use utf8;
  1         2  
  1         6  
4             ## Copyright (C) 2013-2017 Carnë Draug <carandraug+dev@gmail.com>
5             ##
6             ## This program is free software; you can redistribute it and/or modify
7             ## it under the terms of the GNU General Public License as published by
8             ## the Free Software Foundation; either version 3 of the License, or
9             ## (at your option) any later version.
10             ##
11             ## This program is distributed in the hope that it will be useful,
12             ## but WITHOUT ANY WARRANTY; without even the implied warranty of
13             ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14             ## GNU General Public License for more details.
15             ##
16             ## You should have received a copy of the GNU General Public License
17             ## along with this program; if not, see <http://www.gnu.org/licenses/>.
18              
19             # ABSTRACT: Different authors, copyright holders, and licenses for each module.
20             # AUTHOR: Carnë Draug <cdraug@cpan.org>
21             # OWNER: Carnë Draug
22             # LICENSE: GPL_3
23              
24 1     1   32 use strict;
  1         1  
  1         18  
25 1     1   4 use warnings;
  1         1  
  1         31  
26 1     1   430 use Module::Load;
  1         885  
  1         5  
27 1     1   39 use Moose;
  1         1  
  1         7  
28 1     1   4628 use MooseX::Types::Moose qw(Bool Int);
  1         1  
  1         17  
29 1     1   3235 use List::MoreUtils qw(uniq);
  1         1  
  1         21  
30 1     1   974 use Pod::Elemental::Element::Nested;
  1         37810  
  1         36  
31 1     1   7 use Pod::Elemental::Element::Pod5::Ordinary;
  1         1  
  1         37  
32             with (
33             'Pod::Weaver::Role::Section',
34             );
35 1     1   4 use namespace::autoclean;
  1         2  
  1         5  
36              
37              
38              
39             has add_dist_license => (
40             is => 'ro',
41             isa => Bool,
42             lazy => 1,
43             default => 0,
44             );
45              
46              
47             has head => (
48             is => 'ro',
49             isa => Int,
50             lazy => 1,
51             default => 1,
52             );
53              
54              
55             sub _extract_comments {
56 18     18   28 my (undef, $input, $tag) = @_;
57 18         17 my $ppi_document = $input->{ppi_document};
58              
59 18         13 my @comments;
60             $ppi_document->find( sub {
61 96     96   562 my $ppi_node = $_[1];
62 96 100 66     251 if ($ppi_node->isa('PPI::Token::Comment') &&
63             $ppi_node->content =~ qr/^\s*#+\s*$tag:\s*(.+?)\s*$/m ) {
64 32         457 push (@comments, $1);
65             }
66 96         606 return 0;
67 18         77 });
68 18         164 return @comments;
69             }
70              
71              
72             sub _join {
73 12     12   10 my $text;
74 12 100       19 if (@_ == 1) {
75 5         6 $text = $_[0];
76             } else {
77 7         17 $text = join (", ", @_[0 .. $#_ -1]);
78 7         13 $text .= ", and $_[-1]";
79             }
80 12         29 return $text;
81             }
82              
83              
84             sub weave_section {
85 6     6 0 6902 my ($self, $document, $input) = @_;
86 6         7 my $filename = $input->{filename};
87              
88 6         20 my @authors = $self->_extract_comments($input, "AUTHOR");
89 6         13 my @owners = $self->_extract_comments($input, "OWNER");
90 6         11 my @licenses = $self->_extract_comments($input, "LICENSE");
91              
92             @licenses = map {
93 6         8 my $license = "Software::License::$_";
  9         17  
94 9         8 eval {
95 9         19 load $license;
96             ## it doesn't matter who's the holder at this point. We just want the
97             ## pretty text for the license name
98 9         9580 $license = $license->new({holder => "does not matter"})
99             };
100 9 50       49 Carp::croak "Possibly $_ license module not installed: $@" if $@;
101 9         20 $license;
102             } @licenses;
103              
104 6 0 33     214 if ($self->add_dist_license && $input->{license}) {
105 0         0 push (@licenses, $input->{license});
106             }
107              
108 6 50       11 Carp::croak "Unable to find an author for $filename" unless scalar (@authors);
109 6 50       12 Carp::croak "Unable to find a copyright owner for $filename" unless scalar (@owners);
110 6 50       7 Carp::croak "Unable to find a copyright license for $filename" unless scalar (@licenses);
111              
112 6         4 my ($author_text, $license_text);
113              
114 6         14 $author_text = join ("\n\n", @authors);
115              
116             ## One day, we might need a more complex legal text but in the mean
117             ## time, this is fine to avoid repeated entries
118 6         7 @licenses = uniq (map { lcfirst($_->name) } @licenses);
  9         27  
119             ## and make pretty English with year and owner names
120             @owners = map {
121 6         98 my $text;
  12         8  
122             ## there may be spaces and dashes on the years:
123             ## 2003, 2004
124             ## 2006-2007, 2008
125             ##
126             ## so it must start and end with numbers, but in the middle we allow spaces,
127             ## dashes and commas as well.
128 12         34 $_ =~ m/^([\d][\d\s\-,]*[\d])?\s*(.+)$/;
129 12 100       27 $text .= "$1 " if $1;
130 12         19 $text .= "by $2";
131 12         19 $text;
132             } @owners;
133              
134 6         15 $license_text .= "This software is copyright (c) ". _join (@owners) . ".\n";
135 6         8 $license_text .= "\n";
136 6         15 $license_text .= "This software is available under " . _join (@licenses) . ".";
137              
138 6 100       6 push (@{$document->children}, Pod::Elemental::Element::Nested->new({
  6         145  
139             command => "head" . $self->head,
140             content => @authors > 1? "AUTHORS" : "AUTHOR",
141             children => [Pod::Elemental::Element::Pod5::Ordinary->new({ content => $author_text })],
142             }));
143              
144 6         2314 push (@{$document->children}, Pod::Elemental::Element::Nested->new({
  6         137  
145             command => "head" . $self->head,
146             content => "COPYRIGHT",
147             children => [Pod::Elemental::Element::Pod5::Ordinary->new({ content => $license_text })],
148             }));
149             }
150              
151             __PACKAGE__->meta->make_immutable;
152             1;
153              
154             __END__
155              
156             =pod
157              
158             =encoding UTF-8
159              
160             =head1 NAME
161              
162             Pod::Weaver::Section::Legal::Complicated - Different authors, copyright holders, and licenses for each module.
163              
164             =head1 VERSION
165              
166             version 1.23
167              
168             =head1 SYNOPSIS
169              
170             In your F<weaver.ini>
171              
172             [Legal::Complicated]
173              
174             =head1 DESCRIPTION
175              
176             This plugin is aimed at distributions that have several files, each of them with
177             possibly different authors, copyright owners and licenses.
178              
179             It will look for these values in comments of the source code (analyzed
180             through a C<ppi_document>) with the following form:
181              
182             # AUTHOR: John Doe <john.doe@otherside.com>
183             # AUTHOR: Mary Jane <mary.jane@thisside.com>
184             # OWNER: 2001-2005 University of Over Here
185             # OWNER: 2012 Mary Jane
186             # LICENSE: GPL_3
187              
188             This example would generate the following POD:
189              
190             =head2 AUTHORS
191              
192             John Doe <john.doe@otherside.com>
193             Mary Jane <mary.jane@thisside.com>
194              
195             =head2 COPYRIGHT
196              
197             This software is copyright (c) 2001-2005 by University of Over Here, and 2012 by Mary Jane.
198              
199             This software is available under The GNU General Public License, Version 3, June 2007.
200              
201             Note that this plugin makes a distinction between the authors (whoever wrote the
202             code), and the actual copyright owners (possibly the person who paid them to
203             write it).
204              
205             I am not a lawyer myself, any feedback on better ways to deal with this kind of
206             situations is most welcome.
207              
208             =head1 ATTRIBUTES
209              
210             =head2 add_dist_license
211              
212             If true, it will also add the distribution license to each of the files.
213             Defaults to false.
214              
215             =head2 head
216              
217             Sets the heading level for the legal section. Defaults to 1.
218              
219             =head1 NOTE ON DEPENDENCIES
220              
221             This plugin is dependent on the L<Software::License::*> module of the license
222             being used. Since it is not feasible to list them all, only L<Software::License>
223             is listed as dependency (of the distribution, even though it is not actually
224             used directly.
225              
226             =for Pod::Coverage _extract_comments
227              
228             =for Pod::Coverage _join
229             makes sure there's not too many "and" when there's too many entries
230              
231             =for Pod::Coverage weave_section
232              
233             =head1 AUTHOR
234              
235             Carnë Draug <cdraug@cpan.org>
236              
237             =head1 COPYRIGHT AND LICENSE
238              
239             This software is Copyright (c) 2013-2017 by Carnë Draug.
240              
241             This is free software, licensed under:
242              
243             The GNU General Public License, Version 3, June 2007
244              
245             =cut