use different mechanism for disabling some warnings
[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);
d50343b9 151 warnings->unimport(FATAL => @V2_NONFATAL);
152 warnings->import(@V2_NONFATAL);
23c0b85d 153 warnings->unimport(@V2_DISABLE);
154
155 if (_want_extra($opts->{file})) {
156 _load_extras(qw(indirect multidimensional bareword::filehandles));
157 indirect->unimport(':fatal')
158 if $extra_load_states{indirect};
159 multidimensional->unimport
160 if $extra_load_states{multidimensional};
161 bareword::filehandles->unimport
162 if $extra_load_states{'bareword::filehandles'};
163 }
164}
165
9d763997 166sub _want_extra_env {
c5a67be6 167 if (exists $ENV{PERL_STRICTURES_EXTRA}) {
168 if (_PERL_LT_5_8_4 and $ENV{PERL_STRICTURES_EXTRA}) {
169 die 'PERL_STRICTURES_EXTRA checks are not available on perls older'
170 . "than 5.8.4: please unset \$ENV{PERL_STRICTURES_EXTRA}\n";
394c3a46 171 }
9d763997 172 return $ENV{PERL_STRICTURES_EXTRA} ? 1 : 0;
c5a67be6 173 }
9d763997 174 return undef;
175}
176
177sub _want_extra {
178 my $file = shift;
179 my $want_env = _want_extra_env();
180 return $want_env
181 if defined $want_env;
c5a67be6 182 return (
183 !_PERL_LT_5_8_4
184 and $file =~ /^(?:t|xt|lib|blib)[\\\/]/
185 and defined $Smells_Like_VCS ? $Smells_Like_VCS
186 : ( $Smells_Like_VCS = !!(
187 -e '.git' || -e '.svn' || -e '.hg'
188 || (-e '../../dist.ini'
189 && (-e '../../.git' || -e '../../.svn' || -e '../../.hg' ))
190 ))
191 );
192}
4f219885 193
c5a67be6 194sub _load_extras {
195 my @extras = @_;
8f0df510 196 my @failed;
197 foreach my $mod (@extras) {
198 next
199 if exists $extra_load_states{$mod};
4f219885 200
8f0df510 201 $extra_load_states{$mod} = eval "require $mod; 1;" or do {
202 push @failed, $mod;
488f2966 203
8f0df510 204 #work around 5.8 require bug
205 (my $file = $mod) =~ s|::|/|g;
206 delete $INC{"${file}.pm"};
207 };
208 }
4f219885 209
8f0df510 210 if (@failed) {
211 my $failed = join ' ', @failed;
212 my $extras = join ' ', @extras;
213 print STDERR <<EOE;
ffedb166 214strictures.pm extra testing active but couldn't load all modules. Missing were:
215
216 $failed
217
0925b84b 218Extra testing is auto-enabled in checkouts only, so if you're the author
624cf8bb 219of a strictures-using module you need to run:
653f4377 220
8f0df510 221 cpan $extras
653f4377 222
223but these modules are not required by your users.
084caaf3 224EOE
394c3a46 225 }
226}
227
2281;
229
230__END__
231=head1 NAME
232
233strictures - turn on strict and make all warnings fatal
234
235=head1 SYNOPSIS
236
1c35787c 237 use strictures 2;
394c3a46 238
239is equivalent to
240
241 use strict;
242 use warnings FATAL => 'all';
1c35787c 243 use warnings NONFATAL => qw(
244 exec
245 recursion
246 internal
247 malloc
248 newline
249 experimental
250 deprecated
251 portable
252 );
253 no warnings 'once';
394c3a46 254
5ab06a4d 255except when called from a file which matches:
394c3a46 256
5b2a026b 257 (caller)[1] =~ /^(?:t|xt|lib|blib)[\\\/]/
394c3a46 258
3e14202f 259and when either C<.git>, C<.svn>, or C<.hg> is present in the current directory
260(with the intention of only forcing extra tests on the author side) -- or when
261C<.git>, C<.svn>, or C<.hg> is present two directories up along with
262C<dist.ini> (which would indicate we are in a C<dzil test> operation, via
263L<Dist::Zilla>) -- or when the C<PERL_STRICTURES_EXTRA> environment variable is
264set, in which case
394c3a46 265
1c35787c 266 use strictures 2;
394c3a46 267
268is equivalent to
269
270 use strict;
271 use warnings FATAL => 'all';
1c35787c 272 use warnings NONFATAL => qw(
273 exec
274 recursion
275 internal
276 malloc
277 newline
278 experimental
279 deprecated
280 portable
281 );
282 no warnings 'once';
394c3a46 283 no indirect 'fatal';
653f4377 284 no multidimensional;
285 no bareword::filehandles;
394c3a46 286
3e14202f 287Note that C<PERL_STRICTURES_EXTRA> may at some point add even more tests, with
288only a minor version increase, but any changes to the effect of C<use
289strictures> in normal mode will involve a major version bump.
394c3a46 290
0eb0d037 291If any of the extra testing modules are not present, L<strictures> will
25877bf2 292complain loudly, once, via C<warn()>, and then shut up. But you really
ffedb166 293should consider installing them, they're all great anti-footgun tools.
17b03f2e 294
394c3a46 295=head1 DESCRIPTION
296
297I've been writing the equivalent of this module at the top of my code for
298about a year now. I figured it was time to make it shorter.
299
25877bf2 300Things like the importer in C<use Moose> don't help me because they turn
d8c1c6b2 301warnings on but don't make them fatal -- which from my point of view is
2288278f 302useless because I want an exception to tell me my code isn't warnings-clean.
394c3a46 303
304Any time I see a warning from my code, that indicates a mistake.
305
d8c1c6b2 306Any time my code encounters a mistake, I want a crash -- not spew to STDERR
394c3a46 307and then unknown (and probably undesired) subsequent behaviour.
308
309I also want to ensure that obvious coding mistakes, like indirect object
310syntax (and not so obvious mistakes that cause things to accidentally compile
311as such) get caught, but not at the cost of an XS dependency and not at the
312cost of blowing things up on another machine.
313
0eb0d037 314Therefore, L<strictures> turns on additional checking, but only when it thinks
2288278f 315it's running in a test file in a VCS checkout -- although if this causes
93ae637e 316undesired behaviour this can be overridden by setting the
25877bf2 317C<PERL_STRICTURES_EXTRA> environment variable.
394c3a46 318
319If additional useful author side checks come to mind, I'll add them to the
3e14202f 320C<PERL_STRICTURES_EXTRA> code path only -- this will result in a minor version
321increase (e.g. 1.000000 to 1.001000 (1.1.0) or similar). Any fixes only to the
322mechanism of this code will result in a sub-version increase (e.g. 1.000000 to
3231.000001 (1.0.1)).
394c3a46 324
1c35787c 325=head1 VERSIONS
326
327Depending on the version of strictures requested, different warnings will be
328enabled. If no specific version is requested, the current version's behavior
329will be used. Versions can be requested using perl's standard mechanism:
330
331 use strictures 2;
332
333Or, by passing in a C<version> option:
334
335 use strictures version => 2;
394c3a46 336
1c35787c 337=head2 VERSION 2
394c3a46 338
1c35787c 339Equivalent to:
340
341 use strict;
342 use warnings FATAL => 'all';
343 use warnings NONFATAL => 'deprecated', 'experimental';
344 # and if in dev mode:
345 no indirect 'fatal';
346 no multidimensional;
347 no bareword::filehandles;
348
349=head2 VERSION 1
350
351Equivalent to:
352
353 use strict;
354 use warnings FATAL => 'all';
355 # and if in dev mode:
356 no indirect 'fatal';
357 no multidimensional;
358 no bareword::filehandles;
eae006ee 359
360=head1 METHODS
361
362=head2 import
363
1c35787c 364This method does the setup work described above in L</DESCRIPTION>. Optionally
365accepts a C<version> option to request a specific version's behavior.
eae006ee 366
367=head2 VERSION
368
25877bf2 369This method traps the C<< strictures->VERSION(1) >> call produced by a use line
eae006ee 370with a version number on it and does the version check.
371
f9df7e2e 372=head1 EXTRA TESTING RATIONALE
373
25877bf2 374Every so often, somebody complains that they're deploying via C<git pull>
d8c1c6b2 375and that they don't want L<strictures> to enable itself in this case -- and that
f9df7e2e 376setting C<PERL_STRICTURES_EXTRA> to 0 isn't acceptable (additional ways to
377disable extra testing would be welcome but the discussion never seems to get
378that far).
379
380In order to allow us to skip a couple of stages and get straight to a
381productive conversation, here's my current rationale for turning the
382extra testing on via a heuristic:
383
384The extra testing is all stuff that only ever blows up at compile time;
2288278f 385this is intentional. So the oft-raised concern that it's different code being
d8c1c6b2 386tested is only sort of the case -- none of the modules involved affect the
f9df7e2e 387final optree to my knowledge, so the author gets some additional compile
388time crashes which he/she then fixes, and the rest of the testing is
389completely valid for all environments.
390
d8c1c6b2 391The point of the extra testing -- especially C<no indirect> -- is to catch
f9df7e2e 392mistakes that newbie users won't even realise are mistakes without
393help. For example,
394
395 foo { ... };
396
d8c1c6b2 397where foo is an & prototyped sub that you forgot to import -- this is
9a363fed 398pernicious to track down since all I<seems> fine until it gets called
f9df7e2e 399and you get a crash. Worse still, you can fail to have imported it due
400to a circular require, at which point you have a load order dependent
9a363fed 401bug which I've seen before now I<only> show up in production due to tiny
f9df7e2e 402differences between the production and the development environment. I wrote
403L<http://shadow.cat/blog/matt-s-trout/indirect-but-still-fatal/> to explain
404this particular problem before L<strictures> itself existed.
405
2288278f 406As such, in my experience so far L<strictures>' extra testing has
9a363fed 407I<avoided> production versus development differences, not caused them.
f9df7e2e 408
0eb0d037 409Additionally, L<strictures>' policy is very much "try and provide as much
d8c1c6b2 410protection as possible for newbies -- who won't think about whether there's
411an option to turn on or not" -- so having only the environment variable
f9df7e2e 412is not sufficient to achieve that (I get to explain that you need to add
d8c1c6b2 413C<use strict> at least once a week on freenode #perl -- newbies sometimes
f9df7e2e 414completely skip steps because they don't understand that that step
415is important).
416
d8c1c6b2 417I make no claims that the heuristic is perfect -- it's already been evolved
f9df7e2e 418significantly over time, especially for 1.004 where we changed things to
0eb0d037 419ensure it only fires on files in your checkout (rather than L<strictures>-using
f9df7e2e 420modules you happened to have installed, which was just silly). However, I
421hope the above clarifies why a heuristic approach is not only necessary but
3e14202f 422desirable from a point of view of providing new users with as much safety as
423possible, and will allow any future discussion on the subject to focus on "how
424do we minimise annoyance to people deploying from checkouts intentionally".
f9df7e2e 425
96c8649b 426=head1 SEE ALSO
427
428=over 4
429
430=item *
431
432L<indirect>
433
434=item *
435
436L<multidimensional>
437
438=item *
439
440L<bareword::filehandles>
441
442=back
443
eae006ee 444=head1 COMMUNITY AND SUPPORT
445
446=head2 IRC channel
447
448irc.perl.org #toolchain
449
450(or bug 'mst' in query on there or freenode)
451
452=head2 Git repository
453
454Gitweb is on http://git.shadowcat.co.uk/ and the clone URL is:
455
456 git clone git://git.shadowcat.co.uk/p5sagit/strictures.git
457
91be28bc 458The web interface to the repository is at:
459
460 http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=p5sagit/strictures.git
461
eae006ee 462=head1 AUTHOR
463
d81f898d 464mst - Matt S. Trout (cpan:MSTROUT) <mst@shadowcat.co.uk>
eae006ee 465
466=head1 CONTRIBUTORS
467
8190ff5b 468Karen Etheridge (cpan:ETHER) <ether@cpan.org>
eae006ee 469
04b4a35d 470Mithaldu - Christian Walde (cpan:MITHALDU) <walde.christian@gmail.com>
471
a79d1096 472haarg - Graham Knop (cpan:HAARG) <haarg@haarg.org>
473
eae006ee 474=head1 COPYRIGHT
475
476Copyright (c) 2010 the strictures L</AUTHOR> and L</CONTRIBUTORS>
477as listed above.
478
479=head1 LICENSE
480
481This library is free software and may be distributed under the same terms
482as perl itself.
483
484=cut