File Coverage

blib/lib/Keyword/DEVELOPMENT.pm
Criterion Covered Total %
statement 21 30 70.0
branch 4 10 40.0
condition n/a
subroutine 6 7 85.7
pod n/a
total 31 47 65.9


line stmt bran cond sub pod time code
1             package Keyword::DEVELOPMENT;
2              
3 3     3   177151 use 5.012; # required for pluggable keywords
  3         24  
4 3     3   12 use warnings;
  3         5  
  3         74  
5 3     3   12 use Carp 'croak';
  3         3  
  3         128  
6 3     3   1220 use Keyword::Simple;
  3         59692  
  3         694  
7              
8             =head1 NAME
9              
10             Keyword::DEVELOPMENT - Have code blocks which don't exist unless you ask for them.
11              
12             =head1 VERSION
13              
14             Version 0.04
15              
16             =cut
17              
18             our $VERSION = '0.05';
19              
20             =head1 SYNOPSIS
21              
22             use Keyword::DEVELOPMENT;
23              
24             sub foo {
25             my $self = shift;
26             DEVELOPMENT {
27             $self->expensive_debugging_code;
28             }
29             ...
30             }
31              
32             =head1 EXPORT
33              
34             =head2 DEVELOPMENT
35              
36             This module exports one keyword, C. This keyword takes a code
37             block.
38              
39             If the environment variable C is set to a true
40             value, the code block is executed. Otherwise, the entire block is removed at
41             compile-time, thus ensuring that there is no runtime overhead for the block.
42              
43             ALternatively, you can set the C variable to a
44             valid Perl regular expression to only run C blocks in packages
45             matching the regex.
46              
47             This is primarily a development tool for performance-critical code.
48              
49             =cut
50              
51             sub import {
52 3     3   26 my $caller = caller;
53              
54 3         8 my $match = $ENV{PERL_KEYWORD_DEVELOPMENT_MATCH};
55 3 50       11 if ( defined $match ) {
56 0         0 $ENV{PERL_KEYWORD_DEVELOPMENT} = 1;
57 0         0 my $success = eval { qr/$match/; 1 };
  0         0  
  0         0  
58 0 0       0 unless ($success) {
59 0         0 my $error = $@;
60 0         0 croak(
61             "PERL_KEYWORD_DEVELOPMENT_MATCH environment variable '$ENV{PERL_KEYWORD_DEVELOPMENT_MATCH}' is not a valid regex: $error"
62             );
63             }
64             }
65              
66             Keyword::Simple::define 'DEVELOPMENT', sub {
67 2     2   97 my $in_development = 0;
68 2         4 my ($ref) = @_;
69 2 100       9 if ( $ENV{PERL_KEYWORD_DEVELOPMENT} ) {
70 1 50       8 if ( defined $match ) {
71 0 0       0 $in_development = $caller =~ /$match/ ? 1 : 0;
72             }
73             else {
74 1         2 $in_development = 1;
75             }
76             }
77 2         2370 substr( $$ref, 0, 0 ) = "if ($in_development)";
78 3         19 };
79             }
80              
81             sub unimport {
82 0     0     Keyword::Simple::undefine 'DEVELOPMENT';
83             }
84              
85             =head1 EXAMPLE
86              
87             Consider the following code:
88              
89             #!/usr/bin/env perl
90              
91             BEGIN {
92             # just in case someone turned this off
93             $ENV{PERL_KEYWORD_DEVELOPMENT} = 1;
94             }
95             use lib 'lib';
96             use Keyword::DEVELOPMENT;
97              
98             my $value = 0;
99             DEVELOPMENT {
100             sleep 10;
101             $value = 1;
102             }
103              
104             print "Our value is $value";
105              
106             Running this code should print the following after about 10 seconds:
107              
108             Our value is 1
109              
110             However, if you set C to C<0> in the C block, it prints:
111              
112             Our value is 0
113              
114             To know that we really have B overhead during production, run the code under the debugger
115             with C set to C<0>.
116              
117             $ perl -d development.pl
118              
119             Loading DB routines from perl5db.pl version 1.49_04
120             Editor support available.
121              
122             Enter h or 'h h' for help, or 'man perldebug' for more help.
123              
124             main::(development.pl:10): my $value = 0;
125             auto(-1) DB<1> {{v
126             DB<2> n
127             main::(development.pl:10): my $value = 0;
128             auto(-1) DB<2> v
129             7: use lib 'lib';
130             8: use Keyword::DEVELOPMENT;
131             9
132             10==> my $value = 0;
133              
134             11 # PERL_KEYWORD_DEVELOPMENT was false, so the development code was removed.
135             12 #KDCT:_:_:1 DEVELOPMENT
136             13 #line 14 development.pl
137             14
138             15
139             16: print "Our value is $value";
140             DB<2>
141              
142             As you can see, there are only comments there, no code.
143              
144             Note the handy line directive on line 13 to ensure your line numbers remain
145             correct. If you're not familiar with line directives, see
146             L
147              
148             =head1 MATCHING PACKAGES
149              
150             If you use C extensively, you may find that the
151             C block is called too frequently. As of version 0.05, an
152             experimental feature has been added to allow you to only invoke C
153             blocks in packages matching a regex. Set the C
154             variable to a Perl regular expression instead of the
155             C variable. Only packages whose names match the
156             regular expression will have their C block triggered.
157              
158             PERL_KEYWORD_DEVELOPMENT_MATCH='^(?:Our::Codebase::|Our::MonkeyPatches::)' \
159             perl some_code.pl
160              
161             The above will only run C for packages whose package names start
162             with C or C.
163              
164             =head1 ALTERNATIVES
165              
166             As SawyerX pointed out, can replicate the functionality of this module in pure
167             Perl, if desired:
168              
169             use constant PRODUCTION => !!$ENV{PRODUCTION};
170             DEVELOPMENT {expensive_debugging_code()} unless PRODUCTION;
171              
172             Versus:
173              
174             use Keyword::DEVELOPMENT;
175             DEVELOPMENT {expensive_debugging_code()};
176              
177             The first version works because the line is removed entirely from the source
178             code using constant-folding (if C evaluates to false during
179             compile time, the entire line will be omitted).
180              
181             I think C is less fragile in that you never need to
182             remember the C statement modifier. However, we do rely on
183             the pluggable keyword functionality introduced in 5.012. Be warned!
184              
185             =head1 AUTHOR
186              
187             Curtis "Ovid" Poe, C<< >>
188              
189             =head1 BUGS AND LIMITATIONS
190              
191             Please report any bugs or feature requests to C
192             rt.cpan.org>, or through the web interface at
193             L. I will
194             be notified, and then you'll automatically be notified of progress on your bug
195             as I make changes.
196              
197             =head1 SUPPORT
198              
199             You can find documentation for this module with the perldoc command.
200              
201             perldoc Keyword::DEVELOPMENT
202              
203             You can also look for information at:
204              
205             =over 4
206              
207             =item * RT: CPAN's request tracker (report bugs here)
208              
209             L
210              
211             =item * AnnoCPAN: Annotated CPAN documentation
212              
213             L
214              
215             =item * CPAN Ratings
216              
217             L
218              
219             =item * Search CPAN
220              
221             L
222              
223             =back
224              
225             =head1 ACKNOWLEDGEMENTS
226              
227             Thanks to Damian Conway for the excellent C module.
228              
229             =head1 LICENSE AND COPYRIGHT
230              
231             Copyright 2017 Curtis "Ovid" Poe.
232              
233             This program is free software; you can redistribute it and/or modify it
234             under the terms of the the Artistic License (2.0). You may obtain a
235             copy of the full license at:
236              
237             L
238              
239             Any use, modification, and distribution of the Standard or Modified
240             Versions is governed by this Artistic License. By using, modifying or
241             distributing the Package, you accept this license. Do not use, modify,
242             or distribute the Package, if you do not accept this license.
243              
244             If your Modified Version has been derived from a Modified Version made
245             by someone other than you, you are nevertheless required to ensure that
246             your Modified Version complies with the requirements of this license.
247              
248             This license does not grant you the right to use any trademark, service
249             mark, tradename, or logo of the Copyright Holder.
250              
251             This license includes the non-exclusive, worldwide, free-of-charge
252             patent license to make, have made, use, offer to sell, sell, import and
253             otherwise transfer the Package with respect to any patent claims
254             licensable by the Copyright Holder that are necessarily infringed by the
255             Package. If you institute patent litigation (including a cross-claim or
256             counterclaim) against any party alleging that the Package constitutes
257             direct or contributory patent infringement, then this Artistic License
258             to you shall terminate on the date that such litigation is filed.
259              
260             Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER
261             AND CONTRIBUTORS "AS IS' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
262             THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
263             PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY
264             YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR
265             CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR
266             CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE,
267             EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
268              
269             =cut
270              
271             1; # End of Keyword::DEVELOPMENT