File Coverage

blib/lib/Perl/Critic/TestUtils.pm
Criterion Covered Total %
statement 183 209 87.5
branch 50 86 58.1
condition 5 5 100.0
subroutine 34 37 91.8
pod 14 14 100.0
total 286 351 81.4


line stmt bran cond sub pod time code
1             package Perl::Critic::TestUtils;
2              
3 40     40   1603400 use 5.010001;
  40         237  
4 40     40   247 use strict;
  40         97  
  40         977  
5 40     40   255 use warnings;
  40         94  
  40         1372  
6              
7 40     40   5447 use English qw(-no_match_vars);
  40         36646  
  40         334  
8 40     40   22462 use Readonly;
  40         47925  
  40         2191  
9              
10 40     40   317 use Exporter 'import';
  40         103  
  40         1240  
11              
12 40     40   273 use File::Path ();
  40         114  
  40         828  
13 40     40   241 use File::Spec ();
  40         107  
  40         692  
14 40     40   245 use File::Spec::Unix ();
  40         103  
  40         823  
15 40     40   20740 use File::Temp ();
  40         358642  
  40         1197  
16 40     40   342 use File::Find qw( find );
  40         112  
  40         2996  
17              
18 40     40   20943 use Perl::Critic;
  40         174  
  40         2516  
19 40     40   370 use Perl::Critic::Config;
  40         116  
  40         1110  
20 40     40   277 use Perl::Critic::Exception::Fatal::Generic qw{ &throw_generic };
  40         99  
  40         4280  
21 40     40   332 use Perl::Critic::Exception::Fatal::Internal qw{ &throw_internal };
  40         123  
  40         3442  
22 40     40   366 use Perl::Critic::Utils qw{ :severities :data_conversion policy_long_name };
  40         109  
  40         2041  
23 40     40   7540 use Perl::Critic::PolicyFactory (-test => 1);
  40         116  
  40         428  
