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