K
Klaus
Hello,
I have a list of 4 scalars
my @L = (3, '3', 3.0, '3.0');
The first is obviously an int, the second is text, the third a double
and the last is text again.
I want to write a subroutine type_id which returns either 'int',
'double', 'text' (or '?') for each of the scalars, so that
print type_id($_), ' ' for (@L); print "\n";
results in the following output:
int text double text
I have found a solution where I use Devel:eek, call Dump(), redirect
STDERR into an "in-memory" file ( \$data ) and analyse the "in-memory"
content:
$data =~ /^SV = IV(0x/ # for ints
$data =~ /^SV = NV(0x/ # for doubles
$data =~ /^SV = PV(0x/ # for text
but I wanted to know whether there is a better way.
**********************************************************
Here is my solution:
use strict;
use warnings;
use Devel:eek;
print STDERR "Beginning of program\n";
my @L = (3, '3', 3.0, '3.0');
print type_id($_), ' ' for (@L);
print "\n";
print STDERR "End of program\n";
sub type_id {
# ============================
# At first I could not get the "in-memory"
# working. It took me a while before I
# found the all important documentation
# in perldoc -f open:
#
# [...] if you try to re-open STDOUT or
# STDERR as an "in memory" file, you have
# to close it first [...]
#
# As a consequence, a simple
# local *STDERR;
# open STDERR, '>', \$data;
# does not work.
#
# The following redirects STDERR into an
# "in-memory" file, but leaves STDERR
# closed on exit:
# local *STDERR = *STDERR;
# close STDERR;
# open STDERR, '>', \$data;
#
# so we have to dup STDERR first and
# restore STDERR manually at the end
# (...knowing that if the restore fails,
# we won't have STDERR anymore):
# ============================
# dup STDERR
open my $olderr, '>&', \*STDERR
or return "?002 [dup STDERR: $!]";
close STDERR
or return "?005 [close STDERR: $!]";
my $data = '';
open STDERR, '>', \$data;
Dump $_[0];
close STDERR;
# restore STDERR
open STDERR, '>&', $olderr or die;
if ($data =~ m{^SV = (.V)}) {
if ($1 eq 'IV') { return 'int' }
if ($1 eq 'NV') { return 'double' }
if ($1 eq 'PV') { return 'text' }
return "?020 [Invalid: SV = $1]";
}
return "?030 [Err: ".substr($data, 0, 12)."]";
}
I have a list of 4 scalars
my @L = (3, '3', 3.0, '3.0');
The first is obviously an int, the second is text, the third a double
and the last is text again.
I want to write a subroutine type_id which returns either 'int',
'double', 'text' (or '?') for each of the scalars, so that
print type_id($_), ' ' for (@L); print "\n";
results in the following output:
int text double text
I have found a solution where I use Devel:eek, call Dump(), redirect
STDERR into an "in-memory" file ( \$data ) and analyse the "in-memory"
content:
$data =~ /^SV = IV(0x/ # for ints
$data =~ /^SV = NV(0x/ # for doubles
$data =~ /^SV = PV(0x/ # for text
but I wanted to know whether there is a better way.
**********************************************************
Here is my solution:
use strict;
use warnings;
use Devel:eek;
print STDERR "Beginning of program\n";
my @L = (3, '3', 3.0, '3.0');
print type_id($_), ' ' for (@L);
print "\n";
print STDERR "End of program\n";
sub type_id {
# ============================
# At first I could not get the "in-memory"
# working. It took me a while before I
# found the all important documentation
# in perldoc -f open:
#
# [...] if you try to re-open STDOUT or
# STDERR as an "in memory" file, you have
# to close it first [...]
#
# As a consequence, a simple
# local *STDERR;
# open STDERR, '>', \$data;
# does not work.
#
# The following redirects STDERR into an
# "in-memory" file, but leaves STDERR
# closed on exit:
# local *STDERR = *STDERR;
# close STDERR;
# open STDERR, '>', \$data;
#
# so we have to dup STDERR first and
# restore STDERR manually at the end
# (...knowing that if the restore fails,
# we won't have STDERR anymore):
# ============================
# dup STDERR
open my $olderr, '>&', \*STDERR
or return "?002 [dup STDERR: $!]";
close STDERR
or return "?005 [close STDERR: $!]";
my $data = '';
open STDERR, '>', \$data;
Dump $_[0];
close STDERR;
# restore STDERR
open STDERR, '>&', $olderr or die;
if ($data =~ m{^SV = (.V)}) {
if ($1 eq 'IV') { return 'int' }
if ($1 eq 'NV') { return 'double' }
if ($1 eq 'PV') { return 'text' }
return "?020 [Invalid: SV = $1]";
}
return "?030 [Err: ".substr($data, 0, 12)."]";
}