24              
25             our $VERSION = '1.146';
26              
27             Readonly::Array our @EXPORT_OK => qw(
28             pcritique pcritique_with_violations
29             critique critique_with_violations
30             fcritique fcritique_with_violations
31             subtests_in_tree
32             should_skip_author_tests
33             get_author_test_skip_message
34             starting_points_including_examples
35             bundled_policy_names
36             names_of_policies_willing_to_work
37             );
38              
39             sub assert_version {
40 40     40 1 7533 my $expected_version = shift;
41              
42 40 50       289 if ( $expected_version ne $Perl::Critic::VERSION ) {
43 0         0 require Carp;
44 0         0 Carp::confess( "Expected Perl::Critic $expected_version but it is actually $Perl::Critic::VERSION" );
45             }
46              
47 40         148 return;
48             }
49              
50             #-----------------------------------------------------------------------------
51             # If the user already has an existing perlcriticrc file, it will get
52             # in the way of these test. This little tweak to ensures that we
53             # don't find the perlcriticrc file.
54              
55             sub block_perlcriticrc {
56 40     40   383 no warnings 'redefine'; ## no critic (ProhibitNoWarnings);
  40         139  
  40         91875  
57 31     31 1 149 *Perl::Critic::UserProfile::_find_profile_path = sub { return }; ## no critic (ProtectPrivateVars)
  19     19   786  
58 19         65 return 1;
59             }
60              
61             #-----------------------------------------------------------------------------
62             # Criticize a code snippet using only one policy. Returns the violations.
63              
64             sub pcritique_with_violations {
65 2635     2635 1 6789 my($policy, $code_ref, $config_ref) = @_;
66 2635         13186 my $c = Perl::Critic->new( -profile => 'NONE' );
67 2635         13550 $c->add_policy(-policy => $policy, -config => $config_ref);
68 2633         11481 return $c->critique($code_ref);
69             }
70              
71             #-----------------------------------------------------------------------------
72             # Criticize a code snippet using only one policy. Returns the number
73             # of violations
74              
75             sub pcritique { ##no critic(ArgUnpacking)
76 23     23 1 19075 return scalar pcritique_with_violations(@_);
77             }
78              
79             #-----------------------------------------------------------------------------
80             # Criticize a code snippet using a specified config. Returns the violations.
81              
82             sub critique_with_violations {
83 32     32 1 131 my ($code_ref, $config_ref) = @_;
84 32         121 my $c = Perl::Critic->new( %{$config_ref} );
  32         267  
85 32         204 return $c->critique($code_ref);
86             }
87              
88             #-----------------------------------------------------------------------------
89             # Criticize a code snippet using a specified config. Returns the
90             # number of violations
91              
92             sub critique { ##no critic(ArgUnpacking)
93 32     32 1 86443 return scalar critique_with_violations(@_);
94             }
95              
96             #-----------------------------------------------------------------------------
97             # Like pcritique_with_violations, but forces a PPI::Document::File context.
98             # The $filename arg is a Unix-style relative path, like 'Foo/Bar.pm'
99              
100             Readonly::Scalar my $TEMP_FILE_PERMISSIONS => oct 700;
101              
102             sub fcritique_with_violations {
103 57     57 1 167 my($policy, $code_ref, $filename, $config_ref) = @_;
104 57         418 my $c = Perl::Critic->new( -profile => 'NONE' );
105 57         329 $c->add_policy(-policy => $policy, -config => $config_ref);
106              
107 57         303 my $dir = File::Temp::tempdir( 'PerlCritic-tmpXXXXXX', TMPDIR => 1 );
108 57   100     21930 $filename ||= 'Temp.pm';
109 57         572 my @fileparts = File::Spec::Unix->splitdir($filename);
110 57 100       197 if (@fileparts > 1) {
111 13         117 my $subdir = File::Spec->catdir($dir, @fileparts[0..$#fileparts-1]);
112 13         2302 File::Path::mkpath($subdir, 0, $TEMP_FILE_PERMISSIONS);
113             }
114 57         623 my $file = File::Spec->catfile($dir, @fileparts);
115 57 50       4406 if (open my $fh, '>', $file) {
116 57         190 print {$fh} ${$code_ref};
  57         152  
  57         1010  
117 57 50       2483 close $fh or throw_generic "unable to close $file: $OS_ERROR";
118             }
119              
120             # Use eval so we can clean up before throwing an exception in case of
121             # error.
122 57         224 my @v = eval {$c->critique($file)};
  57         351  
123 57         9382 my $err = $EVAL_ERROR;
124 57         25268 File::Path::rmtree($dir, 0, 1);
125 57 50       383 if ($err) {
126 0         0 throw_generic $err;
127             }
128 57         1585 return @v;
129             }
130              
131             #-----------------------------------------------------------------------------
132             # Like pcritique, but forces a PPI::Document::File context. The
133             # $filename arg is a Unix-style relative path, like 'Foo/Bar.pm'
134              
135             sub fcritique { ##no critic(ArgUnpacking)
136 27     27 1 18393 return scalar fcritique_with_violations(@_);
137             }
138              
139             # Note: $include_extras is not documented in the POD because I'm not
140             # committing to the interface yet.
141             sub subtests_in_tree {
142 1     1 1 4 my ($start, $include_extras) = @_;
143              
144 1         2 my %subtests;
145              
146             find(
147             {
148             wanted => sub {
149 219 100   219   5729 return if not -f;
150              
151 192         1332 my ($fileroot) = m{(.+)[.]run\z}xms;
152              
153 192 100       1589 return if not $fileroot;
154              
155 139         1165 my @pathparts = File::Spec->splitdir($fileroot);
156 139 50       398 if (@pathparts < 2) {
157 0         0 throw_internal 'confusing policy test filename ' . $_;
158             }
159              
160 139         472 my $policy = join q{::}, @pathparts[-2, -1]; ## no critic (MagicNumbers)
161              
162 139         334 my $globals = _globals_from_file( $_ );
163 139 50       444 if ( my $prerequisites = $globals->{prerequisites} ) {
164 0         0 foreach my $prerequisite ( keys %{$prerequisites} ) {
  0         0  
165 0 0       0 eval "require $prerequisite; 1" or return;
166             }
167             }
168              
169 139         339 my @subtests = _subtests_from_file( $_ );
170              
171 139 50       357 if ($include_extras) {
172 139         946 $subtests{$policy} =
173             { subtests => [ @subtests ], globals => $globals };
174             }
175             else {
176 0         0 $subtests{$policy} = [ @subtests ];
177             }
178              
179 139         1731 return;
180             },
181 1         129 no_chdir => 1,
182             },
183             $start
184             );
185              
186 1         16 return \%subtests;
187             }
188              
189             # Answer whether author test should be run.
190             #
191             # Note: this code is duplicated in
192             # t/tlib/Perl/Critic/TestUtilitiesWithMinimalDependencies.pm.
193             # If you change this here, make sure to change it there.
194              
195             sub should_skip_author_tests {
196             return not $ENV{TEST_AUTHOR_PERL_CRITIC}
197 0     0 1 0 }
198              
199             sub get_author_test_skip_message {
200             ## no critic (RequireInterpolation);
201 0     0 1 0 return 'Author test. Set $ENV{TEST_AUTHOR_PERL_CRITIC} to a true value to run.';
202             }
203              
204              
205             sub starting_points_including_examples {
206 0 0   0 1 0 return (-e 'blib' ? 'blib' : 'lib', 'examples');
207             }
208              
209             sub _globals_from_file {
210 139     139   231 my $test_file = shift;
211              
212 139         483 my %valid_keys = hashify qw< prerequisites >;
213              
214 139 50       1844 return if -z $test_file; # Skip if the Policy has a regular .t file.
215              
216 139         349 my %globals;
217              
218 139 50       5101 open my $handle, '<', $test_file ## no critic (RequireBriefOpen)
219             or throw_internal "Couldn't open $test_file: $OS_ERROR";
220              
221 139         3394 while ( my $line = <$handle> ) {
222 33882         44735 chomp;
223              
224 33882 50       85826 if (
225             my ($key,$value) =
226             $line =~ m<\A [#][#] [ ] global [ ] (\S+) (?:\s+(.+))? >xms
227             ) {
228 0 0       0 next if not $key;
229 0 0       0 if ( not $valid_keys{$key} ) {
230 0         0 throw_internal "Unknown global key $key in $test_file";
231             }
232              
233 0 0       0 if ( $key eq 'prerequisites' ) {
234 0         0 $value = { hashify( words_from_string($value) ) };
235             }
236 0         0 $globals{$key} = $value;
237             }
238             }
239 139 50       1566 close $handle or throw_generic "unable to close $test_file: $OS_ERROR";
240              
241 139         902 return \%globals;
242             }
243              
244             # The internal representation of a subtest is just a hash with some
245             # named keys. It could be an object with accessors for safety's sake,
246             # but at this point I don't see why.
247             sub _subtests_from_file {
248 139     139   280 my $test_file = shift;
249              
250 139         496 my %valid_keys = hashify qw( name failures parms TODO error filename optional_modules );
251              
252 139 50       2039 return if -z $test_file; # Skip if the Policy has a regular .t file.
253              
254 139 50       4565 open my $fh, '<', $test_file ## no critic (RequireBriefOpen)
255             or throw_internal "Couldn't open $test_file: $OS_ERROR";
256              
257 139         380 my @subtests;
258              
259 139         245 my $incode = 0;
260 139         244 my $cut_in_code = 0;
261 139         278 my $subtest;
262             my $lineno;
263 139         2230 while ( <$fh> ) {
264 33882         47235 ++$lineno;
265 33882         45848 chomp;
266 33882         60398 my $inheader = /^## name/ .. /^## cut/; ## no critic (ExtendedFormatting LineBoundaryMatching DotMatchAnything)
267              
268 33882         51736 my $line = $_;
269              
270 33882 100       59157 if ( $inheader ) {
    100          
    50          
271 9245 50       22464 $line =~ m/\A [#]/xms or throw_internal "Code before cut: $test_file";
272 9245         33383 my ($key,$value) = $line =~ m/\A [#][#] [ ] (\S+) (?:\s+(.+))? /xms;
273 9245 100       18940 next if !$key;
274 9238 100       22358 next if $key eq 'cut';
275 6596 50       13261 if ( not $valid_keys{$key} ) {
276 0         0 throw_internal "Unknown key $key in $test_file";
277             }
278              
279 6596 100       11636 if ( $key eq 'name' ) {
280 2642 100       5154 if ( $subtest ) { # Stash any current subtest
281 2503         5154 push @subtests, _finalize_subtest( $subtest );
282 2503         3881 undef $subtest;
283             }
284 2642         5231 $subtest->{lineno} = $lineno;
285 2642         3803 $incode = 0;
286 2642         3848 $cut_in_code = 0;
287             }
288 6596 50       11089 if ($incode) {
289 0         0 throw_internal "Header line found while still in code: $test_file";
290             }
291 6596         24880 $subtest->{$key} = $value;
292             }
293             elsif ( $subtest ) {
294 24630         31151 $incode = 1;
295 24630   100     81609 $cut_in_code ||= $line =~ m/ \A [#][#] [ ] cut \z /smx;
296             # Don't start a subtest if we're not in one.
297             # Don't add to the test if we have seen a '## cut'.
298 24630 100       41587 $cut_in_code or push @{$subtest->{code}}, $line;
  24608         75139  
299             }
300             elsif (@subtests) {
301             ## don't complain if we have not yet hit the first test
302 0         0 throw_internal "Got some code but I'm not in a subtest: $test_file";
303             }
304             }
305 139 50       1690 close $fh or throw_generic "unable to close $test_file: $OS_ERROR";
306 139 50       443 if ( $subtest ) {
307 139 50       311 if ( $incode ) {
308 139         385 push @subtests, _finalize_subtest( $subtest );
309             }
310             else {
311 0         0 throw_internal "Incomplete subtest in $test_file";
312             }
313             }
314              
315 139         1090 return @subtests;
316             }
317              
318             sub _finalize_subtest {
319 2642     2642   3967 my $subtest = shift;
320              
321 2642 50       4718 if ( $subtest->{code} ) {
322 2642         3840 $subtest->{code} = join "\n", @{$subtest->{code}};
  2642         9878  
323             }
324             else {
325 0         0 throw_internal "$subtest->{name} has no code lines";
326             }
327 2642 50       7612 if ( !defined $subtest->{failures} ) {
328 0         0 throw_internal "$subtest->{name} does not specify failures";
329             }
330 2642 100       5166 if ($subtest->{parms}) {
331 1257         61676 $subtest->{parms} = eval $subtest->{parms}; ## no critic(StringyEval)
332 1257 50       4649 if ($EVAL_ERROR) {
333 0         0 throw_internal
334             "$subtest->{name} has an error in the 'parms' property:\n"
335             . $EVAL_ERROR;
336             }
337 1257 50       3522 if ('HASH' ne ref $subtest->{parms}) {
338 0         0 throw_internal
339             "$subtest->{name} 'parms' did not evaluate to a hashref";
340             }
341             } else {
342 1385         2622 $subtest->{parms} = {};
343             }
344              
345 2642 100       5584 if (defined $subtest->{error}) {
346 2 50       17 if ( $subtest->{error} =~ m{ \A / (.*) / \z }xms) {
347 2         7 $subtest->{error} = eval {qr/$1/}; ## no critic (ExtendedFormatting LineBoundaryMatching DotMatchAnything)
  2         39  
348 2 50       8 if ($EVAL_ERROR) {
349 0         0 throw_internal
350             "$subtest->{name} 'error' has a malformed regular expression";
351             }
352             }
353             }
354              
355 2642         4958 return $subtest;
356             }
357              
358             sub bundled_policy_names {
359 6     6 1 5595 require ExtUtils::Manifest;
360 6         37123 my $manifest = ExtUtils::Manifest::maniread();
361 6         34247 my @policy_paths = map {m{\A lib/(Perl/Critic/Policy/.*).pm \z}xms} keys %{$manifest};
  2574         4110  
  6         364  
362 6         104 my @policies = map { join q{::}, split m{/}xms } @policy_paths;
  870         2963  
363 6         433 my @sorted_policies = sort @policies;
364 6         755 return @sorted_policies;
365             }
366              
367             sub names_of_policies_willing_to_work {
368 1     1 1 12 my %configuration = @_;
369              
370 1         16 my @policies_willing_to_work =
371             Perl::Critic::Config
372             ->new( %configuration )
373             ->policies();
374              
375 1         107 return map { ref } @policies_willing_to_work;
  143         1649  
376             }
377              
378             1;
379              
380             __END__
381              
382             #-----------------------------------------------------------------------------
383              
384             =pod
385              
386             =for stopwords RCS subtest subtests
387              
388             =head1 NAME
389              
390             Perl::Critic::TestUtils - Utility functions for testing new Policies.
391              
392              
393             =head1 INTERFACE SUPPORT
394              
395             This is considered to be a public module. Any changes to its
396             interface will go through a deprecation cycle.
397              
398              
399             =head1 SYNOPSIS
400              
401             use Perl::Critic::TestUtils qw(critique pcritique fcritique);
402              
403             my $code = '<<END_CODE';
404             package Foo::Bar;
405             $foo = frobulator();
406             $baz = $foo ** 2;
407             1;
408             END_CODE
409              
410             # Critique code against all loaded policies...
411             my $perl_critic_config = { -severity => 2 };
412             my $violation_count = critique( \$code, $perl_critic_config);
413              
414             # Critique code against one policy...
415             my $custom_policy = 'Miscellanea::ProhibitFrobulation'
416             my $violation_count = pcritique( $custom_policy, \$code );
417              
418             # Critique code against one filename-related policy...
419             my $custom_policy = 'Modules::RequireFilenameMatchesPackage'
420             my $violation_count = fcritique( $custom_policy, \$code, 'Foo/Bar.pm' );
421              
422              
423             =head1 DESCRIPTION
424              
425             This module is used by L<Perl::Critic|Perl::Critic> only for
426             self-testing. It provides a few handy subroutines for testing new
427             Perl::Critic::Policy modules. Look at the test programs that ship with
428             Perl::Critic for more examples of how to use these subroutines.
429              
430              
431             =head1 EXPORTS
432              
433             =over
434              
435             =item assert_version( $version )
436              
437             Asserts that the C<$version> passed matches the version of Perl::Critic.
438              
439              
440             =item block_perlcriticrc()
441              
442             If a user has a F<~/.perlcriticrc> file, this can interfere with
443             testing. This handy method disables the search for that file --
444             simply call it at the top of your F<.t> program. Note that this is
445             not easily reversible, but that should not matter.
446              
447              
448             =item critique_with_violations( $code_string_ref, $config_ref )
449              
450             Test a block of code against the specified Perl::Critic::Config
451             instance (or C<undef> for the default). Returns the violations that
452             occurred.
453              
454              
455             =item critique( $code_string_ref, $config_ref )
456              
457             Test a block of code against the specified Perl::Critic::Config
458             instance (or C<undef> for the default). Returns the number of
459             violations that occurred.
460              
461              
462             =item pcritique_with_violations( $policy_name, $code_string_ref, $config_ref )
463              
464             Like C<critique_with_violations()>, but tests only a single policy
465             instead of the whole bunch.
466              
467              
468             =item pcritique( $policy_name, $code_string_ref, $config_ref )
469              
470             Like C<critique()>, but tests only a single policy instead of the
471             whole bunch.
472              
473              
474             =item fcritique_with_violations( $policy_name, $code_string_ref, $filename, $config_ref )
475              
476             Like C<pcritique_with_violations()>, but pretends that the code was
477             loaded from the specified filename. This is handy for testing
478             policies like C<Modules::RequireFilenameMatchesPackage> which care
479             about the filename that the source derived from.
480              
481             The C<$filename> parameter must be a relative path, not absolute. The
482             file and all necessary subdirectories will be created via
483             L<File::Temp|File::Temp> and will be automatically deleted.
484              
485              
486             =item fcritique( $policy_name, $code_string_ref, $filename, $config_ref )
487              
488             Like C<pcritique()>, but pretends that the code was loaded from the
489             specified filename. This is handy for testing policies like
490             C<Modules::RequireFilenameMatchesPackage> which care about the
491             filename that the source derived from.
492              
493             The C<$filename> parameter must be a relative path, not absolute. The
494             file and all necessary subdirectories will be created via
495             L<File::Temp|File::Temp> and will be automatically deleted.
496              
497              
498             =item subtests_in_tree( $dir )
499              
500             Searches the specified directory recursively for F<.run> files. Each
501             one found is parsed and a hash-of-list-of-hashes is returned. The
502             outer hash is keyed on policy short name, like
503             C<Modules::RequireEndWithOne>. The inner hash specifies a single test
504             to be handed to C<pcritique()> or C<fcritique()>, including the code
505             string, test name, etc. See below for the syntax of the F<.run>
506             files.
507              
508              
509             =item should_skip_author_tests()
510              
511             Answers whether author tests should run.
512              
513              
514             =item get_author_test_skip_message()
515              
516             Returns a string containing the message that should be emitted when a
517             test is skipped due to it being an author test when author tests are
518             not enabled.
519              
520              
521             =item starting_points_including_examples()
522              
523             Returns a list of the directories contain code that needs to be tested
524             when it is desired that the examples be included.
525              
526              
527             =item bundled_policy_names()
528              
529             Returns a list of Policy packages that come bundled with this package.
530             This functions by searching F<MANIFEST> for
531             F<lib/Perl/Critic/Policy/*.pm> and converts the results to package
532             names.
533              
534              
535             =item names_of_policies_willing_to_work( %configuration )
536              
537             Returns a list of the packages of policies that are willing to
538             function on the current system using the specified configuration.
539              
540              
541             =back
542              
543              
544             =head1 F<.run> file information
545              
546             Testing a policy follows a very simple pattern:
547              
548             * Policy name
549             * Subtest name
550             * Optional parameters
551             * Number of failures expected
552             * Optional exception expected
553             * Optional filename for code
554              
555             Each of the subtests for a policy is collected in a single F<.run>
556             file, with test properties as comments in front of each code block
557             that describes how we expect Perl::Critic to react to the code. For
558             example, say you have a policy called Variables::ProhibitVowels:
559              
560             (In file t/Variables/ProhibitVowels.run)
561              
562             ## name Basics
563             ## failures 1
564             ## cut
565              
566             my $vrbl_nm = 'foo'; # Good, vowel-free name
567             my $wango = 12; # Bad, pronouncable name
568              
569              
570             ## name Sometimes Y
571             ## failures 1
572             ## cut
573              
574             my $yllw = 0; # "y" not a vowel here
575             my $rhythm = 12; # But here it is
576              
577             These are called "subtests", and two are shown above. The beauty of
578             incorporating multiple subtests in a file is that the F<.run> is
579             itself a (mostly) valid Perl file, and not hidden in a HEREDOC, so
580             your editor's color-coding still works, and it is much easier to work
581             with the code and the POD.
582              
583             If you need to pass any configuration parameters for your subtest, do
584             so like this:
585              
586             ## parms { allow_y => '0' }
587              
588             Note that all the values in this hash must be strings because that's
589             what Perl::Critic will hand you from a F<.perlcriticrc>.
590              
591             If it's a TODO subtest (probably because of some weird corner of PPI
592             that we exercised that Adam is getting around to fixing, right?), then
593             make a C<##TODO> entry.
594              
595             ## TODO Should pass when PPI 1.xxx comes out
596              
597             If the code is expected to trigger an exception in the policy,
598             indicate that like so:
599              
600             ## error 1
601              
602             If you want to test the error message, mark it with C</.../> to
603             indicate a C<like()> test:
604              
605             ## error /Can't load Foo::Bar/
606              
607             If the policy you are testing cares about the filename of the code,
608             you can indicate that C<fcritique> should be used like so (see
609             C<fcritique> for more details):
610              
611             ## filename lib/Foo/Bar.pm
612              
613             The value of C<parms> will get C<eval>ed and passed to C<pcritique()>,
614             so be careful.
615              
616             In general, a subtest document runs from the C<## cut> that starts it to
617             either the next C<## name> or the end of the file. In very rare circumstances
618             you may need to end the test document earlier. A second C<## cut> will do
619             this. The only known need for this is in
620             F<t/Miscellanea/RequireRcsKeywords.run>, where it is used to prevent the RCS
621             keywords in the file footer from producing false positives or negatives in the
622             last test.
623              
624             Note that nowhere within the F<.run> file itself do you specify the
625             policy that you're testing. That's implicit within the filename.
626              
627              
628             =head1 BUGS AND CAVEATS AND TODO ITEMS
629              
630             Test that we have a t/*/*.run for each lib/*/*.pm
631              
632             Allow us to specify the nature of the failures, and which one. If
633             there are 15 lines of code, and six of them fail, how do we know
634             they're the right six?
635              
636              
637             =head1 AUTHOR
638              
639             Chris Dolan <cdolan@cpan.org>
640             and the rest of the L<Perl::Critic|Perl::Critic> team.
641              
642              
643             =head1 COPYRIGHT
644              
645             Copyright (c) 2005-2011 Chris Dolan.
646              
647             This program is free software; you can redistribute it and/or modify
648             it under the same terms as Perl itself. The full text of this license
649             can be found in the LICENSE file included with this module.
650              
651             =cut
652              
653             # Local Variables:
654             # mode: cperl
655             # cperl-indent-level: 4
656             # fill-column: 78
657             # indent-tabs-mode: nil
658             # c-indentation-style: bsd
659             # End:
660             # ex: set ts=8 sts=4 sw=4 tw=78 ft=perl expandtab shiftround :