File Coverage

blib/lib/Dist/Iller.pm
Criterion Covered Total %
statement 67 69 97.1
branch 16 18 88.8
condition 5 9 55.5
subroutine 16 17 94.1
pod 0 2 0.0
total 104 115 90.4


line stmt bran cond sub pod time code
1 2     2   781449 use 5.14.0;
  2         30  
2 2     2   12 use strict;
  2         5  
  2         48  
3 2     2   11 use warnings;
  2         3  
  2         145  
4              
5             package Dist::Iller;
6              
7             # ABSTRACT: A Dist::Zilla & Pod::Weaver preprocessor
8             our $AUTHORITY = 'cpan:CSSON'; # AUTHORITY
9             our $VERSION = '0.1411';
10              
11 2     2   859 use Dist::Iller::Elk;
  2         8  
  2         8  
12 2     2   6341 use Types::Standard qw/Map Str ConsumerOf/;
  2         151190  
  2         23  
13 2     2   3372 use Types::Path::Tiny qw/Path/;
  2         60972  
  2         19  
14 2     2   1808 use String::CamelCase qw/camelize/;
  2         1171  
  2         140  
15 2     2   15 use Try::Tiny;
  2         5  
  2         116  
16 2     2   28 use Carp qw/croak/;
  2         5  
  2         91  
17 2     2   1078 use Module::Load qw/load/;
  2         2421  
  2         13  
18 2     2   1053 use Safe::Isa qw/$_does/;
  2         1041  
  2         256  
19 2     2   1210 use YAML::Tiny;
  2         11957  
  2         129  
20 2     2   840 use Dist::Iller::Prereq;
  2         8  
  2         1471  
