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