File Coverage

blib/lib/Dist/Zilla/Role/Hooker.pm
Criterion Covered Total %
statement 44 46 95.6
branch 10 14 71.4
condition 2 3 66.6
subroutine 7 7 100.0
pod 1 1 100.0
total 64 71 90.1


line stmt bran cond sub pod time code
1             # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2             #
3             # file: lib/Dist/Zilla/Role/Hooker.pm
4             #
5             # Copyright © 2015 Van de Bugger
6             #
7             # This file is part of perl-Dist-Zilla-Plugin-Hook.
8             #
9             # perl-Dist-Zilla-Plugin-Hook is free software: you can redistribute it and/or modify it under
10             # the terms of the GNU General Public License as published by the Free Software Foundation,
11             # either version 3 of the License, or (at your option) any later version.
12             #
13             # perl-Dist-Zilla-Plugin-Hook is distributed in the hope that it will be useful, but WITHOUT ANY
14             # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15             # PURPOSE. See the GNU General Public License for more details.
16             #
17             # You should have received a copy of the GNU General Public License along with
18             # perl-Dist-Zilla-Plugin-Hook. If not, see <http://www.gnu.org/licenses/>.
19             #
20             # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
21              
22             #pod =for :this This is C<Hooker> role documentation. Read this if you are going to hack or extend
23             #pod C<Dist-Zilla-Plugin-Hook>, or use the role in your plugin.
24             #pod
25             #pod =for :those If you want to write C<Dist::Zilla> plugin directly in F<dist.ini>, read the L<manual|Dist::Zilla::Plugin::Hook::Manual>. General
26             #pod topics like getting source, building, installing, bug reporting and some others are covered in the
27             #pod F<README>.
28             #pod
29             #pod =head1 DESCRIPTION
30             #pod
31             #pod C<Dist-Zilla-Plugin-Hook> is a set of plugins: C<Hook::Init>, C<Hook::BeforeBuild>, C<Hook::GatherFiles>,
32             #pod etc. All these plugins are just stubs, they contains almost no code. They just use services
33             #pod provided by the C<Hooker> role. The role is an engine for all C<Hook> plugins.
34             #pod
35             #pod =head1 SEE ALSO
36             #pod
37             #pod =for :list
38             #pod = L<Dist::Zilla>
39             #pod = L<Dist::Zilla::Role>
40             #pod = L<Dist::Zilla::Role::Plugin>
41             #pod = L<Dist::Zilla::Plugin::Hook::Manual>
42             #pod
43             #pod =cut
44              
45             package Dist::Zilla::Role::Hooker;
46              
47 1     1   518 use Moose::Role;
  1         2  
  1         7  
48 1     1   3448 use namespace::autoclean;
  1         2  
  1         7  
49 1     1   60 use version 0.77;
  1         23  
  1         6  
