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