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 )