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 )