class GoogleMaps::Services::Convert

Converts Ruby types to string representations suitable for Google Maps API server.

Public Class Methods

bounds(arg) click to toggle source

Converts a lat/lng bounds to a comma- and pipe-separated string.

@param [Hash] arg The bounds. A hash with two entries - “southwest” and “northeast”.

@example Converts lat/lng bounds to comma- and pipe-separated string

sydney_bounds = {
  :northeast => { :lat => -33.4245981, :lng => 151.3426361 },
  :southwest => { :lat => -34.1692489, :lng => 150.502229 }
}
Convert.bounds(sydney_bounds) # '-34.169249,150.502229|-33.424598,151.342636'

@return [String] comma- and pipe-separated string.

# File lib/googlemaps/services/util.rb, line 220
def self.bounds(arg)
  raise TypeError, "#{__method__.to_s} expected a Hash of bounds." unless arg.is_a? Hash
  "#{to_latlng(arg[:southwest])}|#{to_latlng(arg[:northeast])}"
end
components(arg) click to toggle source

Converts a Hash of components to the format expect by the Google Maps API server.

@param [Hash] arg The component filter. @example Converts a components hash to server-friendly string

c = {"country" => ["US", "BE"], "postal_code" => 7452}
Convert.components(c) # 'country:BE|country:US|postal_code:7452'

@return [String] Server-friendly string representation

# File lib/googlemaps/services/util.rb, line 200
def self.components(arg)
  raise TypeError, "#{__method__.to_s} expected a Hash of components." unless arg.is_a? Hash

  arg.map { |c, val|
    ArrayBox.wrap(val).map {|elem| "#{c}:#{elem}"}.sort_by(&:downcase)
  }.join('|')
end
decode_polyline(polyline) click to toggle source

Decodes a Polyline string into an array of lat/lng hashes.

See the developer docs for a detailed description of this algorithm: developers.google.com/maps/documentation/utilities/polylinealgorithm

@param [String] polyline An encoded polyline.

@return [Array] an array of lat/lng hashes.

# File lib/googlemaps/services/util.rb, line 266
def self.decode_polyline(polyline)
  raise TypeError, "#{__method__.to_s} expected an argument of type String." unless polyline.is_a? String
  points = Array.new
  index, lat, lng = 0, 0, 0

  while index < polyline.length
    result = 1
    shift = 0
    while true
      b = polyline[index].ord - 63 - 1
      index += 1
      result += (b << shift)
      shift += 5
      if b < 0x1f
        break
      end
    end
    lat += (result & 1) != 0 ? (~result >> 1) : (result >> 1)

    result = 1
    shift = 0
    while true
      b = polyline[index].ord - 63 - 1
      index += 1
      result += (b << shift)
      shift += 5
      if b < 0x1f
        break
      end
    end
    lng += (result & 1) != 0 ? ~(result >> 1) : (result >> 1)

    points.push({:lat => lat * 1e-5, :lng => lng * 1e-5})
  end
  points
end
encode_polyline(points) click to toggle source

Encodes an array of points into a polyline string.

See the developer docs for a detailed description of this algorithm: developers.google.com/maps/documentation/utilities/polylinealgorithm

@param [Array] points Array of lat/lng hashes.

@return [String] a polyline string.

# File lib/googlemaps/services/util.rb, line 233
def self.encode_polyline(points)
  raise TypeError, "#{__method__.to_s} expected an Array of points." unless points.is_a? Array
  last_lat, last_lng = 0, 0
  result = ''
  points.each { |point|
    lat = (point[:lat] * 1e5).round.to_i
    lng = (point[:lng] * 1e5).round.to_i
    delta_lat = lat - last_lat
    delta_lng = lng - last_lng

    [delta_lat, delta_lng].each { |val|
      val = (val < 0) ? ~(val << 1) : (val << 1)
      while val >= 0x20
        result += ((0x20 | (val & 0x1f)) + 63).chr
        val >>= 5
      end
      result += (val + 63).chr
    }

    last_lat = lat
    last_lng = lng
  }
  result
end
format_float(arg) click to toggle source

Formats a float value to as short as possible.

@param [Float] arg The lat or lng float. @example Formats the lat or lng float

