Benchmark-Perl-Formance-Cargo
view release on metacpan or search on metacpan
share/PerlCritic/Critic/Document.pm view on Meta::CPAN
##############################################################################
# $URL: http://perlcritic.tigris.org/svn/perlcritic/trunk/distributions/Perl-Critic/lib/Perl/Critic/Document.pm $
# $Date: 2010-06-22 16:14:07 -0400 (Tue, 22 Jun 2010) $
# $Author: clonezone $
# $Revision: 3843 $
##############################################################################
package # hide from indexer
Perl::Critic::Document;
use 5.006001;
use strict;
use warnings;
use Carp qw< confess >;
use PPI::Document;
use PPI::Document::File;
use List::Util qw< reduce >;
use Scalar::Util qw< blessed weaken >;
use version;
use Perl::Critic::Annotation;
use Perl::Critic::Exception::Parse qw< throw_parse >;
use Perl::Critic::Utils qw< :booleans :characters shebang_line >;
#-----------------------------------------------------------------------------
our $VERSION = '1.108';
#-----------------------------------------------------------------------------
our $AUTOLOAD;
sub AUTOLOAD { ## no critic (ProhibitAutoloading,ArgUnpacking)
my ( $function_name ) = $AUTOLOAD =~ m/ ([^:\']+) \z /xms;
return if $function_name eq 'DESTROY';
my $self = shift;
return $self->{_doc}->$function_name(@_);
}
#-----------------------------------------------------------------------------
sub new {
my ($class, @args) = @_;
my $self = bless {}, $class;
return $self->_init(@args);
}
#-----------------------------------------------------------------------------
sub _init { ## no critic (Subroutines::RequireArgUnpacking)
my $self = shift;
my %args;
if (@_ == 1) {
warnings::warnif(
'deprecated',
'Perl::Critic::Document->new($source) deprecated, use Perl::Critic::Document->new(-source => $source) instead.' ## no critic (ValuesAndExpressions::RequireInterpolationOfMetachars)
);
%args = ('-source' => shift);
} else {
%args = @_;
}
my $source_code = $args{'-source'};
# $source_code can be a file name, or a reference to a
# PPI::Document, or a reference to a scalar containing source
# code. In the last case, PPI handles the translation for us.
my $doc = _is_ppi_doc( $source_code ) ? $source_code
: ref $source_code ? PPI::Document->new($source_code)
: PPI::Document::File->new($source_code);
# Bail on error
if ( not defined $doc ) {
my $errstr = PPI::Document::errstr();
my $file = ref $source_code ? undef : $source_code;
throw_parse
message => qq<Can't parse code: $errstr>,
file_name => $file;
}
$self->{_doc} = $doc;
$self->{_annotations} = [];
$self->{_suppressed_violations} = [];
$self->{_disabled_line_map} = {};
$self->index_locations();
$self->_disable_shebang_fix();
$self->{_is_module} = $self->_determine_is_module(\%args);
return $self;
}
#-----------------------------------------------------------------------------
sub _is_ppi_doc {
my ($ref) = @_;
return blessed($ref) && $ref->isa('PPI::Document');
}
#-----------------------------------------------------------------------------
sub ppi_document {
my ($self) = @_;
return $self->{_doc};
}
#-----------------------------------------------------------------------------
sub isa {
my ($self, @args) = @_;
return $self->SUPER::isa(@args)
|| ( (ref $self) && $self->{_doc} && $self->{_doc}->isa(@args) );
}
#-----------------------------------------------------------------------------
sub find {
my ($self, $wanted, @more_args) = @_;
# This method can only find elements by their class names. For
# other types of searches, delegate to the PPI::Document
if ( ( ref $wanted ) || !$wanted || $wanted !~ m/ \A PPI:: /xms ) {
return $self->{_doc}->find($wanted, @more_args);
}
# Build the class cache if it doesn't exist. This happens at most
# once per Perl::Critic::Document instance. %elements of will be
# populated as a side-effect of calling the $finder_sub coderef
# that is produced by the caching_finder() closure.
if ( !$self->{_elements_of} ) {
my %cache = ( 'PPI::Document' => [ $self ] );
# The cache refers to $self, and $self refers to the cache. This
# creates a circular reference that leaks memory (i.e. $self is not
# destroyed until execution is complete). By weakening the reference,
# we allow perl to collect the garbage properly.
weaken( $cache{'PPI::Document'}->[0] );
my $finder_coderef = _caching_finder( \%cache );
$self->{_doc}->find( $finder_coderef );
$self->{_elements_of} = \%cache;
}
# find() must return false-but-defined on fail
return $self->{_elements_of}->{$wanted} || q{};
}
#-----------------------------------------------------------------------------
sub find_first {
my ($self, $wanted, @more_args) = @_;
# This method can only find elements by their class names. For
# other types of searches, delegate to the PPI::Document
if ( ( ref $wanted ) || !$wanted || $wanted !~ m/ \A PPI:: /xms ) {
return $self->{_doc}->find_first($wanted, @more_args);
}
my $result = $self->find($wanted);
return $result ? $result->[0] : $result;
}
#-----------------------------------------------------------------------------
sub find_any {
my ($self, $wanted, @more_args) = @_;
# This method can only find elements by their class names. For
# other types of searches, delegate to the PPI::Document
if ( ( ref $wanted ) || !$wanted || $wanted !~ m/ \A PPI:: /xms ) {
return $self->{_doc}->find_any($wanted, @more_args);
}
my $result = $self->find($wanted);
return $result ? 1 : $result;
}
#-----------------------------------------------------------------------------
sub filename {
my ($self) = @_;
my $doc = $self->{_doc};
return $doc->can('filename') ? $doc->filename() : undef;
}
#-----------------------------------------------------------------------------
sub highest_explicit_perl_version {
my ($self) = @_;
my $highest_explicit_perl_version =
$self->{_highest_explicit_perl_version};
if ( not exists $self->{_highest_explicit_perl_version} ) {
my $includes = $self->find( \&_is_a_version_statement );
if ($includes) {
( run in 1.009 second using v1.01-cache-2.11-cpan-8f98c5d2c55 )