How can I avoid Perl :: Critic warnings when processing a multi-line string with a file descriptor?
Does anyone have a solution to the problem of handling a multi-line string one line at a time other than the below string-as-a-file solution?
my $multiline_string = "line one\nline two\nline three\nline four";
my $filehandle;
open( $filehandle, '<', \$multiline_string )
or croak("Can't open multi-line string as a filehandle: $!");
while ( defined (my $single_line = <$filehandle>) ) {
# do some processing of $single_line here ...
}
close( $filehandle );
My reason for not using a file descriptor is pretty weak. Test :: Perl :: Critical screams when I have more than 10 lines of source code between my open command and my close command on any file descriptor. I'm doing quite a lot of $ single_line processing, so I actually have about 40 lines of code between my open call and my closed call, and I don't see any way to get that to 10.
And I really don't want to ignore the Perl :: Critic test in my assembly, because it is a really decent test that I would like to pass whenever I open an actual file on disk in my code.
source to share
Make Creta Perl happy and make yourself even happier by creating a subroutine and name it with every line of the file.
use strict; use warnings;
sub do_something {
my ($line) = @_;
# do something with $line
}
open my $fh, '<', \$multiline_string
or die "Cannot open scalar for reading: $!";
while(<$fh>) {
chomp;
do_something($_);
}
close $fh;
source to share
Long before I even knew that you could flip a multiline string into a file descriptor, there was split
:
foreach my $single_line (split /\n/, $multiline_string) {
# process $single_line here
# although note that it doesn't end in a newline anymore
}
Insert a statement about using literal and non-portable \n
here.
source to share
Perl :: Critic is nice, but when you start obsessing with some of its requirements, it starts wasting its time, not saving it. I just let the file descriptor go out of scope and not worry about being closed:
my $multiline_string = "line one\nline two\nline three\nline four";
{
open my( $fh ), '<', \$multiline_string )
or croak("Can't open multi-line string as a filehandle: $!");
while ( defined (my $single_line = <$fh>) ) {
# do some processing of $single_line here ...
}
}
A lot of people achieve regex or break, but I think this is sloppy. You don't need to create a new list and use much more memory in your program.
source to share
You can use regular expression.
#!/usr/bin/perl
use strict;
use warnings;
my $s = "line one\nline two\nline three\nline four";
while ($s =~ m'^(.*)$'gm) {
print "'$1'\n";
}
die "Exited loop too early\n" unless pos $s == length $s;
Or you can use split
:
for my $line ( split m'\n', $multiline_string ){
# ...
}
source to share
Personally, I like to use it $/
to split strings in a multi-line string.
my $multiline_string = "line one\nline two\nline three\nline four";
foreach (split($/, $mutliline_string)) {
process_file($_);
}
sub process_file {
my $filename = shift;
my $filehandle;
open( $filehandle, '<', $filename )
or croak("Can't open multi-line string as a filehandle: $!");
while ( defined (my $single_line = <$filehandle>) ) {
process_line($single_line);
}
close( $filehandle );
}
sub process_line {
my $line = shift;
...
}
source to share