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