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 )