Skip to content

Commit

Permalink
subclasses no longer need to register themselves;
Browse files Browse the repository at this point in the history
  • Loading branch information
drhyde committed May 27, 2008
1 parent 2a71b26 commit 13825fa
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 60 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
2008-05-27 1.6 Magic country detection now works (thanks to
Jos Boumans for reporting the bug);
New UK allocations

2008-02-27 1.581 Added dependency on perl 5.006 (DBM::Deep uses 'our');
Removed docs from N::P::UK::DBM::Deep and
replaced with note about its status;
Expand Down
1 change: 1 addition & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,4 @@ lib/Number/Phone/UK/Exchanges.pm
lib/Number/Phone/UK/DBM/Deep/Array.pm
lib/Number/Phone/UK/DBM/Deep/Hash.pm
lib/Number/Phone/UK/DBM/Deep.pm
t/30_find-right-subclass.t
2 changes: 1 addition & 1 deletion Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use 5.006;
use ExtUtils::MakeMaker;
WriteMakefile(
NAME => 'Number::Phone',
VERSION => 1.581,
VERSION => 1.6,
PREREQ_PM => {
'Scalar::Util' => 0,
# commented out cos 1.0 is incompatible
Expand Down
6 changes: 0 additions & 6 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
$ perl -Ilib -MData::Dumper -MNumber::Phone::UK -e 'print Dumper(Number::Phone->new("+441234567890"))'
$VAR1 = bless( do{\(my $o = '+441234567890')}, 'Number::Phone::UK' );

$ perl -Ilib -MData::Dumper -MNumber::Phone -e 'print Dumper(Number::Phone->new("+441234567890"))'
$VAR1 = '';

better OFCOM parser
more systematic UK tests
details for NANP-ish countries
Expand Down
4 changes: 2 additions & 2 deletions build-data.realwork
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ while(my $line = <S8>) {
$line =~ s/,$/,""/;
$csv->parse($line) || die("Bad CSV line in s8_code.txt\n\n$line\n\n");
my @fields = $csv->fields();
next if($fields[3] !~ /^Allocated( for Migration only)?$/); # || $fields[5] eq 'mixed operators');
next if($fields[3] !~ /^Allocated( \(Closed Range\)| for Migration only)?$/); # || $fields[5] eq 'mixed operators');

my $retard = join('',@fields[0,1,2]);
my $telco = $fields[6];
Expand Down Expand Up @@ -169,7 +169,7 @@ while(my $line = <S7>) {

(my $retard = join('',@fields[0, 1])) =~ s/\D//g; # there's spaces in OFCOM's data!
my $telco = $fields[4];
my $format = $fields[6];
my $format = $fields[6] || '10 digit numbers';

push @telco_length_data, [$retard, $telco, $format];
if($fields[5] eq 'Mobile services') {
Expand Down
93 changes: 47 additions & 46 deletions lib/Number/Phone.pm
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ use Scalar::Util 'blessed';

use Number::Phone::Country qw(noexport uk);

our $VERSION = 1.581;
our %subclasses = ();
our $VERSION = 1.6;

my @is_methods = qw(
is_valid is_allocated is_in_use
Expand All @@ -21,22 +20,22 @@ foreach my $method (
@is_methods, qw(
country_code regulator areacode areaname
subscriber operator translates_to
format location
format location
)
) {
no strict 'refs';
*{__PACKAGE__."::$method"} = sub {
my $self = shift;
return undef if(blessed($self) && $self->isa(__PACKAGE__));
return undef if(blessed($self) && $self->isa(__PACKAGE__));
my $pkg = __PACKAGE__;
$self = shift if(
$self eq __PACKAGE__ ||
substr($self, 0, 2 + length(__PACKAGE__)) eq __PACKAGE__.'::'
);
$self = __PACKAGE__->new($self)
unless(blessed($self) && $self->isa(__PACKAGE__));
return $self->$method() if($self);
undef;
return $self->$method() if($self);
undef;
}
}

Expand All @@ -47,19 +46,19 @@ sub type {
no strict 'refs';

unless(blessed($parm) && $parm->isa(__PACKAGE__)) {
if(
if(
$parm eq __PACKAGE__ ||
substr($parm, 0, 2 + length(__PACKAGE__)) eq __PACKAGE__.'::'
) {
substr($parm, 0, 2 + length(__PACKAGE__)) eq __PACKAGE__.'::'
) {
$class = $parm;
$parm = shift;
}
$parm = shift;
}
$parm = $class->new($parm);
}

my $rval = $parm ?
[grep { $parm->$_() } @is_methods] :
undef;
undef;
wantarray() ? @{$rval} : $rval;
}

Expand All @@ -84,17 +83,22 @@ In a sub-class ...
package Number::Phone::UK;
use base 'Number::Phone';
$Number::Phone::subclasses{country_code()} = __PACKAGE__;
and to magically use the right subclass ...
use Number::Phone;
$daves_phone = Number::Phone->new('+442087712924');
$daves_other_phone = Number::Phone->new('+44 7979 866 975');
if($daves_phone->is_mobile()) {
send_rude_SMS();
}
in the example, the +44 is recognised as the country code for the UK,
so the appropriate country-specific module is loaded if available.
If you pass in a bogus country code or one for a country for which
no supporting module is available, the constructor will return undef.
=head1 IMPORTANT NOTE WHAT YOU SHOULD READ
All previous versions had a dependency on the excellent DBM::Deep module.
Expand All @@ -110,18 +114,20 @@ sub new {
unless($number);
$number =~ s/\D//g;

foreach my $retard (
map { substr($number, 0, $_) }
reverse 1 .. length($number)
) {
return $subclasses{$retard}->new("+$number") if($subclasses{$retard});
}
# $number = '+'.$number;
# my $country = Number::Phone::Country::phone2country($number);
# return undef unless($country);
# eval "use Number::Phone::$country";
# return undef if($@);
# return "Number::Phone::$country"->new($number);
# foreach my $retard (
# map { substr($number, 0, $_) }
# reverse 1 .. length($number)
# ) {
# return $subclasses{$retard}->new("+$number") if($subclasses{$retard});
# }

$number = "+$number" unless($number =~ /^\+/);
my $country = Number::Phone::Country::phone2country($number);
return undef unless($country);
$country = "NANP" if($number =~ /^\+1/);
eval "use Number::Phone::$country";
return undef if($@);
return "Number::Phone::$country"->new($number);
}

=head1 METHODS
Expand Down Expand Up @@ -330,19 +336,10 @@ If a country code is specified, and a subclass for that country is available,
the phone number is passed to its constructor unchanged.
If only one parameter is passed, then we try to figure out which is the right
country subclass to use thus:
=over 4
If the phone number begins with a + sign we take the following few digits
as a country code, look up the country that code is assigned to, and if
the module exists, call its constructor with the supplied phone number.
Otherwise, we try the constructors for all registered subclasses. If one
of them returns an object, we return that. However, if none of them succeed,
or if 2 or more succeed, this is a failure.
=back
country subclass to use by pre-pending a + sign to the number if
there isn't one, and looking the country up using
Number::Phone::Country. That gives us a two letter country code that
is used to try to load the right module.
The constructor returns undef if it can not figure out which subclass to
use.
Expand All @@ -356,19 +353,23 @@ The constructor should take a single parameter, a phone number, and should
validate that. If the number is valid (use your C<is_valid()> method!) then
you can return a blessed object. Otherwise you should return undef.
To register your subclass so that Number::Phone can automagically use it when
appropriate, do thus:
$Number::Phone::subclasses{country_code()} = __PACKAGE__;
as in the SYNOPSIS above.
The constructor *must* be capable of accepting a number with the
+ sign and the country's numeric code attached, but should also accept
numbers in the preferred local format (eg 01234 567890 in the UK, which
is the same number as +44 1234 567890) so that users can go straight
to your class without going through Number::Phone's magic country
detector.
Subclasses' names should be Number::Phone::XX, where XX is the two letter
ISO code for the country, in upper case. So, for example, France would be
FR and Ireland would be IE. As usual, the UK is an exception, using UK
instead of the ISO-mandated GB. NANP countries are also an exception,
going like Number::Phone::NANP::XX.
Note that subclasses no longer need to register themselves with
Number::Phone. In fact, registration is now *ignored* as the magic
country detector now works properly.
=head1 BUGS/FEEDBACK
Please report bugs by email or using http://rt.cpan.org, including,
Expand All @@ -385,6 +386,6 @@ perl itself.
David Cantrell E<lt>david@cantrell.org.ukE<gt>
Copyright 2004 - 2007
Copyright 2004 - 2008
=cut
3 changes: 3 additions & 0 deletions lib/Number/Phone/Country.pm
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,11 @@ my %idd_codes = (
8818 => 'Globalstar', # |
8819 => 'Globalstar', # /
882 => 'InternationalNetworks',
# 979 is used for testing when we fail to load a module when we
# know what "country" it is
979 => 'InternationalPremiumRate',
991 => 'ITPCS',
# 999 deliberately NYI for testing
);

sub phone2country {
Expand Down
2 changes: 0 additions & 2 deletions lib/Number/Phone/NANP.pm
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ use Number::Phone::Country qw(noexport);

our $VERSION = 1.1;

$Number::Phone::subclasses{country_code()} = __PACKAGE__;

my $cache = {};

=head1 NAME
Expand Down
2 changes: 0 additions & 2 deletions lib/Number/Phone/UK.pm
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ use base 'Number::Phone';

our $VERSION = 1.551;

$Number::Phone::subclasses{country_code()} = __PACKAGE__;

my $cache = {};

=head1 NAME
Expand Down
10 changes: 9 additions & 1 deletion t/01_uk_data.t
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use strict;

use Number::Phone::UK;

BEGIN { $| = 1; print "1..56\n"; }
BEGIN { $| = 1; print "1..59\n"; }

my $test = 0;

Expand Down Expand Up @@ -153,3 +153,11 @@ print 'ok '.(++$test)." 4+5 (mixed) format works\n";
print 'not ' unless(Number::Phone->new('+441768881000')->format() eq
'+44 1768 881000');
print 'ok '.(++$test)." 4+6 (mixed) format works\n";

$number = Number::Phone->new('+447500000000');
print 'not ' unless($number->is_mobile());
print 'ok '.(++$test)." 075 mobiles correctly identified\n";
print 'not ' unless($number->operator() eq 'Vodafone Ltd');
print 'ok '.(++$test)." 075 mobiles have right operator\n";
print 'not ' unless($number->format() eq '+44 7500000000');
print 'ok '.(++$test)." 075 mobiles have right operator\n";
33 changes: 33 additions & 0 deletions t/30_find-right-subclass.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/perl -w

use Test::More tests => 5;
use Scalar::Util qw(blessed);

use Number::Phone;

my $number = Number::Phone->new("+441234567890");
ok(blessed($number) && $number->isa('Number::Phone::UK'),
"N::P->new() works without specifically loading a country module");

$number = Number::Phone->new("+12265550199");
ok(blessed($number) && $number->isa('Number::Phone::NANP::CA'),
"... and it even works for the NANP!");

$number = Number::Phone->new("+18666232282");
ok(blessed($number) && $number->isa('Number::Phone::NANP'),
"... and it even works for the non-geographic NANP!");

# +999 is "Proposed disaster relief (TDR) service", NYI by N::P::Country
ok(
!blessed(Number::Phone->new("+999123")) &&
!defined(Number::Phone->new("+999123")),
"A country code not recognised by N::P::Country returns false"
);
# +979 is International Premium Rate Service
ok(
!blessed(Number::Phone->new("+979123")) &&
!defined(Number::Phone->new("+979123")),
"A country code whose module we can't find returns false"
);

# FIXME - Kazakhstan/Russia weirdness

0 comments on commit 13825fa

Please sign in to comment.