add 5.20 warning categories
[p5sagit/strictures.git] / lib / strictures.pm
CommitLineData
394c3a46 1package strictures;
2
3use strict;
4use warnings FATAL => 'all';
5
500f28df 6BEGIN {
7 *_PERL_LT_5_8_4 = ($] < 5.008004) ? sub(){1} : sub(){0};
8}
084caaf3 9
23c0b85d 10our $VERSION = '2.000000';
20b853bb 11$VERSION = eval $VERSION;
394c3a46 12
23c0b85d 13our @WARNING_CATEGORIES = grep { exists $warnings::Offsets{$_} } qw(
14 closure
15 deprecated
16 exiting
17 experimental
c5b35ddf 18 experimental::autoderef
23c0b85d 19 experimental::lexical_subs
20 experimental::lexical_topic
c5b35ddf 21 experimental::postderef
23c0b85d 22 experimental::regex_sets
c5b35ddf 23 experimental::signatures
23c0b85d 24 experimental::smartmatch
25 glob
26 imprecision
27 io
28 closed
29 exec
30 layer
31 newline
32 pipe
c5b35ddf 33 syscalls
23c0b85d 34 unopened
35 misc
36 numeric
37 once
38 overflow
39 pack
40 portable
41 recursion
42 redefine
43 regexp
44 severe
45 debugging
46 inplace
47 internal
48 malloc
49 signal
50 substr
51 syntax
52 ambiguous
53 bareword
54 digit
55 illegalproto
56 parenthesis
57 precedence
58 printf
59 prototype
60 qw
61 reserved
62 semicolon
63 taint
64 threads
65 uninitialized
66 unpack
67 untie
68 utf8
69 non_unicode
70 nonchar
71 surrogate
72 void
73 y2k
74);
75
394c3a46 76sub VERSION {
92cde693 77 no warnings;
78 local $@;
79 if (defined $_[1] && eval { $_[0]->UNIVERSAL::VERSION($_[1]); 1}) {
80 $^H |= 0x20000
81 unless _PERL_LT_5_8_4;
82 $^H{strictures_enable} = int $_[1];
394c3a46 83 }
92cde693 84 goto &UNIVERSAL::VERSION;
394c3a46 85}
86
8f0df510 87our %extra_load_states;
ffedb166 88
2da53f4a 89our $Smells_Like_VCS;
12b8f19b 90
394c3a46 91sub import {
92cde693 92 my $class = shift;
93 my %opts = ref $_[0] ? %{$_[0]} : @_;
94 if (!exists $opts{version}) {
95 $opts{version}
96 = exists $^H{strictures_enable} ? delete $^H{strictures_enable}
97 : int $VERSION;
98 }
c5a67be6 99 $opts{file} = (caller)[1];
92cde693 100 $class->_enable(\%opts);
101}
102
103sub _enable {
104 my ($class, $opts) = @_;
105 my $version = $opts->{version};
106 $version = 'undef'
107 if !defined $version;
108 my $method = "_enable_$version";
109 if (!$class->can($method)) {
a97f64c7 110 require Carp;
111 Carp::croak("Major version specified as $version - not supported!");
92cde693 112 }
113 $class->$method($opts);
114}
115
116sub _enable_1 {
c5a67be6 117 my ($class, $opts) = @_;
394c3a46 118 strict->import;
119 warnings->import(FATAL => 'all');
084caaf3 120
c5a67be6 121 if (_want_extra($opts->{file})) {
122 _load_extras(qw(indirect multidimensional bareword::filehandles));
123 indirect->unimport(':fatal')
124 if $extra_load_states{indirect};
125 multidimensional->unimport
126 if $extra_load_states{multidimensional};
127 bareword::filehandles->unimport
128 if $extra_load_states{'bareword::filehandles'};
129 }
8f0df510 130}
131
1931c77d 132our @V2_NONFATAL = grep { exists $warnings::Offsets{$_} } (
133 'exec', # not safe to catch
134 'recursion', # will be caught by other mechanisms
135 'internal', # not safe to catch
136 'malloc', # not safe to catch
137 'newline', # stat on nonexistent file with a newline in it
138 'experimental', # no reason for these to be fatal
139 'deprecated', # unfortunately can't make these fatal
140 'portable', # everything worked fine here, just may not elsewhere
23c0b85d 141);
1931c77d 142our @V2_DISABLE = grep { exists $warnings::Offsets{$_} } (
143 'once' # triggers inconsistently, can't be fatalized
23c0b85d 144);
145
146sub _enable_2 {
147 my ($class, $opts) = @_;
148 strict->import;
149 warnings->import;
150 warnings->import(FATAL => @WARNING_CATEGORIES);
151 warnings->import(NONFATAL => @V2_NONFATAL);
152 warnings->unimport(@V2_DISABLE);
153
154 if (_want_extra($opts->{file})) {
155 _load_extras(qw(indirect multidimensional bareword::filehandles));
156 indirect->unimport(':fatal')
157 if $extra_load_states{indirect};
158 multidimensional->unimport
159 if $extra_load_states{multidimensional};
160 bareword::filehandles->unimport
161 if $extra_load_states{'bareword::filehandles'};
162 }
163}
164
9d763997 165sub _want_extra_env {
c5a67be6 166 if (exists $ENV{PERL_STRICTURES_EXTRA}) {
167 if (_PERL_LT_5_8_4 and $ENV{PERL_STRICTURES_EXTRA}) {
168 die 'PERL_STRICTURES_EXTRA checks are not available on perls older'
169 . "than 5.8.4: please unset \$ENV{PERL_STRICTURES_EXTRA}\n";
394c3a46 170 }
9d763997 171 return $ENV{PERL_STRICTURES_EXTRA} ? 1 : 0;
c5a67be6 172 }
9d763997 173 return undef;
174}
175
176sub _want_extra {
177 my $file = shift;
178 my $want_env = _want_extra_env();
179 return $want_env
180 if defined $want_env;
c5a67be6 181 return (
182 !_PERL_LT_5_8_4
183 and $file =~ /^(?:t|xt|lib|blib)[\\\/]/
184 and defined $Smells_Like_VCS ? $Smells_Like_VCS
185 : ( $Smells_Like_VCS = !!(
186 -e '.git' || -e '.svn' || -e '.hg'
187 || (-e '../../dist.ini'
188 && (-e '../../.git' || -e '../../.svn' || -e '../../.hg' ))
189 ))
190 );
191}
4f219885 192
c5a67be6 193sub _load_extras {
194 my @extras = @_;
8f0df510 195 my @failed;
196 foreach my $mod (@extras) {
197 next
198 if exists $extra_load_states{$mod};
4f219885 199
8f0df510 200 $extra_load_states{$mod} = eval "require $mod; 1;" or do {
201 push @failed, $mod;
488f2966 202
8f0df510 203 #work around 5.8 require bug
204 (my $file = $mod) =~ s|::|/|g;
205 delete $INC{"${file}.pm"};
206 };
207 }
4f219885 208
8f0df510 209 if (@failed) {
210 my $failed = join ' ', @failed;
211 my $extras = join ' ', @extras;
212 print STDERR <<EOE;
ffedb166 213strictures.pm extra testing active but couldn't load all modules. Missing were:
214
215 $failed
216
0925b84b 217Extra testing is auto-enabled in checkouts only, so if you're the author
624cf8bb 218of a strictures-using module you need to run:
653f4377 219
8f0df510 220 cpan $extras
653f4377 221
222but these modules are not required by your users.
084caaf3 223EOE
394c3a46 224 }
225}
226
2271;
228
229__END__
230=head1 NAME
231
232strictures - turn on strict and make all warnings fatal
233
234=head1 SYNOPSIS
235
1c35787c 236 use strictures 2;
394c3a46 237
238is equivalent to
239
240 use strict;
241 use warnings FATAL => 'all';
1c35787c 242 use warnings NONFATAL => qw(
243 exec
244 recursion
245 internal
246 malloc
247 newline
248 experimental
249 deprecated
250 portable
251 );
252 no warnings 'once';
394c3a46 253
5ab06a4d 254except when called from a file which matches:
394c3a46 255
5b2a026b 256 (caller)[1] =~ /^(?:t|xt|lib|blib)[\\\/]/
394c3a46 257
3e14202f 258and when either C<.git>, C<.svn>, or C<.hg> is present in the current directory
259(with the intention of only forcing extra tests on the author side) -- or when
260C<.git>, C<.svn>, or C<.hg> is present two directories up along with
261C<dist.ini> (which would indicate we are in a C<dzil test> operation, via
262L<Dist::Zilla>) -- or when the C<PERL_STRICTURES_EXTRA> environment variable is
263set, in which case
394c3a46 264
1c35787c 265 use strictures 2;
394c3a46 266
267is equivalent to
268
269 use strict;
270 use warnings FATAL => 'all';
1c35787c 271 use warnings NONFATAL => qw(
272 exec
273 recursion
274 internal
275 malloc
276 newline
277 experimental
278 deprecated
279 portable
280 );
281 no warnings 'once';
394c3a46 282 no indirect 'fatal';
653f4377 283 no multidimensional;
284 no bareword::filehandles;
394c3a46 285
3e14202f 286Note that C<PERL_STRICTURES_EXTRA> may at some point add even more tests, with
287only a minor version increase, but any changes to the effect of C<use
288strictures> in normal mode will involve a major version bump.
394c3a46 289
0eb0d037 290If any of the extra testing modules are not present, L<strictures> will
25877bf2 291complain loudly, once, via C<warn()>, and then shut up. But you really
ffedb166 292should consider installing them, they're all great anti-footgun tools.
17b03f2e 293
394c3a46 294=head1 DESCRIPTION
295
296I've been writing the equivalent of this module at the top of my code for
297about a year now. I figured it was time to make it shorter.
298
25877bf2 299Things like the importer in C<use Moose> don't help me because they turn
d8c1c6b2 300warnings on but don't make them fatal -- which from my point of view is
2288278f 301useless because I want an exception to tell me my code isn't warnings-clean.
394c3a46 302
303Any time I see a warning from my code, that indicates a mistake.
304
d8c1c6b2 305Any time my code encounters a mistake, I want a crash -- not spew to STDERR
394c3a46 306and then unknown (and probably undesired) subsequent behaviour.
307
308I also want to ensure that obvious coding mistakes, like indirect object
309syntax (and not so obvious mistakes that cause things to accidentally compile
310as such) get caught, but not at the cost of an XS dependency and not at the
311cost of blowing things up on another machine.
312
0eb0d037 313Therefore, L<strictures> turns on additional checking, but only when it thinks
2288278f 314it's running in a test file in a VCS checkout -- although if this causes
93ae637e 315undesired behaviour this can be overridden by setting the
25877bf2 316C<PERL_STRICTURES_EXTRA> environment variable.
394c3a46 317
318If additional useful author side checks come to mind, I'll add them to the
3e14202f 319C<PERL_STRICTURES_EXTRA> code path only -- this will result in a minor version
320increase (e.g. 1.000000 to 1.001000 (1.1.0) or similar). Any fixes only to the
321mechanism of this code will result in a sub-version increase (e.g. 1.000000 to
3221.000001 (1.0.1)).
394c3a46 323
1c35787c 324=head1 VERSIONS
325
326Depending on the version of strictures requested, different warnings will be
327enabled. If no specific version is requested, the current version's behavior
328will be used. Versions can be requested using perl's standard mechanism:
329
330 use strictures 2;
331
332Or, by passing in a C<version> option:
333
334 use strictures version => 2;
394c3a46 335
1c35787c 336=head2 VERSION 2
394c3a46 337
1c35787c 338Equivalent to:
339
340 use strict;
341 use warnings FATAL => 'all';
342 use warnings NONFATAL => 'deprecated', 'experimental';
343 # and if in dev mode:
344 no indirect 'fatal';
345 no multidimensional;
346 no bareword::filehandles;
347
348=head2 VERSION 1
349
350Equivalent to:
351
352 use strict;
353 use warnings FATAL => 'all';
354 # and if in dev mode:
355 no indirect 'fatal';
356 no multidimensional;
357 no bareword::filehandles;
eae006ee 358
359=head1 METHODS
360
361=head2 import
362
1c35787c 363This method does the setup work described above in L</DESCRIPTION>. Optionally
364accepts a C<version> option to request a specific version's behavior.
eae006ee 365
366=head2 VERSION
367
25877bf2 368This method traps the C<< strictures->VERSION(1) >> call produced by a use line
eae006ee 369with a version number on it and does the version check.
370
f9df7e2e 371=head1 EXTRA TESTING RATIONALE
372
25877bf2 373Every so often, somebody complains that they're deploying via C<git pull>
d8c1c6b2 374and that they don't want L<strictures> to enable itself in this case -- and that
f9df7e2e 375setting C<PERL_STRICTURES_EXTRA> to 0 isn't acceptable (additional ways to
376disable extra testing would be welcome but the discussion never seems to get
377that far).
378
379In order to allow us to skip a couple of stages and get straight to a
380productive conversation, here's my current rationale for turning the
381extra testing on via a heuristic:
382
383The extra testing is all stuff that only ever blows up at compile time;
2288278f 384this is intentional. So the oft-raised concern that it's different code being
d8c1c6b2 385tested is only sort of the case -- none of the modules involved affect the
f9df7e2e 386final optree to my knowledge, so the author gets some additional compile
387time crashes which he/she then fixes, and the rest of the testing is
388completely valid for all environments.
389
d8c1c6b2 390The point of the extra testing -- especially C<no indirect> -- is to catch
f9df7e2e 391mistakes that newbie users won't even realise are mistakes without
392help. For example,
393
394 foo { ... };
395
d8c1c6b2 396where foo is an & prototyped sub that you forgot to import -- this is
9a363fed 397pernicious to track down since all I<seems> fine until it gets called
f9df7e2e 398and you get a crash. Worse still, you can fail to have imported it due
399to a circular require, at which point you have a load order dependent
9a363fed 400bug which I've seen before now I<only> show up in production due to tiny
f9df7e2e 401differences between the production and the development environment. I wrote
402L<http://shadow.cat/blog/matt-s-trout/indirect-but-still-fatal/> to explain
403this particular problem before L<strictures> itself existed.
404
2288278f 405As such, in my experience so far L<strictures>' extra testing has
9a363fed 406I<avoided> production versus development differences, not caused them.
f9df7e2e 407
0eb0d037 408Additionally, L<strictures>' policy is very much "try and provide as much
d8c1c6b2 409protection as possible for newbies -- who won't think about whether there's
410an option to turn on or not" -- so having only the environment variable
f9df7e2e 411is not sufficient to achieve that (I get to explain that you need to add
d8c1c6b2 412C<use strict> at least once a week on freenode #perl -- newbies sometimes
f9df7e2e 413completely skip steps because they don't understand that that step
414is important).
415
d8c1c6b2 416I make no claims that the heuristic is perfect -- it's already been evolved
f9df7e2e 417significantly over time, especially for 1.004 where we changed things to
0eb0d037 418ensure it only fires on files in your checkout (rather than L<strictures>-using
f9df7e2e 419modules you happened to have installed, which was just silly). However, I
420hope the above clarifies why a heuristic approach is not only necessary but
3e14202f 421desirable from a point of view of providing new users with as much safety as
422possible, and will allow any future discussion on the subject to focus on "how
423do we minimise annoyance to people deploying from checkouts intentionally".
f9df7e2e 424
96c8649b 425=head1 SEE ALSO
426
427=over 4
428
429=item *
430
431L<indirect>
432
433=item *
434
435L<multidimensional>
436
437=item *
438
439L<bareword::filehandles>
440
441=back
442
eae006ee 443=head1 COMMUNITY AND SUPPORT
444
445=head2 IRC channel
446
447irc.perl.org #toolchain
448
449(or bug 'mst' in query on there or freenode)
450
451=head2 Git repository
452
453Gitweb is on http://git.shadowcat.co.uk/ and the clone URL is:
454
455 git clone git://git.shadowcat.co.uk/p5sagit/strictures.git
456
91be28bc 457The web interface to the repository is at:
458
459 http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/strictures.git
460
eae006ee 461=head1 AUTHOR
462
d81f898d 463mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
eae006ee 464
465=head1 CONTRIBUTORS
466
8190ff5b 467Karen Etheridge (cpan:ETHER) <ether@cpan.org>
eae006ee 468
04b4a35d 469Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@gmail.com>
470
a79d1096 471haarg - Graham Knop (cpan:HAARG) <haarg@haarg.org>
472
eae006ee 473=head1 COPYRIGHT
474
475Copyright (c) 2010 the strictures L</AUTHOR> and L</CONTRIBUTORS>
476as listed above.
477
478=head1 LICENSE
479
480This library is free software and may be distributed under the same terms
481as perl itself.
482
483=cut