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   1584627 use 5.010001;
  40         240  
4 40     40   243 use strict;
  40         119  
  40         976  
5 40     40   231 use warnings;
  40         112  
  40         1456  
6              
7 40     40   5382 use English qw(-no_match_vars);
  40         36971  
  40         2910  
8 40     40   22116 use Readonly;
  40         47847  
  40         2192  
9              
10 40     40   293 use Exporter 'import';
  40         120  
  40         1333  
11              
12 40     40   273 use File::Path ();
  40         128  
  40         760  
13 40     40   218 use File::Spec ();
  40         111  
  40         690  
14 40     40   235 use File::Spec::Unix ();
  40         101  
  40         732  
15 40     40   21542 use File::Temp ();
  40         360868  
  40         1218  
16 40     40   294 use File::Find qw( find );
  40         124  
  40         2957  
17              
18 40     40   20925 use Perl::Critic;
  40         180  
  40         2234  
19 40     40   328 use Perl::Critic::Config;
  40         127  
  40         1135  
20 40     40   245 use Perl::Critic::Exception::Fatal::Generic qw{ &throw_generic };
  40         132  
  40         4320  
21 40     40   342 use Perl::Critic::Exception::Fatal::Internal qw{ &throw_internal };
  40         133  
  40         3544  
22 40     40   355 use Perl::Critic::Utils qw{ :severities :data_conversion policy_long_name };
  40         117  
  40         2028  
23 40     40   7608 use Perl::Critic::PolicyFactory (-test => 1);
  40         130  
  40         360  
24              
25             our $VERSION = '1.148';
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 7882 my $expected_version = shift;
41              
42 40 50       258 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         141 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   411 no warnings 'redefine'; ## no critic (ProhibitNoWarnings);
  40         149  
  40         90993  
57 31     31 1 156 *Perl::Critic::UserProfile::_find_profile_path = sub { return }; ## no critic (ProtectPrivateVars)
  19     19   803  
58 19         69 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 6384 my($policy, $code_ref, $config_ref) = @_;
66 2635         12568 my $c = Perl::Critic->new( -profile => 'NONE' );
67 2635         12881 $c->add_policy(-policy => $policy, -config => $config_ref);
68 2633         10404 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 21031 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 193 my ($code_ref, $config_ref) = @_;
84 32         86 my $c = Perl::Critic->new( %{$config_ref} );
  32         267  
