Test-MockFile
view release on metacpan or search on metacpan
lib/Test/MockFile/FileHandle.pm view on Meta::CPAN
return 0;
}
my $strlen = length($buf);
$offset //= 0;
if ( $offset < 0 ) {
$offset = $strlen + $offset;
}
if ( $offset < 0 || $offset > $strlen ) {
CORE::warn(qq{Offset outside string at @{[ join ' line ', (caller)[1,2] ]}.\n});
$! = EINVAL;
return 0;
}
# Write directly â syswrite must NOT inherit $, or $\ from PRINT.
# Per perlapi: if len exceeds available data after offset, writes
# only what is available (substr handles this naturally).
my $bytes = $self->_write_bytes( substr( $buf, $offset, $len ) );
$self->_update_write_times() if $bytes;
return $bytes;
}
=head2 READLINE
This method is called when the handle is read via <HANDLE> or readline
HANDLE.
Based on the numeric location we are in the file (tell), we read until
the EOF separator (C<$/>) is seen. tell is updated after the line is
read. undef is returned if tell is already at EOF.
=cut
sub _READLINE_ONE_LINE {
my ($self) = @_;
my $data = $self->{'data'} or return undef;
my $contents = $data->{'contents'};
my $len = length($contents);
my $tell = $self->{'tell'};
# Slurp mode: $/ = undef â return everything from tell to end
if ( !defined $/ ) {
return undef if $tell >= $len;
$self->{'tell'} = $len;
return substr( $contents, $tell );
}
# Fixed-record mode: $/ = \N â read exactly N bytes
if ( ref $/ ) {
my $reclen = ${ $/ } + 0;
return undef if $tell >= $len;
my $remaining = $len - $tell;
my $read_len = $reclen < $remaining ? $reclen : $remaining;
$self->{'tell'} = $tell + $read_len;
return substr( $contents, $tell, $read_len );
}
# Paragraph mode: $/ = '' â read paragraphs separated by blank lines
if ( $/ eq '' ) {
my $pos = $tell;
# Skip leading newlines
while ( $pos < $len && substr( $contents, $pos, 1 ) eq "\n" ) {
$pos++;
}
return undef if $pos >= $len;
my $start = $pos;
my $boundary = index( $contents, "\n\n", $pos );
if ( $boundary == -1 ) {
# No more paragraph boundaries â return rest
$self->{'tell'} = $len;
return substr( $contents, $start );
}
# Return text up to boundary + 2 newlines (Perl collapses to exactly 2)
my $text = substr( $contents, $start, $boundary - $start ) . "\n\n";
# Advance past all consecutive newlines at the boundary
$pos = $boundary;
while ( $pos < $len && substr( $contents, $pos, 1 ) eq "\n" ) {
$pos++;
}
$self->{'tell'} = $pos;
return $text;
}
# Normal mode: read until $/ is found
return undef if $tell >= $len;
my $idx = index( $contents, $/, $tell );
if ( $idx == -1 ) {
# Record separator not found â return rest of string
$self->{'tell'} = $len;
return substr( $contents, $tell );
}
my $new_tell = $idx + length($/);
$self->{'tell'} = $new_tell;
return substr( $contents, $tell, $new_tell - $tell );
}
sub READLINE {
my ($self) = @_;
if ( !$self->{'read'} ) {
my $path = $self->{'file'} // 'unknown';
CORE::warn("Filehandle $path opened only for output");
return;
}
return if $self->EOF;
if (wantarray) {
my @all;
( run in 2.956 seconds using v1.01-cache-2.11-cpan-364913b4093 )