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             # ---------------------------------------------------------------------- copyright and license ---
2             #
3             # file: lib/Dist/Zilla/Role/Hooker.pm
4             #
5             # Copyright © 2015, 2016 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             # ---------------------------------------------------------------------- copyright and license ---
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   586 use Moose::Role;
  1         2  
  1         7  
48 1     1   4057 use namespace::autoclean;
  1         3  
  1         7  
49 1     1   67 use version 0.77;
  1         22  
  1         7  
50              
51             # ABSTRACT: Run Perl code written in your plugin's F<dist.ini> section
52             our $VERSION = 'v0.8.2_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 61824 my $self = shift( @_ );
122 18 50       662 if ( not $self->code ) {
123 0         0 return;
124             };
125 18         525 my $zilla = $self->zilla; # `eval` sees these variables.
126 18         107 my $plugin = $self;
127 18         24 my $dist = $zilla;
128 18         30 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         30 my $msg = "$_[ 0 ]";
134 1         4 chomp( $msg );
135 1         5 $self->log( $msg );
136 18     18   134 };
137             eval( ## no critic ( ProhibitStringyEval, RequireCheckingReturnValueOfEval )
138 18         57 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         103 };
147 18         34 my $want = wantarray();
148 18         22 my ( $err, @ret );
149             {
150 18         22 local $@ = $@; # Keep outer `$@` intact.
  18         29  
151 18 50       56 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         32 $code->( @_ );
157             };
158 18         19808 $err = "$@"; # Stringify `$@`.
159             }
160 18 100       208 if ( $err ne '' ) {
161 8         38 chomp( $err );
162 8         46 $self->abort( $err );
163             };
164 10 50       280 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   141 my ( $self, $file, $line ) = @_;
194 36         71 $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       75 if ( not defined( $line ) ) {
197 36         46 $line = 1;
198             };
199 36         759 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         562 my $zilla = $self->zilla;
217 18         180 my $prologue = $zilla->plugin_named( 'prologue' );
218 18 100 66     2161 if ( $prologue and $prologue->meta->does_role( 'Dist::Zilla::Role::Hooker' ) ) {
219 4         282 return $prologue->code;
220             };
221 14         410 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, 2016 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             # ------------------------------------------------------------------------------------------------
264             #
265             # file: doc/what.pod
266             #
267             # This file is part of perl-Dist-Zilla-Plugin-Hook.
268             #
269             # ------------------------------------------------------------------------------------------------
270              
271             #pod =encoding UTF-8
272             #pod
273             #pod =head1 WHAT?
274             #pod
275             #pod C<Dist-Zilla-Plugin-Hook> (or just C<Hook>) is a set of C<Dist-Zilla> plugins. Every plugin executes Perl
276             #pod code inlined into F<dist.ini> at particular stage of build process.
277             #pod
278             #pod =cut
279              
280             # end of file #
281              
282              
283             # end of file #
284              
285             __END__
286              
287             =pod
288              
289             =encoding UTF-8
290              
291             =head1 NAME
292              
293             Dist::Zilla::Role::Hooker - Run Perl code written in your plugin's F<dist.ini> section
294              
295             =head1 VERSION
296              
297             Version v0.8.2_01, released on 2016-11-24 21:44 UTC.
298             This is a B<trial release>.
299              
300             =head1 WHAT?
301              
302             C<Dist-Zilla-Plugin-Hook> (or just C<Hook>) is a set of C<Dist-Zilla> plugins. Every plugin executes Perl
303             code inlined into F<dist.ini> at particular stage of build process.
304              
305             This is C<Hooker> role documentation. Read this if you are going to hack or extend
306             C<Dist-Zilla-Plugin-Hook>, or use the role in your plugin.
307              
308             If you want to write C<Dist::Zilla> plugin directly in F<dist.ini>, read the L<manual|Dist::Zilla::Plugin::Hook::Manual>. General
309             topics like getting source, building, installing, bug reporting and some others are covered in the
310             F<README>.
311              
312             =head1 DESCRIPTION
313              
314             C<Dist-Zilla-Plugin-Hook> is a set of plugins: C<Hook::Init>, C<Hook::BeforeBuild>, C<Hook::GatherFiles>,
315             etc. All these plugins are just stubs, they contains almost no code. They just use services
316             provided by the C<Hooker> role. The role is an engine for all C<Hook> plugins.
317              
318             =head1 OBJECT ATTRIBUTES
319              
320             =head2 code
321              
322             Perl code to execute, list of lines (without newline characters).
323              
324             C<ArrayRef[Str]>, read-only. Default value is empty array (i. e. no code).
325              
326             Note: C<init_arg> attribute property set to ".". In F<dist.ini> file the Perl code should be
327             specified using this notation:
328              
329             [Hook::Role]
330             . = …Perl code…
331              
332             =head1 OBJECT METHODS
333              
334             =head2 hook
335              
336             $ret = $self->hook( @args );
337             @ret = $self->hook( @args );
338             $self->hook( @args );
339              
340             This is the primary method of the role. The method executes Perl code specified in C<code>
341             attribute (prepended with C<_prologue>) with string form of C<eval>. The method passes arguments
342             specified by the caller to the code, and passes the code return value back to the caller. Calling
343             context (list, scalar, or void) is preserved. The method also hides all the lexical variables
344             (except the variables documented below) from code. The method intercepts warnings generated in code
345             and logs them; warnings do not stop executing.
346              
347             Following lexical variables are exposed to the code intentionally:
348              
349             =over 4
350              
351             =item C<@_>
352              
353             C<hook> arguments, self-reference is already shifted!
354              
355             =item C<$arg>
356              
357             The same as C<$_[ 0 ]>.
358              
359             =item C<$self>
360              
361             =item C<$plugin>
362              
363             Reference to the plugin object executing the code (such as C<Hook::Init> or C<Hook::BeforeBuild>).
364              
365             =item C<$dist>
366              
367             =item C<$zilla>
368              
369             Reference to C<Dist::Zilla> object, the same as C<< $self->zilla >>.
370              
371             =back
372              
373             If code dies, the method logs error message and aborts C<Dist::Zilla>.
374              
375             =head2 _line_directive
376              
377             $dir = $self->_line_directive( $filename, $linenumber );
378             $dir = $self->_line_directive( $filename );
379              
380             The method returns Perl line directive, like
381              
382             #line 1 "filename.ext"
383              
384             The method takes care about quotes. Perl line directive does not allow any quotes (escaped or not)
385             in filename, so directive
386              
387             #line 1 "\"Assa\" project.txt"
388              
389             will be ignored. To avoid this, C<line_directive> replaces quotes in filename with apostrophes, e.
390             g.:
391              
392             #line 1 "'Assa' project.txt"
393              
394             If line number is not specified, 1 will be used.
395              
396             =head2 _prologue
397              
398             @code = $self->_prologue;
399              
400             The method returns prologue code.
401              
402             Prologue code is extracted from C<Dist::Zilla> plugin named C<prologue>.
403              
404             =head2 mvp_multivalue_args
405              
406             The method tells C<Dist::Zilla> that dot (C<.>) is a multi-value option.
407              
408             =head1 SEE ALSO
409              
410             =over 4
411              
412             =item L<Dist::Zilla>
413              
414             =item L<Dist::Zilla::Role>
415              
416             =item L<Dist::Zilla::Role::Plugin>
417              
418             =item L<Dist::Zilla::Plugin::Hook::Manual>
419              
420             =back
421              
422             =head1 AUTHOR
423              
424             Van de Bugger <van.de.bugger@gmail.com>
425              
426             =head1 COPYRIGHT AND LICENSE
427              
428             Copyright (C) 2015, 2016 Van de Bugger
429              
430             License GPLv3+: The GNU General Public License version 3 or later
431             <http://www.gnu.org/licenses/gpl-3.0.txt>.
432              
433             This is free software: you are free to change and redistribute it. There is
434             NO WARRANTY, to the extent permitted by law.
435              
436             =cut