Algorithm-Dependency-Objects
view release on metacpan or search on metacpan
lib/Algorithm/Dependency/Objects.pm view on Meta::CPAN
return;
}
sub new {
my ($class, %params) = @_;
my $objects = $class->_to_set($params{objects}) or
croak "The 'objects' parameter must be an array reference or a Set::Object";
my $selected = exists($params{selected})
? $class->_to_set($params{selected})
: Set::Object->new()
or croak "If provided, the 'selected' parameter must be an array reference or a Set::Object";
# all the contents of the Set::Object must have depends methods
$class->assert_can_get_deps($objects);
$objects = $class->verify_input_set($objects);
return bless {
objects => $objects,
selected => $selected,
}, $class;
}
sub objects { (shift)->{objects} }
sub selected { (shift)->{selected} }
sub get_deps {
my ( $self, $obj ) = @_;
$obj->depends;
}
sub can_get_deps {
my ( $self, $obj ) = @_;
$obj->can("depends");
}
lib/Algorithm/Dependency/Objects.pm view on Meta::CPAN
sub assert_can_get_deps {
my ( $self, $objs ) = @_;
$self->can_get_deps($_) || croak "Objects must have a 'depends' method" for $objs->members;
}
sub depends {
my ( $self, @objs ) = @_;
my @queue = @objs;
my $selected_now = Set::Object->new;
my $selected_previously = $self->selected;
my $all_objects = $self->objects;
while (@queue){
my $obj = shift @queue;
$self->unknown_object($obj) unless $all_objects->contains($obj);
next if $selected_now->contains($obj);
next if $selected_previously->contains($obj);
push @queue, $self->get_deps($obj);
$selected_now->insert($obj);
}
$selected_now->remove(@objs);
return wantarray ? $selected_now->members : $selected_now;
}
sub verify_input_set {
my ( $self, $objects ) = @_;
my $dependant = Set::Object->new(map { $self->get_deps($_) } $objects->members);
my $unresolvable = $dependant->difference($objects);
if ($unresolvable->size){
lib/Algorithm/Dependency/Objects.pm view on Meta::CPAN
sub unknown_object {
my ( $self, $obj ) = @_;
croak "$obj is not in the input objects";
}
sub schedule {
my ( $self, @desired ) = @_;
my $desired = Set::Object->new(@desired);
my $selected = $self->selected;
my $missing = $desired->difference($selected);
$self->depends(@desired)->union($missing)->members;
}
sub schedule_all {
my $self = shift;
$self->objects->difference($self->selected)->members;
}
__PACKAGE__
__END__
=pod
=head1 NAME
Algorithm::Dependency::Objects - An implementation of an Object Dependency Algorithm
=head1 SYNOPSIS
use Algorithm::Dependency::Objects;
my $o = Algorithm::Dependency::Objects->new(
objects => \@objects,
selected => \@selected, # objects which are already taken care of
);
my @needed = $o->schedule( $objects[0] );
# need to take care of @needed for $objecs[0] to be resolved
=head1 DESCRIPTION
This modules is a re-implementation of L<Algorithm::Dependency> using only
objects instead of object ids, making use of L<Set::Object> for book-keeping.
lib/Algorithm/Dependency/Objects.pm view on Meta::CPAN
=head1 METHODS
=over 4
=item B<new>
Duh.
=item B<objects>
=item B<selected>
Returns the L<Set::Object> representing this collection. Objects is an
enumeration of all the object who we're dependo-frobnicating, and selected is
those that don't need to be run.
=item B<depends>
=item B<schedule>
=item B<schedule_all>
See L<Algorithm::Dependency>'s corresponding methods.
lib/Algorithm/Dependency/Objects/Ordered.pm view on Meta::CPAN
}
sub schedule_all {
my ( $self, @args ) = @_;
$self->_order($self->SUPER::schedule_all(@args));
}
sub _order {
my ( $self, @queue ) = @_;
my $selected = Set::Object->new( $self->selected->members );
my $error_marker;
my @schedule;
my %dep_set;
while (@queue){
my $obj = shift @queue;
if ( defined($error_marker) and refaddr($error_marker) == refaddr($obj) ) {
$self->circular_dep($obj, @queue);
}
my $dep_set = $dep_set{refaddr $obj} ||= Set::Object->new( $self->get_deps($obj) );
unless ( $selected->superset($dep_set) ) {
# we have some missing deps
# put the object back in the queue
push @queue, $obj;
# if we encounter it again without any change
# then a circular dependency is detected
$error_marker = $obj unless defined $error_marker;
} else {
# the dependancies are a subset of the selected objects,
# so they are all resolved.
push @schedule, $obj;
# mark the object as selected
$selected->insert($obj);
# since something changed we can forget about the error marker
undef $error_marker;
}
}
# return the ordered list
@schedule;
}
lib/Algorithm/Dependency/Objects/Ordered.pm view on Meta::CPAN
=head1 DESCRIPTION
=head1 METHODS
=over 4
=item B<new>
=item B<objects>
=item B<selected>
=item B<depends>
=item B<schedule>
=item B<schedule_all>
=item B<circular_dep>
=back
t/01_basics.t view on Meta::CPAN
my $m;
BEGIN { use_ok($m = "Algorithm::Dependency::Objects") };
# Load the data/basics.txt file in as a source file, and test it rigorously.
{
# Try to create a basic unordered dependency
isa_ok(my $dep = $m->new(objects => $objs), $m);
is($dep->objects->size, 6, "six objects are registered");
is($dep->selected->size, 0, "no objects are selected");
verify_dep_and_sched($dep, [
[$a], [], [$a] ], [
[$b], [$c], [$b, $c] ], [
[$c], [], [$c] ], [
[$d], [$e, $f], [$d, $e, $f] ], [
[$e], [], [$e] ], [
[$f], [], [$f] ], [
[$a, $b], [$c], [$a, $b, $c] ], [
[$b, $d], [$c, $e, $f], [$b, $c, $d, $e, $f] ]
);
}
{
# Create with one selected
isa_ok(my $dep = $m->new( objects => $objs, selected => Set::Object->new($f) ), $m);
cmp_deeply(
[ $dep->schedule_all ],
bag( $a, $b, $c, $d, $e ), # no $f
"schedule_all",
);
is($dep->objects->size, 6, "six objects registered" );
is($dep->selected->size, 1, "one objects selected" );
ok( !$dep->selected->contains($a), "a is not selected" );
ok( $dep->selected->contains($f), "f is selected" );
verify_dep_and_sched($dep, [
[$a], [], [$a] ], [
[$b], [$c], [$b, $c] ], [
[$c], [], [$c] ], [
[$d], [$e], [$d, $e] ], [
[$e], [], [$e] ], [
[$f], [], [] ], [
[$a, $b], [$c], [$a, $b, $c] ], [
[$b, $d], [$c, $e], [$b, $c, $d, $e] ]
( run in 1.534 second using v1.01-cache-2.11-cpan-49f99fa48dc )