85 32         207 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 89654 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 165 my($policy, $code_ref, $filename, $config_ref) = @_;
104 57         406 my $c = Perl::Critic->new( -profile => 'NONE' );
105 57         282 $c->add_policy(-policy => $policy, -config => $config_ref);
106              
107 57         262 my $dir = File::Temp::tempdir( 'PerlCritic-tmpXXXXXX', TMPDIR => 1 );
108 57   100     20677 $filename ||= 'Temp.pm';
109 57         544 my @fileparts = File::Spec::Unix->splitdir($filename);
110 57 100       186 if (@fileparts > 1) {
111 13         110 my $subdir = File::Spec->catdir($dir, @fileparts[0..$#fileparts-1]);
112 13         2236 File::Path::mkpath($subdir, 0, $TEMP_FILE_PERMISSIONS);
113             }
114 57         599 my $file = File::Spec->catfile($dir, @fileparts);
115 57 50       4286 if (open my $fh, '>', $file) {
116 57         184 print {$fh} ${$code_ref};
  57         136  
  57         1079  
117 57 50       2342 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         316  
123 57         9447 my $err = $EVAL_ERROR;
124 57         24346 File::Path::rmtree($dir, 0, 1);
125 57 50       349 if ($err) {
126 0         0 throw_generic $err;
127             }
128 57         1420 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 17807 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 5 my ($start, $include_extras) = @_;
143              
144 1         3 my %subtests;
145              
146             find(
147             {
148             wanted => sub {
149 219 100   219   5871 return if not -f;
150              
151 192         1299 my ($fileroot) = m{(.+)[.]run\z}xms;
152              
153 192 100       1572 return if not $fileroot;
154              
155 139         1175 my @pathparts = File::Spec->splitdir($fileroot);
156 139 50       402 if (@pathparts < 2) {
157 0         0 throw_internal 'confusing policy test filename ' . $_;
158             }
159              
160 139         485 my $policy = join q{::}, @pathparts[-2, -1]; ## no critic (MagicNumbers)
161              
162 139         315 my $globals = _globals_from_file( $_ );
163 139 50       442 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         330 my @subtests = _subtests_from_file( $_ );
170              
171 139 50       325 if ($include_extras) {
172 139         924 $subtests{$policy} =
173             { subtests => [ @subtests ], globals => $globals };
174             }
175             else {
176 0         0 $subtests{$policy} = [ @subtests ];
177             }
178              
179 139         1706 return;
180             },
181 1         122 no_chdir => 1,
182             },
183             $start
184             );
185              
186 1         20 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   272 my $test_file = shift;
211              
212 139         489 my %valid_keys = hashify qw< prerequisites >;
213              
214 139 50       1867 return if -z $test_file; # Skip if the Policy has a regular .t file.
215              
216 139         350 my %globals;
217              
218 139 50       4940 open my $handle, '<', $test_file ## no critic (RequireBriefOpen)
219             or throw_internal "Couldn't open $test_file: $OS_ERROR";
220              
221 139         3422 while ( my $line = <$handle> ) {
222 33882         44343 chomp;
223              
224 33882 50       86224 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       1525 close $handle or throw_generic "unable to close $test_file: $OS_ERROR";
240              
241 139         938 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   266 my $test_file = shift;
249              
250 139         523 my %valid_keys = hashify qw( name failures parms TODO error filename optional_modules );
251              
252 139 50       2042 return if -z $test_file; # Skip if the Policy has a regular .t file.
253              
254 139 50       4588 open my $fh, '<', $test_file ## no critic (RequireBriefOpen)
255             or throw_internal "Couldn't open $test_file: $OS_ERROR";
256              
257 139         417 my @subtests;
258              
259 139         297 my $incode = 0;
260 139         247 my $cut_in_code = 0;
261 139         267 my $subtest;
262             my $lineno;
263 139         2288 while ( <$fh> ) {
264 33882         47777 ++$lineno;
265 33882         44298 chomp;
266 33882         61248 my $inheader = /^## name/ .. /^## cut/; ## no critic (ExtendedFormatting LineBoundaryMatching DotMatchAnything)
267              
268 33882         50760 my $line = $_;
269              
270 33882 100       61002 if ( $inheader ) {
    100          
    50          
271 9245 50       22591 $line =~ m/\A [#]/xms or throw_internal "Code before cut: $test_file";
272 9245         34248 my ($key,$value) = $line =~ m/\A [#][#] [ ] (\S+) (?:\s+(.+))? /xms;
273 9245 100       19321 next if !$key;
274 9238 100       23358 next if $key eq 'cut';
275 6596 50       12977 if ( not $valid_keys{$key} ) {
276 0         0 throw_internal "Unknown key $key in $test_file";
277             }
278              
279 6596 100       11493 if ( $key eq 'name' ) {
280 2642 100       4730 if ( $subtest ) { # Stash any current subtest
281 2503         5033 push @subtests, _finalize_subtest( $subtest );
282 2503         4234 undef $subtest;
283             }
284 2642         5293 $subtest->{lineno} = $lineno;
285 2642         3818 $incode = 0;
286 2642         3697 $cut_in_code = 0;
287             }
288 6596 50       11302 if ($incode) {
289 0         0 throw_internal "Header line found while still in code: $test_file";
290             }
291 6596         25588 $subtest->{$key} = $value;
292             }
293             elsif ( $subtest ) {
294 24630         31266 $incode = 1;
295 24630   100     81090 $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       40931 $cut_in_code or push @{$subtest->{code}}, $line;
  24608         76593  
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       1615 close $fh or throw_generic "unable to close $test_file: $OS_ERROR";
306 139 50       410 if ( $subtest ) {
307 139 50       324 if ( $incode ) {
308 139         390 push @subtests, _finalize_subtest( $subtest );
309             }
310             else {
311 0         0 throw_internal "Incomplete subtest in $test_file";
312             }
313             }
314              
315 139         1082 return @subtests;
316             }
317              
318             sub _finalize_subtest {
319 2642     2642   4477 my $subtest = shift;
320              
321 2642 50       5232 if ( $subtest->{code} ) {
322 2642         3589 $subtest->{code} = join "\n", @{$subtest->{code}};
  2642         9641  
323             }
324             else {
325 0         0 throw_internal "$subtest->{name} has no code lines";
326             }
327 2642 50       7949 if ( !defined $subtest->{failures} ) {
328 0         0 throw_internal "$subtest->{name} does not specify failures";
329             }
330 2642 100       5068 if ($subtest->{parms}) {
331 1257         59180 $subtest->{parms} = eval $subtest->{parms}; ## no critic(StringyEval)
332 1257 50       4564 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       3365 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         2608 $subtest->{parms} = {};
343             }
344              
345 2642 100       5347 if (defined $subtest->{error}) {
346 2 50       18 if ( $subtest->{error} =~ m{ \A / (.*) / \z }xms) {
347 2         6 $subtest->{error} = eval {qr/$1/}; ## no critic (ExtendedFormatting LineBoundaryMatching DotMatchAnything)
  2         43  
348 2 50       10 if ($EVAL_ERROR) {
349 0         0 throw_internal
350             "$subtest->{name} 'error' has a malformed regular expression";
351             }
352             }
353             }
354              
355 2642         5045 return $subtest;
356             }
357              
358             sub bundled_policy_names {
359 6     6 1 5796 require ExtUtils::Manifest;
360 6         39163 my $manifest = ExtUtils::Manifest::maniread();
361 6         35181 my @policy_paths = map {m{\A lib/(Perl/Critic/Policy/.*).pm \z}xms} keys %{$manifest};
  2574         4231  
  6         334  
362 6         114 my @policies = map { join q{::}, split m{/}xms } @policy_paths;
  870         3074  
363 6         444 my @sorted_policies = sort @policies;
364 6         751 return @sorted_policies;
365             }
366              
367             sub names_of_policies_willing_to_work {
368 1     1 1 11 my %configuration = @_;
369              
370 1         15 my @policies_willing_to_work =
371             Perl::Critic::Config
372             ->new( %configuration )
373             ->policies();
374              
375 1         93 return map { ref } @policies_willing_to_work;
  143         1631  
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 :