Chemistry-Mol

 view release on metacpan or  search on metacpan

lib/Chemistry/File.pm  view on Meta::CPAN

sub write_file {
    my ($self, $mol, $file, %opts) = @_;

    $self->new(file => $file, mols => [$mol], opts => \%opts)->write;
}

=item $class->name_is($fname, %options)

Returns true if a filename is of the format corresponding to the class.
It should look at the filename only, because it may be called with
non-existent files. It is used to determine with which format to save a file.
For example, the Chemistry::File::PDB returns true if the file ends in .pdb.

=cut

sub name_is {
    0;
}

=item $class->string_is($s, %options)

Examines the string $s and returns true if it has the format of the class.

=cut

sub string_is {
    0;
}

=item $class->file_is($file, %options)

Examines the file $file and returns true if it has the format of the class.
The default method slurps the whole file and then calls string_is, but derived
classes may choose to override it.

=cut

sub file_is {
    my ($self, $file, %opts) = @_;
    
    my $s = eval {
        $self->open('<');
        $self->slurp;
    };
    if ($s) {
        $self->string_is($s, %opts);
    } elsif (! ref $file) {
        $self->name_is($file, %opts);
    }
}

=item $class->slurp

Reads a file into a scalar. Automatic decompression of gzipped files is
supported if the Compress::Zlib module is installed. Files ending in .gz are
assumed to be compressed; otherwise it is possible to force decompression by
passing the gzip => 1 option (or no decompression with gzip => 0).

=cut

# slurp a file into a scalar, with transparent decompression
sub slurp {
    my ($self) = @_;

    my $fh = $self->fh;
    local $/; 
    <$fh>;
}

=item $class->new(file => $file, opts => \%opts)

Create a new file object. This method is usually called indirectly via
the Chemistry::Mol->file method. $file may be a scalar with a filename, an
open filehandle, or a reference to a scalar. If a reference to a scalar is 
used, the string contained in the scalar is used as an in-memory file.

=cut

sub new {
    my $self = shift->SUPER::new(@_);
    $self->{opts}{fatal} = 1 unless exists $self->{opts}{fatal};
    $self;
}

Chemistry::Obj::accessor(qw(file fh opts mols mode));

=back

=head1 INSTANCE METHODS

=head2 Accessors

Chemistry::File objects are derived from Chemistry::Obj and have the same
properties (name, id, and type), as well as the following ones:

=over

=item file

The "file" as described above under C<new>.

=item fh

The filehandle used for reading and writing molecules. It is opened by C<open>.

=item opts

A hashref containing the options that are passed through to the old-style class
methods. They are also passed to the instance method to keep a similar
interface, but they could access them via $self->opts anyway.

=item mode

'>' if the file is open for writing, '<' for reading, and false if not open.

=item mols

C<read> stores all the molecules that were read in this property as an array
reference. C<write> gets the molecules to write from here.

=back

lib/Chemistry/File.pm  view on Meta::CPAN

more molecules in the file. This method should be overridden by derived
classes; otherwise it will call slurp_mol and parse_string (for backwards
compatibility; it is recommended to override read_mol directly in new modules).

Note: some old file I/O modules (written before the 0.30 interface) may return
more than one molecule anyway, so it is recommended to call read_mol in list
context to be safe:

    ($mol) = $file->read_mol($fh, %opts);

=cut

sub read_mol {
    my ($self, $fh, %opts) = @_;
    my $s = $self->slurp_mol($fh);
    return unless defined $s and length $s;
    $self->parse_string($s, %opts, _must_override => 1);
}
=item $file->write_header

Write whatever information is needed before the first molecule.
Does nothing by default.

=cut

sub write_header { }

=item $file->write_footer

Write whatever information is needed after the last molecule.
Does nothing by default.

=cut

sub write_footer { }

=item $self->write_mol($fh, $mol, %opts)

Write one molecule to $fh. By default and for backward compatibility, it just
calls C<write_string> and prints its return value to $self->fh. New classes
should override it.

=cut

sub write_mol {
    my ($self, $fh, $mol, %opts) = @_;
    print $fh $self->write_string($mol, %opts, _must_override => 1);
}

########################## OTHER ##################################

=back

=head2 Other methods

=over 

=item $self->open($mode) 

Opens the file (held in $self->file) for reading by default, or for writing if
$mode eq '>'. This method sets $self->fh transparently regardless of whether
$self->file is a filename (compressed or not), a scalar reference, or a
filehandle.

=cut

sub open {
    my ($self, $mode) = @_;
    my $fh;
    my $s;
    $mode ||= '<';
    $self->mode($mode);
    my $file = $self->file;
    croak "Chemistry::File::open: no file supplied" unless defined $file;
    if (ref $file eq 'SCALAR') {
        croak "decompression only supported for files" if $self->{opts}{gzip};
        if ($] >= 5.008) {
            open $fh, $mode, $file;
        } else { 
            require IO::String;
            $fh = IO::String->new($$file);
        }
    } elsif (ref $file) {
        croak "decompression only supported for files" if $self->{opts}{gzip};
        $fh = $file;
    } elsif ($self->{opts}{gzip} 
        or !defined $self->{opts}{gzip} and $file =~ /.gz$/) 
    {
        eval { require Compress::Zlib } # Carp
            or croak "Compress::Zlib not installed!";
        require File::Temp;

        $fh = File::Temp::tempfile();
        $self->{opts}{gzip} ||= 1;
        unless ($mode eq '>') { 
            my $gz = Compress::Zlib::gzopen($file, "rb") 
                 or croak "Cannot open compressed $file: "
                     . "$Compress::Zlib::gzerrno\n";

            my $buffer;
            print $fh $buffer while $gz->gzread($buffer) > 0;
        
            if ($Compress::Zlib::gzerrno != Compress::Zlib::Z_STREAM_END()) {
                croak "Error reading from $file: $Compress::Zlib::gzerrno"
                    . ($Compress::Zlib::gzerrno+0) . "\n";
            }
            $gz->gzclose();
            seek $fh, 0, 0;
        }
    } else {
        $fh = FileHandle->new("$mode$file") 
            or croak "Could not open file $file: $!";
    }
    $self->fh($fh);
    $self;
}

=item $self->close

Close the file. For regular files this just closes the filehandle, but for
gzipped files it does some additional postprocessing. This method is called



( run in 0.821 second using v1.01-cache-2.11-cpan-96521ef73a4 )