21              
22             has docs => (
23             is => 'ro',
24             isa => Map[Str, ConsumerOf['Dist::Iller::DocType'] ],
25             default => sub { +{ } },
26             traits => ['Hash'],
27             handles => {
28             set_doc => 'set',
29             get_doc => 'get',
30             doc_keys => 'keys',
31             doc_kv => 'kv',
32             },
33             );
34             has filepath => (
35             is => 'ro',
36             isa => Path,
37             default => 'iller.yaml',
38             coerce => 1,
39             );
40              
41             sub parse {
42 5     5 0 137 my $self = shift;
43 5         13 my $phase = shift;
44              
45 5         161 my $yaml = YAML::Tiny->read($self->filepath->stringify);
46              
47             DOCTYPE:
48 5         44830 for my $document (sort { $a->{'doctype'} cmp $b->{'doctype'} } @{ $yaml }) {
  26         66  
  5         54  
49 19         124 my $doctype_class = sprintf 'Dist::Iller::DocType::%s', camelize($document->{'doctype'});
50             try {
51 19     19   1030 load $doctype_class;
52             }
53             catch {
54 0     0   0 croak "Can't load $doctype_class: $_";
55 19         566 };
56 19 100       1589 next DOCTYPE if $doctype_class->phase ne $phase;
57 7         310 $self->set_doc($document->{'doctype'}, $doctype_class->new(global => $self->get_doc('global'))->parse($document));
58             }
59 5 100       194 if($self->get_doc('dist')) {
60 4         125 $self->get_doc('dist')->add_prereq(Dist::Iller::Prereq->new(
61             module => __PACKAGE__,
62             version => __PACKAGE__->VERSION,
63             phase => 'develop',
64             relation => 'suggests',
65             ));
66              
67             DOC:
68 4         134 for my $doc ($self->doc_kv) {
69 12 100       481 if($doc->[1]->$_does('Dist::Iller::Role::HasPlugins')) {
70 8         854 $self->get_doc('dist')->add_plugins_as_prereqs($doc->[1]->packages_for_plugin, $doc->[1]->all_plugins);
71             }
72              
73 12         801 for my $included_config ($doc->[1]->all_included_configs) {
74 5         163 $self->get_doc('dist')->add_prereq(Dist::Iller::Prereq->new(
75             module => $included_config->[0],
76             version => $included_config->[1],
77             phase => 'develop',
78             relation => 'suggests',
79             ));
80             }
81              
82 12 100       53 next DOC if $doc->[0] eq 'dist';
83 8 100       28 next DOC if $doc->[0] eq 'cpanfile';
84 7 50       29 if($doc->[1]->$_does('Dist::Iller::Role::HasPrereqs')) {
85 0         0 $self->get_doc('dist')->merge_prereqs($doc->[1]->all_prereqs);
86             }
87             }
88             }
89 5 100 66     277 if($self->get_doc('cpanfile') && $self->get_doc('dist')) {
90 1         32 $self->get_doc('cpanfile')->merge_prereqs($self->get_doc('dist')->all_prereqs);
91             }
92             }
93              
94             sub generate_files {
95 4     4 0 40912 my $self = shift;
96 4         18 my $phase = shift;
97              
98 4 50 66     49 croak q{'phase' must be either 'before' or 'after'} if !defined $phase || $phase ne 'before' && $phase ne 'after';
      33        
99              
100 4         183 for my $doc ($self->doc_kv) {
101 12 100       93 next if $doc->[1]->phase ne $phase;
102 6         37 $doc->[1]->generate_file;
103             }
104             }
105              
106             __PACKAGE__->meta->make_immutable;
107              
108             1;
109              
110             __END__
111              
112             =pod
113              
114             =encoding UTF-8
115              
116             =head1 NAME
117              
118             Dist::Iller - A Dist::Zilla & Pod::Weaver preprocessor
119              
120              
121              
122             =begin html
123              
124             <p>
125             <img src="https://img.shields.io/badge/perl-5.14+-blue.svg" alt="Requires Perl 5.14+" />
126             <img src="https://img.shields.io/badge/coverage-84.4%25-orange.svg" alt="coverage 84.4%" />
127             <a href="https://github.com/Csson/p5-Dist-Iller/actions?query=workflow%3Amakefile-test"><img src="https://img.shields.io/github/workflow/status/Csson/p5-Dist-Iller/makefile-test" alt="Build status at Github" /></a>
128             </p>
129              
130             =end html
131              
132             =head1 VERSION
133              
134             Version 0.1411, released 2020-01-01.
135              
136             =head1 SYNOPSIS
137              
138             # dzil new, but...
139             $ dzil new -P DistIller::AMintingProvider My::Module
140              
141             $ cd My/Module
142              
143             # ...all other commands can be used via iller
144             $ iller build
145              
146             =head1 STATUS
147              
148             This is alpha software. Anything can change at any time.
149              
150             It is mostly here to document how I build my distributions. It is perfectly fine to use C<dzil> with a distribution built with C<Dist::Iller> (after a fork, for example).
151              
152             =head1 DESCRIPTION
153              
154             Dist::Iller is a L<Dist::Zilla> and L<Pod::Weaver> preprocessor. It comes with a command line tool (C<iller>) which is a C<dzil> wrapper: When run, it first generates
155             files specified in C<iller.yaml> in the current directory and then executes C<dzil> automatically. (Since C<iller> requires that an C<iller.yaml> is present, C<iller new ...> does not work.)
156              
157             The C<doctype> key in a document in C<iller.yaml> matches a camelized class in the C<Dist::Iller::DocType> namespace; so C<doctype: dist> is parsed by L<Dist::Iller::DocType::Dist>.
158              
159             =head2 iller.yaml
160              
161             This is the general syntax of an C<iller.yaml> file:
162              
163             ---
164             # This specifies that this yaml document will generate dist.ini.
165             doctype: dist
166              
167             # This generates the top part of C<dist.ini>. C<author> can be a list or string.
168             header:
169             name: My-Module
170             author: Ex Ample <ample@example.org>
171             license: Perl_5
172             copyright_holder: Ex Ample
173             copyright_year: 2015
174              
175             # It is possible to list all prereqs. The groups are specified in CPAN::Meta::Spec.
176             # Minimum version numbers are optional.
177             prereqs:
178             runtime:
179             requires:
180             - perl: 5.010001
181             - Moose
182              
183             # List all plugins under the 'plugins' key.
184             # Each +plugin item is a Dist::Zilla> plugin.
185             # All commands for Dist::Iller is prepended with a +.
186             plugins:
187             # Includes all plugins specified in Dist::Iller::Config::My::Config
188             - +config: My::Config
189              
190             - +plugin: DistIller::MetaGeneratedBy
191             - +plugin: AutoVersion
192             - +plugin: GatherDir
193              
194             # 'dir' is a parameter for ShareDir
195             - +plugin: ShareDir
196             dir: myshare
197              
198             [...]
199              
200             ---
201             # Here starts the weaver.ini configuration.
202             doctype: weaver
203              
204             plugins:
205             # Same Dist::Iller::Config as in the 'dist' document
206             - +config: My::Config
207              
208             # Use PluginBundles
209             - +plugin: '@CorePrep'
210              
211             - +plugin: -SingleEncoding
212              
213             - +plugin: Name
214              
215             - +plugin: Version
216             format: Version %v, released %{YYYY-MM-dd}d.
217              
218             - +plugin: prelude
219             +base: Region
220              
221             - +plugin: List
222             +base: -Transformer
223             +in: Elemental
224             transformer: List
225              
226             [...]
227              
228             ---
229             # Here starts the .gitignore configuration
230             doctype: gitignore
231              
232             always:
233             - /.build
234             - /_build*
235             - /Build
236             - MYMETA.*
237             - '!META.json'
238             - /.prove
239             ---
240             # No configuration for .cpanfile, but by having a YAML document for it, it gets generated from
241             # the prereqs listed in the 'dist' document
242             doctype: cpanfile
243              
244             =head2 Rationale
245              
246             PluginBundles for both L<Dist::Zilla> and L<Pod::Weaver> have a few downsides:
247              
248             =over 4
249              
250             =item *
251              
252             Mixes code and configuration.
253              
254             =item *
255              
256             Not straightforward to remove or replace specific plugins for a certain distribution
257              
258             =item *
259              
260             Difficult to insert a plugin before another plugin for a certain distribution.
261              
262             =item *
263              
264             PluginBundles can change after a distribution has been released.
265              
266             =item *
267              
268             Difficult for others to understand/know which plugins actually were in effect when the distribution was built.
269              
270             =back
271              
272             C<Dist::Iller> tries to solve this:
273              
274             =over 4
275              
276             =item *
277              
278             Dist::Iller configs (similar to PluginBundles) has their own C<iller.yaml> (normally in C<share/>) where plugins are specified. See tests and L<Dist::Iller::Config::Author::CSSON>.
279              
280             =item *
281              
282             Since C<dist.ini> and C<weaver.ini> are generated each time C<iller> is run, the plugins listed in them are those that were used to build the distribution.
283              
284             =item *
285              
286             Remove a plugin:
287              
288             =back
289              
290             - +remove_plugin: GatherDir
291              
292             =over 4
293              
294             =item *
295              
296             Insert a plugin:
297              
298             =back
299              
300             - +add_plugin: Git::GatherDir
301             +before: AutoVersion
302              
303             =over 4
304              
305             =item *
306              
307             Replace a plugin:
308              
309             =back
310              
311             - +replace_plugin: ShareDir
312             +with: ShareDir::Tarball
313              
314             =over 4
315              
316             =item *
317              
318             Set more attributes for an already included plugin:
319              
320             =back
321              
322             - +extend_plugin: Git::GatherDir
323             exclude_match:
324             - examples/.*\.html
325              
326             =head1 SEE ALSO
327              
328             =over 4
329              
330             =item *
331              
332             L<Dist::Zilla>
333              
334             =item *
335              
336             L<Pod::Weaver>
337              
338             =item *
339              
340             L<Dist::Iller::Config::Author::CSSON>
341              
342             =back
343              
344             =head1 SOURCE
345              
346             L<https://github.com/Csson/p5-Dist-Iller>
347              
348             =head1 HOMEPAGE
349              
350             L<https://metacpan.org/release/Dist-Iller>
351              
352             =head1 AUTHOR
353              
354             Erik Carlsson <info@code301.com>
355              
356             =head1 COPYRIGHT AND LICENSE
357              
358             This software is copyright (c) 2021 by Erik Carlsson.
359              
360             This is free software; you can redistribute it and/or modify it under
361             the same terms as the Perl 5 programming language system itself.
362              
363             =cut