Bio-Community
view release on metacpan or search on metacpan
lib/Bio/Community/IO.pm view on Meta::CPAN
lazy => 1,
);
# Overriding new... Is there a better alternative?
func new ($class, @args) {
my $real_class = Scalar::Util::blessed($class) || $class;
# These all come from the same base, Moose::Object, so this is fine
my $params = $real_class->BUILDARGS(@args);
my $format = delete $params->{'-format'};
if (not defined $format) {
# Try to guess format
my $guesser = Bio::Community::IO::FormatGuesser->new();
if ($params->{'-file'}) {
$guesser->file( $params->{'-file'} );
} elsif ($params->{'-fh'}) {
$guesser->fh( $params->{'-fh'} );
}
$format = $guesser->guess;
}
if (not defined $format) {
$real_class->throw("Could not automatically detect input format.");
}
# Use the real driver class here
$real_class = __PACKAGE__.'::Driver::'.$format;
Module::Runtime::use_module($real_class);
$class->throw("Module $real_class does not implement a community IO stream")
unless $real_class->does('Bio::Community::Role::IO');
$params = $real_class->BUILDARGS(%$params);
my $self = Class::MOP::Class->initialize($real_class)->new_object($params);
return $self;
}
method BUILD ($args) {
# Start IOs
$self->_initialize_io(%$args);
return 1;
}
=head2 next_member
Usage : my ($member, $count) = $in->next_member;
Function: Get the next member from the community and its abundance. This
function is implemented by the Bio::Community::IO::Driver used to
parse the given file format.
Args : None
Returns : An array containing:
A Bio::Community::Member object (or undef)
A positive number (or undef)
=cut
method next_member () {
$self->throw_not_implemented;
}
=head2 next_community
Usage : my $community = $in->next_community;
Function: Get the next community. Note that communities without members are
skipped.
Args : None
Returns : A Bio::Community object
or
undef if there were no communities left
=cut
method next_community () {
my $community;
if (not defined $self->_meta) {
$self->_next_metacommunity_init( );
$self->_meta(Bio::Community::Meta->new);
}
while ( 1 ) { # Skip communities with no members
# Initialize driver for next community and set community name
my $name = $self->_next_community_init;
# All communities have been read
last if not defined $name;
# Create a new community object
$community = Bio::Community->new( -name => $name );
# Reinitialize queue
my $count_queue = {};
my $member_queue = $self->_member_queue;
# Populate the community with members
while ( my ($member, $count) = $self->next_member() ) {
# All members have been read
last if not defined $member;
# Skip members without proper weights for now
if (exists $member_queue->{$member->id}) {
$count_queue->{$member->id} = $count;
next;
}
# Add this member to the community
$community->add_member($member, $count);
}
$self->_count_queue( $count_queue );
# Process member queue now
if (scalar keys %$count_queue > 0) {
$self->_process_member_queue($community);
}
$self->_next_community_finish;
if ( ($community->get_richness > 0) || (not $self->skip_empty_communities) ) {
last;
} else {
$community = undef;
}
}
# Community is undef if all communities have been seen
return $community;
}
method _next_community_init () {
# Driver-side method to initialize new community and return its name
$self->throw_not_implemented;
}
method _next_community_finish () {
# Driver-side method to finalize a community
$self->throw_not_implemented;
}
=head2 next_metacommunity
Usage : my $meta = $in->next_metacommunity;
Function: Get the next metacommunity. It may contain one or several communities
depending on the format of the file read,
Args : None
Returns : A Bio::Community::Meta object
or
undef after the metacommunity has been read
=cut
method next_metacommunity () {
my $meta;
if (not defined $self->_meta) {
$meta = Bio::Community::Meta->new();
my $name = $self->_next_metacommunity_init;
if (defined $name) {
$meta->name($name);
}
$self->_meta($meta);
while (my $community = $self->next_community) {
$self->_meta->add_communities([$community]);
}
# _next_metacommunity_finish will happen before close()
}
return $meta;
}
method _next_metacommunity_init () {
# Driver-side method to initialize new metacommunity and return its name
$self->throw_not_implemented;
}
method _next_metacommunity_finish () {
# Driver-side method to finalize reading a metacommunity
$self->throw_not_implemented;
}
=head2 write_member
Usage : $out->write_member($member, $abundance);
Function: Write the next member from the community and its count or relative
abundance. This function is implemented by a Bio::Community::IO::Driver
specific to the given file format.
Args : A Bio::Community::Member object
A positive number
Returns : 1 for success
=cut
method write_member (Bio::Community::Member $member, Count $count) {
$self->throw_not_implemented;
}
=head2 write_community
Usage : $out->write_community($community);
Function: Write the next community.
Args : A Bio::Community object
Returns : 1 for success
=cut
method write_community (Bio::Community $community) {
if (not defined $self->_meta) {
my $meta = Bio::Community::Meta->new;
$self->_write_metacommunity_init($meta);
$self->_meta($meta);
}
# Write community but skip empty ones if desired
if ( ($community->get_richness > 0) || (not $self->skip_empty_communities) ) {
$self->_write_community_init($community);
if (not defined $self->_meta->get_community_by_name($community->name)) {
$self->_meta->add_communities([$community]);
}
my $sort_members = $self->sort_members;
if ($sort_members == 1) {
my $rank = $community->get_richness;
while ( my $member = $community->get_member_by_rank($rank) ) {
$self->_process_member($member, $community);
$rank--;
last if $rank == 0;
}
} elsif ($sort_members == -1) {
my $rank = 1;
while ( my $member = $community->get_member_by_rank($rank) ) {
$self->_process_member($member, $community);
$rank++;
}
} elsif ($sort_members == 0) {
while ( my $member = $community->next_member('_write_community_ite') ) {
$self->_process_member($member, $community);
}
} else {
$self->throw("$sort_members is not a valid sort value.\n");
}
$self->_write_community_finish($community);
}
if ( ($self->_meta->get_communities_count > 1) && (not $self->multiple_communities) ) {
$self->throw('Format '.$self->format.' only supports writing one community per file');
}
return 1;
}
method _write_community_init (Bio::Community $community) {
# Driver-side method to initialize writing a community
$self->throw_not_implemented;
}
method _write_community_finish (Bio::Community $community) {
# Driver-side method to finalize writing a community
$self->throw_not_implemented;
}
=head2 write_metacommunity
Usage : $out->write_metacommunity($meta);
Function: Write a metacommunity.
Args : A Bio::Community::Meta object
Returns : 1 for success
=cut
method write_metacommunity (Bio::Community::Meta $meta) {
if (not defined $self->_meta) {
$self->_meta($meta);
$self->_write_metacommunity_init($meta);
while (my $community = $meta->next_community) {
$self->write_community($community);
}
# _write_metacommunity_finish will happen before close()
} else {
$self->throw('Can write only one metacommunity');
}
return 1;
}
method _write_metacommunity_init (Bio::Community::Meta $meta) {
# Driver-side method to initialize writing a metacommunity
$self->throw_not_implemented;
}
method _write_metacommunity_finish (Bio::Community::Meta $meta) {
# Driver-side method to finalize writing a metacommunity
$self->throw_not_implemented;
}
before 'close' => sub {
my $self = shift;
if ($self->mode eq 'r') {
$self->_next_metacommunity_finish();
} else {
# Finish preparing the metacommunity for writing
$self->_write_metacommunity_finish($self->_meta);
# For objects consuming Bio::Community::Role::Table, write the table now
if (does_role($self, 'Bio::Community::Role::Table')) {
$self->_write_table unless $self->_was_written;
}
}
return 1;
};
#method _process_member (Bio::Community::Member $member, Bio::Community $community) {
method _process_member ($member, $community) {
my $ab_value;
my $ab_type = $self->abundance_type;
if ($ab_type eq 'count') {
$ab_value = $community->get_count($member);
} elsif ($ab_type eq 'absolute') {
$ab_value = $community->get_abs_ab($member);
} elsif ($ab_type eq 'percentage') {
$ab_value = $community->get_rel_ab($member);
} elsif ($ab_type eq 'fraction') {
$ab_value = $community->get_rel_ab($member) / 100;
} else {
$self->throw("$ab_value is not a valid abundance type.\n");
}
$self->write_member($member, $ab_value);
return 1;
}
=head2 skip_empty_communities
Usage : $in->skip_empty_communities;
Function: Get or set whether empty communities (with no members) should be
read/written or skipped.
Args : 0 or 1
Returns : 0 or 1
=cut
has 'skip_empty_communities' => (
is => 'rw',
isa => 'Bool',
required => 0,
lazy => 1,
default => 0,
init_arg => '-skip_empty_communities',
);
=head2 sort_members
( run in 1.398 second using v1.01-cache-2.11-cpan-39bf76dae61 )