Class: Graticule::Geocoder::Multi

Inherits:
Object
  • Object
show all
Defined in:
lib/graticule/geocoder/multi.rb

Defined Under Namespace

Classes: ParallelLookup, SerialLookup

Instance Method Summary collapse

Constructor Details

#initialize(*geocoders, &acceptable) ⇒ Multi

The Multi geocoder allows you to use multiple geocoders in succession.

geocoder = Graticule.service(:multi).new(
  Graticule.service(:google).new("api_key"),
  Graticule.service(:yahoo).new("api_key"),
)
geocoder.locate '49423' # <= tries geocoders in succession

The Multi geocoder will try the geocoders in order if a Graticule::AddressError is raised. You can customize this behavior by passing in a block to the Multi geocoder. For example, to try the geocoders until one returns a result with a high enough precision:

geocoder = Graticule.service(:multi).new(geocoders) do |result|
  [:address, :street].include?(result.precision)
end

Geocoders will be tried in order until the block returned true for one of the results

Use the :timeout option to specify the number of seconds to allow for each geocoder before raising a Timout::Error (defaults to 10 seconds).

Graticule.service(:multi).new(geocoders, :timeout => 3)

32
33
34
35
36
# File 'lib/graticule/geocoder/multi.rb', line 32

def initialize(*geocoders, &acceptable)
  @options = {:timeout => 10, :async => false}.merge(geocoders.extract_options!)
  @acceptable = acceptable || Proc.new { true }
  @geocoders = geocoders
end

Instance Method Details

#locate(address) ⇒ Object


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/graticule/geocoder/multi.rb', line 38

def locate(address)
  @lookup = @options[:async] ? ParallelLookup.new : SerialLookup.new
  last_error = nil
  @geocoders.each do |geocoder|
    @lookup.perform do
      begin
        result = nil
        Timeout.timeout(@options[:timeout]) do
          result = geocoder.locate address
        end
        result if @acceptable.call(result)
      rescue => e
        last_error = e
        nil
      end
    end
  end
  @lookup.result || raise(last_error || AddressError.new("Couldn't find '#{address}' with any of the services"))
end