50              
51             # ABSTRACT: Run Perl code written in your plugin's F<dist.ini> section
52             our $VERSION = 'v0.8.1_01'; # TRIAL VERSION
53              
54             with 'Dist::Zilla::Role::Plugin';
55             with 'Dist::Zilla::Role::ErrorLogger' => { -version => 0.005 };
56              
57             # --------------------------------------------------------------------------------------------------
58              
59             #pod =attr code
60             #pod
61             #pod Perl code to execute, list of lines (without newline characters).
62             #pod
63             #pod C<ArrayRef[Str]>, read-only. Default value is empty array (i. e. no code).
64             #pod
65             #pod Note: C<init_arg> attribute property set to ".". In F<dist.ini> file the Perl code should be
66             #pod specified using this notation:
67             #pod
68             #pod [Hook::Role]
69             #pod . = …Perl code…
70             #pod
71             #pod =cut
72              
73             has code => (
74             is => 'ro',
75             isa => 'ArrayRef[Str]',
76             auto_deref => 1,
77             init_arg => '.',
78             default => sub { [] },
79             );
80              
81             # --------------------------------------------------------------------------------------------------
82              
83             #pod =method hook
84             #pod
85             #pod $ret = $self->hook( @args );
86             #pod @ret = $self->hook( @args );
87             #pod $self->hook( @args );
88             #pod
89             #pod This is the primary method of the role. The method executes Perl code specified in C<code>
90             #pod attribute (prepended with C<_prologue>) with string form of C<eval>. The method passes arguments
91             #pod specified by the caller to the code, and passes the code return value back to the caller. Calling
92             #pod context (list, scalar, or void) is preserved. The method also hides all the lexical variables
93             #pod (except the variables documented below) from code. The method intercepts warnings generated in code
94             #pod and logs them; warnings do not stop executing.
95             #pod
96             #pod Following lexical variables are exposed to the code intentionally:
97             #pod
98             #pod =begin :list
99             #pod
100             #pod = C<@_>
101             #pod C<hook> arguments, self-reference is already shifted!
102             #pod
103             #pod = C<$arg>
104             #pod The same as C<$_[ 0 ]>.
105             #pod
106             #pod = C<$self>
107             #pod = C<$plugin>
108             #pod Reference to the plugin object executing the code (such as C<Hook::Init> or C<Hook::BeforeBuild>).
109             #pod
110             #pod = C<$dist>
111             #pod = C<$zilla>
112             #pod Reference to C<Dist::Zilla> object, the same as C<< $self->zilla >>.
113             #pod
114             #pod =end :list
115             #pod
116             #pod If code dies, the method logs error message and aborts C<Dist::Zilla>.
117             #pod
118             #pod =cut
119              
120             sub hook { ## no critic ( RequireArgUnpacking )
121 18     18 1 51590 my $self = shift( @_ );
122 18 50       597 if ( not $self->code ) {
123 0         0 return;
124             };
125 18         444 my $zilla = $self->zilla; # `eval` sees these variables.
126 18         77 my $plugin = $self;
127 18         19 my $dist = $zilla;
128 18         24 my $arg = $_[ 0 ];
129             my $code = # Declaration is not yet completed, `eval` will not see it.
130             sub {
131             #~ local $SIG{ __DIE__ }; # TODO: Should I cancel die handler, if any is set?
132             local $SIG{ __WARN__ } = sub {
133 1         27 my $msg = "$_[ 0 ]";
134 1         3 chomp( $msg );
135 1         4 $self->log( $msg );
136 18     18   110 };
137             eval( ## no critic ( ProhibitStringyEval, RequireCheckingReturnValueOfEval )
138 18         56 join(
139             "\n",
140             $self->_line_directive( 'prologue' ), # Make error repot nice.
141             $self->_prologue,
142             $self->_line_directive( $self->plugin_name ), # Make error repot nice.
143             $self->code,
144             )
145             );
146 18         72 };
147 18         25 my $want = wantarray();
148 18         16 my ( $err, @ret );
149             {
150 18         20 local $@ = $@; # Keep outer `$@` intact.
  18         33  
151 18 50       48 if ( $want ) { # Let us keep calling context.
    100          
152 0         0 @ret = $code->( @_ );
153             } elsif ( defined( $want ) ) {
154 2         7 $ret[ 0 ] = $code->( @_ );
155             } else {
156 16         29 $code->( @_ );
157             };
158 18         16158 $err = "$@"; # Stringify `$@`.
159             }
160 18 100       163 if ( $err ne '' ) {
161 8         22 chomp( $err );
162 8         42 $self->abort( $err );
163             };
164 10 50       232 return $want ? @ret : $ret[ 0 ];
165             };
166              
167             # --------------------------------------------------------------------------------------------------
168              
169             #pod =method _line_directive
170             #pod
171             #pod $dir = $self->_line_directive( $filename, $linenumber );
172             #pod $dir = $self->_line_directive( $filename );
173             #pod
174             #pod The method returns Perl line directive, like
175             #pod
176             #pod #line 1 "filename.ext"
177             #pod
178             #pod The method takes care about quotes. Perl line directive does not allow any quotes (escaped or not)
179             #pod in filename, so directive
180             #pod
181             #pod #line 1 "\"Assa\" project.txt"
182             #pod
183             #pod will be ignored. To avoid this, C<line_directive> replaces quotes in filename with apostrophes, e.
184             #pod g.:
185             #pod
186             #pod #line 1 "'Assa' project.txt"
187             #pod
188             #pod If line number is not specified, 1 will be used.
189             #pod
190             #pod =cut
191              
192             sub _line_directive {
193 36     36   100 my ( $self, $file, $line ) = @_;
194 36         58 $file =~ s{"}{'}gx; # Perl `#line` directive does not allow quotes in filename.
195             # TODO: Issue a warning if filename contains double quote?
196 36 50       60 if ( not defined( $line ) ) {
197 36         38 $line = 1;
198             };
199 36         600 return sprintf( '#line %d "%s"', $line, $file );
200             };
201              
202             # --------------------------------------------------------------------------------------------------
203              
204             #pod =method _prologue
205             #pod
206             #pod @code = $self->_prologue;
207             #pod
208             #pod The method returns prologue code.
209             #pod
210             #pod Prologue code is extracted from C<Dist::Zilla> plugin named C<prologue>.
211             #pod
212             #pod =cut
213              
214             sub _prologue {
215 18     18   29 my ( $self ) = @_;
216 18         406 my $zilla = $self->zilla;
217 18         135 my $prologue = $zilla->plugin_named( 'prologue' );
218 18 100 66     1738 if ( $prologue and $prologue->meta->does_role( 'Dist::Zilla::Role::Hooker' ) ) {
219 4         217 return $prologue->code;
220             };
221 14         329 return ();
222             };
223              
224             # --------------------------------------------------------------------------------------------------
225              
226             #pod =method mvp_multivalue_args
227             #pod
228             #pod The method tells C<Dist::Zilla> that dot (C<.>) is a multi-value option.
229             #pod
230             #pod =cut
231              
232             around mvp_multivalue_args => sub {
233             my ( $orig, $self ) = @_;
234             return ( $self->$orig(), qw{ . } );
235             };
236              
237             # --------------------------------------------------------------------------------------------------
238              
239             around mvp_aliases => sub {
240             my ( $orig, $self ) = @_;
241             my $aliases = $self->$orig();
242             $aliases->{ hook } = '.';
243             return $aliases;
244             };
245              
246             1;
247              
248             # --------------------------------------------------------------------------------------------------
249              
250             #pod =head1 COPYRIGHT AND LICENSE
251             #pod
252             #pod Copyright (C) 2015 Van de Bugger
253             #pod
254             #pod License GPLv3+: The GNU General Public License version 3 or later
255             #pod <http://www.gnu.org/licenses/gpl-3.0.txt>.
256             #pod
257             #pod This is free software: you are free to change and redistribute it. There is
258             #pod NO WARRANTY, to the extent permitted by law.
259             #pod
260             #pod
261             #pod =cut
262              
263             # doc/what.pod #
264              
265             #pod =encoding UTF-8
266             #pod
267             #pod =head1 WHAT?
268             #pod
269             #pod C<Dist-Zilla-Plugin-Hook> (or just C<Hook>) is a set of C<Dist-Zilla> plugins. Every plugin executes Perl
270             #pod code inlined into F<dist.ini> at particular stage of build process.
271             #pod
272             #pod =cut
273              
274             # end of file #
275              
276              
277             # end of file #
278              
279             __END__
280              
281             =pod
282              
283             =encoding UTF-8
284              
285             =head1 NAME
286              
287             Dist::Zilla::Role::Hooker - Run Perl code written in your plugin's F<dist.ini> section
288              
289             =head1 VERSION
290              
291             Version v0.8.1_01, released on 2016-10-11 00:10 UTC.
292             This is a B<trial release>.
293              
294             =head1 WHAT?
295              
296             C<Dist-Zilla-Plugin-Hook> (or just C<Hook>) is a set of C<Dist-Zilla> plugins. Every plugin executes Perl
297             code inlined into F<dist.ini> at particular stage of build process.
298              
299             This is C<Hooker> role documentation. Read this if you are going to hack or extend
300             C<Dist-Zilla-Plugin-Hook>, or use the role in your plugin.
301              
302             If you want to write C<Dist::Zilla> plugin directly in F<dist.ini>, read the L<manual|Dist::Zilla::Plugin::Hook::Manual>. General
303             topics like getting source, building, installing, bug reporting and some others are covered in the
304             F<README>.
305              
306             =head1 DESCRIPTION
307              
308             C<Dist-Zilla-Plugin-Hook> is a set of plugins: C<Hook::Init>, C<Hook::BeforeBuild>, C<Hook::GatherFiles>,
309             etc. All these plugins are just stubs, they contains almost no code. They just use services
310             provided by the C<Hooker> role. The role is an engine for all C<Hook> plugins.
311              
312             =head1 OBJECT ATTRIBUTES
313              
314             =head2 code
315              
316             Perl code to execute, list of lines (without newline characters).
317              
318             C<ArrayRef[Str]>, read-only. Default value is empty array (i. e. no code).
319              
320             Note: C<init_arg> attribute property set to ".". In F<dist.ini> file the Perl code should be
321             specified using this notation:
322              
323             [Hook::Role]
324             . = …Perl code…
325              
326             =head1 OBJECT METHODS
327              
328             =head2 hook
329              
330             $ret = $self->hook( @args );
331             @ret = $self->hook( @args );
332             $self->hook( @args );
333              
334             This is the primary method of the role. The method executes Perl code specified in C<code>
335             attribute (prepended with C<_prologue>) with string form of C<eval>. The method passes arguments
336             specified by the caller to the code, and passes the code return value back to the caller. Calling
337             context (list, scalar, or void) is preserved. The method also hides all the lexical variables
338             (except the variables documented below) from code. The method intercepts warnings generated in code
339             and logs them; warnings do not stop executing.
340              
341             Following lexical variables are exposed to the code intentionally:
342              
343             =over 4
344              
345             =item C<@_>
346              
347             C<hook> arguments, self-reference is already shifted!
348              
349             =item C<$arg>
350              
351             The same as C<$_[ 0 ]>.
352              
353             =item C<$self>
354              
355             =item C<$plugin>
356              
357             Reference to the plugin object executing the code (such as C<Hook::Init> or C<Hook::BeforeBuild>).
358              
359             =item C<$dist>
360              
361             =item C<$zilla>
362              
363             Reference to C<Dist::Zilla> object, the same as C<< $self->zilla >>.
364              
365             =back
366              
367             If code dies, the method logs error message and aborts C<Dist::Zilla>.
368              
369             =head2 _line_directive
370              
371             $dir = $self->_line_directive( $filename, $linenumber );
372             $dir = $self->_line_directive( $filename );
373              
374             The method returns Perl line directive, like
375              
376             #line 1 "filename.ext"
377              
378             The method takes care about quotes. Perl line directive does not allow any quotes (escaped or not)
379             in filename, so directive
380              
381             #line 1 "\"Assa\" project.txt"
382              
383             will be ignored. To avoid this, C<line_directive> replaces quotes in filename with apostrophes, e.
384             g.:
385              
386             #line 1 "'Assa' project.txt"
387              
388             If line number is not specified, 1 will be used.
389              
390             =head2 _prologue
391              
392             @code = $self->_prologue;
393              
394             The method returns prologue code.
395              
396             Prologue code is extracted from C<Dist::Zilla> plugin named C<prologue>.
397              
398             =head2 mvp_multivalue_args
399              
400             The method tells C<Dist::Zilla> that dot (C<.>) is a multi-value option.
401              
402             =head1 SEE ALSO
403              
404             =over 4
405              
406             =item L<Dist::Zilla>
407              
408             =item L<Dist::Zilla::Role>
409              
410             =item L<Dist::Zilla::Role::Plugin>
411              
412             =item L<Dist::Zilla::Plugin::Hook::Manual>
413              
414             =back
415              
416             =head1 AUTHOR
417              
418             Van de Bugger <van.de.bugger@gmail.com>
419              
420             =head1 COPYRIGHT AND LICENSE
421              
422             Copyright (C) 2015 Van de Bugger
423              
424             License GPLv3+: The GNU General Public License version 3 or later
425             <http://www.gnu.org/licenses/gpl-3.0.txt>.
426              
427             This is free software: you are free to change and redistribute it. There is
428             NO WARRANTY, to the extent permitted by law.
429              
430             =cut