Convert.format_float(45.1289700)

@return [String] formatted value of lat or lng float

# File lib/googlemaps/services/util.rb, line 164
def self.format_float(arg)
  arg.to_s.chomp('0').chomp('.')
end
get_mime_type(content_type) click to toggle source

Returns the MIME type from the given header value.

@param [String] content_type The Content-Type header value.

@return [String] the MIME type value.

# File lib/googlemaps/services/util.rb, line 324
def self.get_mime_type(content_type)
  content_type.split(';').first
end
join_array(sep, arg) click to toggle source

If arg is array-like, then joins it with sep

@param [String] sep Separator string. @param [Object] arg Object to coerce into an array.

@return [String] a joined string.

# File lib/googlemaps/services/util.rb, line 188
def self.join_array(sep, arg)
  ArrayBox.wrap(arg).join(sep)
end
piped_location(arg) click to toggle source

Joins an array of locations into a pipe separated string, handling the various formats supported for lat/lng values.

@param [Array] arg Array of locations. @example Joins the locations array to pipe-separated string

arr = [{ :lat => -33.987486, :lng => 151.217990}, "Brussels"]
Convert.piped_location(arr) # '-33.987486,151.21799|Brussels'

@return [String] pipe-separated string.

# File lib/googlemaps/services/util.rb, line 177
def self.piped_location(arg)
  raise TypeError, "#{__method__.to_s} expected argument to be an Array." unless arg.instance_of? Array
  arg.map { |location| to_latlng(location) }.join('|')
end
rectangular_dimensions(size) click to toggle source

Returns the rectangular dimensions in the form {horizontal_value}x{vertical_value}.

@example

Convert.rectangular_dimensions({:length => 500, :width => 400}) # "500x400"

@param [Hash] size The size hash.

@return [String] a string value in the form “lengthxwidth”.

# File lib/googlemaps/services/util.rb, line 336
def self.rectangular_dimensions(size)
  raise TypeError, "#{__method__.to_s} expected a Hash." unless size.is_a? Hash
  "#{size[:length]}x#{size[:width]}"
end
shortest_path(locations) click to toggle source

Returns the shortest representation of the given locations.

The Elevation API limits requests to 2000 characters, and accepts multiple locations either as pipe-delimited lat/lng values, or an encoded polyline, so we determine which is shortest and use it.

@param [Array] locations The lat/lng array.

@return [String] shortest path.

# File lib/googlemaps/services/util.rb, line 312
def self.shortest_path(locations)
  raise TypeError, "#{__method__.to_s} expected an Array of locations." unless locations.is_a? Array
  encoded = "enc:#{encode_polyline(locations)}"
  unencoded = piped_location(locations)
  encoded.length < unencoded.length ? encoded : unencoded
end
to_latlng(arg) click to toggle source

Converts a lat/lng value to a comma-separated string.

@param [String, Hash] arg The lat/lng value. @example Convert lat/lng value to comma-separated string

Convert.to_latlng("45.458878,-39.56487")
Convert.to_latlng("Brussels")
Convert.to_latlng({ :lat => 45.458878, :lng => -39.56487 })

@return [String] comma-separated string.

# File lib/googlemaps/services/util.rb, line 146
def self.to_latlng(arg)
  case arg
  when String
    arg
  when Hash
    "#{self.format_float(arg[:lat])},#{self.format_float(arg[:lng])}"
  else
    raise TypeError, "#{__method__.to_s} expected location to be String or Hash."
  end
end
unix_time(val) click to toggle source

Converts the value into a unix time (seconds since unix epoch).

@param [Integer, Time, Date] val value to convert to unix time format. @example converts value to unix time

Convert.unix_time(1472809264)
Convert.unix_time(Time.now)
Convert.unix_time(Date.parse("2016-09-02"))

@return [String] seconds since unix epoch.

# File lib/googlemaps/services/util.rb, line 124
def self.unix_time(val)
  case val
  when Integer
    val.to_s
  when Time
    val.to_i.to_s
  when Date
    val.to_time.to_i.to_s
  else
    raise TypeError, "#{__method__.to_s} expected value to be Integer, Time or Date."
  end
end