Skip to content

Instantly share code, notes, and snippets.

@maddingue
Last active August 29, 2015 14:13
Show Gist options
  • Save maddingue/c657eca920185042ad8e to your computer and use it in GitHub Desktop.
Save maddingue/c657eca920185042ad8e to your computer and use it in GitHub Desktop.
types coercion
sub coerce_types {
my $struct = shift;
my $ref = ref $struct;
croak "can only work with references" unless $ref;
if ($ref eq "ARRAY") {
for my $i (0..$#{$struct}) {
next unless defined $struct->[$i];
# recurse into array/hash-refs
coerce_types($struct->[$i]), next if ref $struct->[$i];
my $value = $struct->[$i];
my $copy = $struct->[$i];
# we must treat the NV before because floats without decimals
# are printed without decimal part, therefore 1.0 becomes 1
# and will be incorrectly catched by the boolean conversion
my $sv = svref_2object(\$struct->[$i]);
$struct->[$i] = $struct->[$i] / 1.0, next
if $sv->FLAGS & SVf_NOK;
# special case: coerce booleans into integers
$value = int $value if $copy eq "0" or $copy eq "1";
# special case: coerce integers given as strings
# iff they're at most 8 digits long & do not start with a zero
$value = int $value if $copy =~ /^[1-9][0-9]{0,7}$/;
$sv = svref_2object(\$value);
$value = int $value if $sv->FLAGS & SVf_IOK;
$struct->[$i] = $value;
}
}
elsif ($ref eq "HASH") {
for my $key (keys %$struct) {
next unless defined $struct->{$key};
# recurse into array/hash-refs
coerce_types($struct->{$key}), next if ref $struct->{$key};
my $value = $struct->{$key};
my $copy = $struct->{$key};
# we must treat the NV before because floats without decimals
# are printed without decimal part, therefore 1.0 becomes 1
# and will be incorrectly catched by the boolean conversion
my $sv = svref_2object(\$struct->{$key});
$struct->{$key} = $struct->{$key} / 1.0, next
if $sv->FLAGS & SVf_NOK;
# special case: coerce booleans into integers
$value = int $value if $copy eq "0" or $copy eq "1";
# special case: coerce integers given as strings
# iff they're at most 8 digits long & do not start with a zero
$value = int $value if $copy =~ /^[1-9][0-9]{0,7}$/;
$sv = svref_2object(\$value);
$value = int $value if $sv->FLAGS & SVf_IOK;
$struct->{$key} = $value;
}
}
else {
croak "don't know how to handle \L$ref reference"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment