The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Number::MuPhone - parsing and displaying phone numbers in pure Perl

NOTE: this is a full rewrite and is not backwards compatible with earlier versions of this module.

DESCRIPTION

Parse, validate (loosely in some cases) and display phone numbers as expected.

This has stripped down functionality compared to libphonenumber, but it is also Pure Perl (TM), is simpler to use, and contains the core functionality needed by common use cases.

If you have functionality requests, please let me know: mailto:clive.holloway@gmail.com

All number regexes are derived from the XML file supplied by:

https://github.com/google/libphonenumber/

BASIC USAGE

Instantiate an instance using one of the following syntaxes

    # single arg: E.123 formatted number, scalar shortcut
    my $num = Number::MuPhone->new('+1 203 503 1199');

    # single arg: E.123 formatted number, hashref format
    my $num = Number::MuPhone->new({
                number => '+1 203 503 1199'
              });

    # double arg, number and country - number can be in local or E.123 format, scalar args
    my $num = Number::MuPhone->new('+1 203 503 1199','US");
    my $num = Number::MuPhone->new('(203) 503-1199','US');

    # double arg, number and country - number can be in local or E.123 format, hashref args
    my $num = Number::MuPhone->new({
                number  => '+1 203 503 1199'
                country => 'US',
              });
    my $num = Number::MuPhone->new({
                number  => '(203) 503-1199'
                country => 'US',
              });

    # after instantiation, check all is well before using the object
    if ($num->error) {
      # process the error
    }

ATTRIBUTES

number

The raw number sent in at instantiation - not needed (outside of logging, maybe)

extension

Extenstion number (digits only)

country

The 2 character country code sent in instantiation, or inferred from an E.123 number

error

If the args don't lead to a valid number at instantiation, this error will be set

country_name

Full text name of country (may be inaccurate for single arg instantiation - see below)

country_code

1-3 digit country code

national_dial

How you would dial this number within the country (including national dial code)

national_display

Display this number in the national number format

international_display

Display this number in the international number format (E.123)

e164

The number in E.164 format (+$COUNTRY_CODE$NUMBER[;ext=$EXTENSION])

e164_no_ext

The number in E.164 format, but with no extension (+$COUNTRY_CODE$NUMBER)

METHODS

dial_from

How to dial the number from the number/country sent in as an arg. eg

    my $uk_num1 = Number::MuPhone->new({ country => 'GB', number => '01929 552699' });
    my $uk_num2 = Number::MuPhone->new({ country => 'GB', number => '01929 552698' });
    my $us_num  = Number::MuPhone->new({ country => 'US', number => '203 503 1234' });

    # these all have the same output (01929552699)
    my $dial_from_uk = $uk_num1->dial_from($uk_num2);
    my $dial_from_uk = $uk_num1->dial_from('GB');
    my $dial_from_uk = $uk_num1->dial_from('+441929 552698');

    # similarly, dialling the number from the US (011441929552699)
    my $dial_from_us = $uk_num1->dial_from($us_num);
    my $dial_from_us = $uk_num1->dial_from('US');
    my $dial_from_us = $uk_num1->dial_from('+1 203 503 1234');

display_from

How to display the number for the number/country sent in as an arg. eg

    my $uk_num1 = Number::MuPhone->new({ country => 'GB', number => '01929 552699' });
    my $uk_num2 = Number::MuPhone->new({ country => 'GB', number => '01929 552698' });
    my $us_num  = Number::MuPhone->new({ country => 'US', number => '203 503 1234' });

    # these all have the same output (01929 552699)
    my $display_from_uk = $uk_num1->display_from($uk_num2);
    my $display_from_uk = $uk_num1->display_from('GB');
    my $display_from_uk = $uk_num1->display_from('+441929 552698');

    # similarly, dialling the number from the US (01144 1929 552699)
    my $display_from_us = $uk_num1->display_from($us_num);
    my $display_from_us = $uk_num1->display_from('US');
    my $display_from_us = $uk_num1->display_from('+1 203 503 1234');

A WARNING ABOUT INFERRED COUNTRIES

If you instantiate an object with an E.123 formatted number, the inferred country will be the 'main' country for that number. This is because Number::MuPhone is currently using the loosest regex available to validate a number for a country (this may change soon). This affects these country codes:

    Code       Main Country
    ====       ============
    1          US
    44         GB
    212        EH
    61         CC
    590        MF
    7          KZ
    599        BQ
    47         SJ
    262        YT

As far as functionality is concerned, you should see no difference, unless you want to use the country() attribute. To avoid this, instantiate with both number and country.

KEEPING UP TO DATE WITH CHANGES IN THE SOURCE XML FILE

The data used to validate and format the phone numbers comes from Google's libphonenumber:

https://github.com/google/libphonenumber/releases/latest

This distribution should come with a reasonably recent copy of the libphonenumber source XML, but you can also set up a cron to update your source data weekly, to ensure you don't have problems with new area codes as they get added (this happens probably more often than you think).

By default, Number::MuPhone's update script (perl-muphone-build-data) stores this data in the ~/.muphone directory, but you can overload this by setting the MUPHONE_BASE_DIR environment variable. Wherever you choose, it must be writeable by the user, and remember to expose the same ENV var to any scripts using Number::MuPhone (if needed).

When run, the following files are created in the ~/.muphone or $ENV{MUPHONE_BASE_DIR} dirs as appropriate

    ./etc/PhoneNumberMetadata.xml     # the libphonenumber source XML file
    ./lib/NumberMuPhoneData.pm        # the generated Number::MuPhone::Data
    ./t/check_data_module.t           # a little sanity script that runs after creating the data file

Currently, the extractor script only grabs the data we need, and removes spacing, to keep the size down.

If you want to examine all available data, set $DEBUG=1 (add in padding, switch commas to =>) and set $STRIP_SUPERFLUOUS_DATA=0 in the script and run it again. then look at the generated NumberMuPhoneData.pm

Initial run

Optionally, set the MUPHONE_BASE_DIR environment variable to point to your config directory (must be writeable). Otherwise, ~/.muphone will get used (default).

As the appropriate user, run:

    perl-muphone-build-data

Confirm the tests pass and the files are created (if no error output, tests passed, and all should be good).

Set up the cron to run weekly to update the data

    # using default data dir (~/.muphone)
    0 5 * * 1 /usr/local/bin/perl-muphone-build-data

    # using user specific data dir
    0 5 * * 1 MUPHONE_BASE_DIR=/path/to/config /usr/local/bin/perl-muphone-build-data

Dockerfile config

Similarly, add the perl-muphone-build-data script to your Dockerfile, as appropriate. If you're using Kubernetes, this might be enough, but for longer running Docker instances, you might want to consider setting up the cronjob within the image too.

If anyone has best practice recommendations for this, let me know and I'll update the POD :D