Convert-Pluggable
view release on metacpan or search on metacpan
lib/Convert/Pluggable.pm view on Meta::CPAN
my $matches = shift;
my @matches = @{$matches};
$matches[0] =~ s/"/inches/;
$matches[0] =~ s/'/feet/;
$matches[1] =~ s/"/inches/;
$matches[1] =~ s/'/feet/;
my @match_types = ();
my @factors = ();
my @units = ();
my @can_be_negative = ();
my @types = @{ get_units() };
foreach my $match (@matches) {
foreach my $type ( @{ $self->types } ) {
if ( lc $match eq $type->{'unit'}
|| grep { $_ eq lc $match } @{ $type->{'aliases'} } )
{
push( @match_types, $type->{'type'} );
push( @factors, $type->{'factor'} );
push( @units, $type->{'unit'} );
push( @can_be_negative, $type->{'can_be_negative'} || '0' );
}
}
}
return if scalar(@match_types) != 2;
return if scalar(@factors) != 2;
return if scalar(@units) != 2;
return if scalar(@can_be_negative) != 2;
my %matches = (
'type_1' => $match_types[0],
'type_2' => $match_types[1],
'factor_1' => $factors[0],
'factor_2' => $factors[1],
'from_unit' => $units[0],
'to_unit' => $units[1],
'can_be_negative_1' => $can_be_negative[0],
'can_be_negative_2' => $can_be_negative[1],
);
return \%matches;
}
sub convert {
my $self = shift;
my $conversion = shift;
my $matches = get_matches( $self,
[ $conversion->{'from_unit'}, $conversion->{'to_unit'} ] );
return
if !( $matches->{'type_1'} && $matches->{'type_2'} );
if ( looks_like_number( $conversion->{'factor'} ) ) {
# looks_like_number thinks 'Inf' and 'NaN' are numbers:
return
if float_is_infinite( $conversion->{'factor'} )
|| float_is_nan( $conversion->{'factor'} );
# if factor is < 0 and first thing can't be negative ...
return
if $conversion->{'factor'} < 0 && !$matches->{'can_be_negative_1'};
}
else {
# if it doesn't look like a number, and it contains a number (e.g., '6^2'):
$conversion->{'factor'} = parse_number( $conversion->{'factor'} );
}
return if $conversion->{'factor'} =~ /[[:alpha:]]/;
# matches must be of the same type (e.g., can't convert mass to length):
return if ( $matches->{'type_1'} ne $matches->{'type_2'} );
# run the conversion:
# temperatures don't have 1:1 conversions, so they get special treatment:
my $factor;
if ( $matches->{'type_1'} eq 'temperature' ) {
$factor = convert_temperatures(
{
from_unit => $matches->{'from_unit'},
to_unit => $matches->{'to_unit'},
factor => $conversion->{'factor'},
}
);
}
else {
$factor = $conversion->{'factor'} *
( $matches->{'factor_2'} / $matches->{'factor_1'} );
}
return if $factor < 0 && !( $matches->{'can_be_negative_2'} );
$matches->{'result'} = precision(
{
factor => $factor,
precision => $conversion->{'precision'} || $DEFAULT_PRECISION,
}
);
return $matches;
}
# thanks, @mwmiller!
sub parse_number {
my $in = shift;
my $out =
( $in =~ /^(-?\d*(?:\.?\d+))\^(-?\d*(?:\.?\d+))$/ ) ? $1**$2 : $in;
return $in if $out =~ /[^\d]/; # elo
return 0 + $out;
}
sub _build_types {
( run in 0.997 second using v1.01-cache-2.11-cpan-39bf76dae61 )