Geo-Coder-List
view release on metacpan or search on metacpan
lib/Geo/Coder/List.pm view on Meta::CPAN
L<Object::Configure>; for example, setting
C<GEO__CODER__LIST__carp_on_warn=1> causes warnings to use L<Carp>.
use Geo::Coder::List;
use CHI;
# With an optional L2 cache (any CHI driver works)
my $geocoder = Geo::Coder::List->new(
cache => CHI->new(driver => 'Memory', global => 1),
debug => 0,
);
# Clone an existing object with a higher debug level
my $verbose = $geocoder->new(debug => 2);
=head3 API SPECIFICATION
=head4 INPUT
# Params::Validate::Strict schema
{
cache => {
type => [ 'hashref', 'object' ], # OBJECT must implement get($key) and set($key, $value, $ttl)
optional => 1,
},
debug => {
type => 'boolean',
optional => 1,
default => 0,
},
# Any additional key is forwarded to Object::Configure
}
=head4 OUTPUT
# Return::Set schema
OBJECT blessed into Geo::Coder::List
=cut
sub new
{
my $class = shift;
my $params = Params::Get::get_params(undef, \@_) || {};
# Handle the rare Geo::Coder::List::new() (function-style) invocation
if(!defined($class)) {
if(scalar keys %{$params} > 0) {
# Using ::new() with arguments is not supported
carp(__PACKAGE__, ' use ->new() not ::new() to instantiate');
return;
}
# FIXME: cloning does not work when called as ::new() with arguments
$class = __PACKAGE__;
} elsif(blessed($class)) {
# Shallow clone merged with new params; log is always fresh so the
# clone starts with an empty event history independent of the original
return bless { %{$class}, %{$params}, log => [] }, ref($class);
}
# Let Object::Configure overlay defaults from environment / config files
$params = Object::Configure::configure($class, $params);
# Fill in any %config defaults the caller did not explicitly supply
for my $key (keys %config) {
$params->{$key} //= $config{$key};
}
# Bless and return; params override scalar defaults but locations/log
# are always initialised fresh so callers cannot inject stale state
return bless {
debug => DEBUG_DEFAULT,
geocoders => [],
%{$params},
locations => {},
log => [],
}, $class;
}
# =============================================================================
=head2 push
Appends a geocoder to the chain. Geocoders are tried in the order they
were pushed. Returns C<$self> so calls can be chained.
A plain geocoder object is tried for every location. A hashref with
C<regex>, C<geocoder>, and optional C<limit> keys restricts the geocoder to
locations matching the regex and caps total queries at C<limit>.
my $list = Geo::Coder::List->new()
->push({ regex => qr/USA$/, geocoder => Geo::Coder::CA->new(), limit => 100 })
->push(Geo::Coder::OSM->new());
=head3 API SPECIFICATION
=head4 INPUT
# Params::Validate::Strict schema
{
geocoder => {
type => OBJECT | HASHREF,
required => 1,
# HASHREF must contain: geocoder => OBJECT
# HASHREF may contain: regex => Regexp
# limit => SCALAR (positive integer)
},
}
=head4 OUTPUT
# Return::Set schema
OBJECT blessed into Geo::Coder::List # $self, for chaining
=cut
sub push
{
# Deliberately NOT using Params::Get here: passing the hashref through it
# would stringify the compiled qr// object, destroying the regex.
my ($self, $geocoder) = @_;
( run in 1.049 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )