App-CriticDB
view release on metacpan or search on metacpan
lib/App/CriticDB/DB.pm view on Meta::CPAN
package App::CriticDB::DB;
use strict;
use warnings;
use Carp qw/confess/;
use Perl::Critic::Violation;
use App::CriticDB::DB::Index;
our $VERSION='0.0.6';
my %engines=(
storable=>'App::CriticDB::DB::Stor',
);
sub new {
my (undef,%opt)=@_;
$opt{mode}//='not provided';
my ($class,%self);
if($opt{mode} eq 'file') {
if(!$opt{file}) { confess('File storage requires filename') }
$opt{type}//='storable';
%self=map {$_=>$opt{$_}} qw/mode file type/;
$class=$engines{$opt{type}}//$engines{storable};
eval "require $class";
}
else { confess("Storage type not available: $opt{mode}") }
my $self=bless(\%self,$class);
$self->read();
return $self;
}
sub _initStore {
my ($self)=@_;
return (
version=>1001,
index=>{
policy=>App::CriticDB::DB::Index->new(values=>'id',prefix=>'p:'),
'policy-file'=>App::CriticDB::DB::Index->new(values=>'set'),
},
file=>{},
);
}
sub _init {
my ($self)=@_;
%{$$self{store}}=$self->_initStore();
return $self->write();
}
sub _filemtime {
my ($fn)=@_;
if(!-e $fn) { return }
return (stat($fn))[9];
}
sub _fileNewer {
my ($self,$fn,$ts)=@_;
if(!$ts) { return }
my $tm=_filemtime($fn);
if(!$tm) { return }
return ($tm>$ts);
}
sub _violation {
my ($self,$fn,$V)=@_;
my %res;
my %remap=(
'_description' =>'desc',
'_explanation' =>'expl',
'_policy' =>'policy',
'_severity' =>'sev',
'_source' =>'code',
);
if('Perl::Critic::Violation' eq ref($V)) {
%res=(
(map {$remap{$_}=>$$V{$_}} keys(%remap)),
line =>$V->line_number(),
col =>$V->column_number(),
)
}
elsif('HASH' eq ref($V)) { %res=%$V }
else { confess('Invalid type of violation') }
$res{file}=$fn; # added for IndexSet construction
foreach my $ka (keys %res) {
if(defined($$self{store}{index}{$ka})) { $res{$ka}=$$self{store}{index}{$ka}->upsert($res{$ka}) }
foreach my $kb (grep {$_ ne $ka} keys %res) {
if($$self{store}{index}{"$ka-$kb"}) { $$self{store}{index}{"$ka-$kb"}->add(@res{$ka,$kb}) }
}
}
delete($res{file}); # not needed in the stored violation
return %res;
}
sub store {
my ($self,%opt)=@_;
if(!$opt{file}) { return $self }
my @violations=map {+{$self->_violation($opt{file},$_)}} @{$opt{violations}//[]};
$$self{store}{file}{$opt{file}}{violations}=\@violations;
$$self{store}{file}{$opt{file}}{mtime}=_filemtime($opt{file})//$opt{mtime}//time();
return $self;
}
sub flush {
my ($self,$fn)=@_;
return $self->write(fn=>$fn);
}
sub newer {
my ($self,$fn)=@_;
if(!$$self{store}{file}{$fn}) { return 1 }
return $self->_fileNewer($fn,$$self{store}{file}{$fn}{mtime}//0);
}
( run in 2.155 seconds using v1.01-cache-2.11-cpan-14f38c9f855 )