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