Schedule-Activity
view release on metacpan or search on metacpan
lib/Schedule/Activity/Annotation.pm view on Meta::CPAN
package Schedule::Activity::Annotation;
use strict;
use warnings;
use Ref::Util qw/is_hashref is_regexpref is_ref/;
use Scalar::Util qw/looks_like_number/;
our $VERSION='0.3.0';
my %property=map {$_=>undef} qw/message nodes before between p limit attributes note/;
sub new {
my ($ref,%opt)=@_;
my $class=is_ref($ref)||$ref;
return bless(\%opt,$class);
}
sub validate {
my (%node)=@_;
my @errors;
foreach my $k (grep {!exists($property{$_})} keys(%node)) { push @errors,"Invalid key: $k" }
if(!defined($node{message})) { push @errors,'Expected: message' }
if(!is_regexpref($node{nodes})) { push @errors,'Expected regexp: nodes' }
foreach my $k (grep {defined($node{$_})} qw/between p limit/) {
if(!looks_like_number($node{$k})) { push @errors,"Invalid value: $k" }
elsif($node{$k}<0) { push @errors,"Negative value: $k" }
}
$node{before}//={};
if(!is_hashref($node{before})) { push @errors,'Before invalid structure' }
else { foreach my $k (grep {defined($node{before}{$_})} qw/min max/) {
if(!looks_like_number($node{before}{$k})) { push @errors,"Invalid value: before{$k}" }
} }
return @errors;
}
sub annotate {
my ($self,@schedule)=@_;
my %before=%{$$self{before}//{}};
my %opt=(
p =>$$self{p}//1,
beforemin=>$before{min}//$before{max}//1,
beforemax=>$before{max}//$before{min}//1,
between =>$$self{between}//1,
);
my @matchidx=grep {rand()<=$opt{p}} grep {$schedule[$_][1]{keyname}=~$$self{nodes}} (0..$#schedule);
if(!@matchidx) { return }
my @notes;
foreach my $i (@matchidx) {
my @tmwindow=sort {$a<=>$b} ($schedule[$i][0]-$opt{beforemax},$schedule[$i][0]-$opt{beforemin});
if($i>0) { my $tm=$schedule[$i-1][0]+1; if($tmwindow[0]<=$tm) { $tmwindow[0]=$tm } }
if($i<$#schedule) { my $tm=$schedule[$i+1][0]-1; if($tmwindow[1]>=$tm) { $tmwindow[1]=$tm } }
if($tmwindow[1]>=$tmwindow[0]) { push @notes,[@tmwindow] }
}
if($$self{limit}) { while(1+$#notes>$$self{limit}) {
my $idx=int(rand(1+$#notes)); splice(@notes,$idx,1) } }
for(my $i=1;$i<=$#notes;$i++) { ## no critic (CStyleForLoops)
if($notes[$i][0]-$notes[$i-1][0]<$opt{between}) {
if($notes[$i][1]-$notes[$i-1][0]<$opt{between}) { splice(@notes,$i,1); $i-- }
else { $notes[$i][0]=$notes[$i-1][0]+$opt{between} }
}
}
return map {[$$_[0], {map {$_=>$$self{$_}} grep {$$self{$_}} qw/message attributes/}]} @notes;
}
1;
( run in 0.476 second using v1.01-cache-2.11-cpan-39bf76dae61 )