Class: Barometer::Query

Inherits:
Object
  • Object
show all
Defined in:
lib/barometer/query.rb

Overview

This class represents a query and can answer the questions that a Barometer will need to measure the weather

Summary:

When you create a new Query, you set the query string
ie: "New York, NY" or "90210"
The class will then determine the query string format
ie: :zipcode, :postalcode, :geocode, :coordinates
Now, when a Weather API driver asks for the query, it will prefer
certain formats, and only permit certain formats.  The Query class
will attempt to either return the query string as-is if acceptable,
or it will attempt to convert it to a format that is acceptable
(most likely this conversion will use Googles geocoding service using
the Graticule gem).  Worst case scenario is that the Weather API will
not accept the query string.

Defined Under Namespace

Classes: Format

Constant Summary collapse

FORMATS =

This array defines the order to check a query for the format

%w(
  ShortZipcode Zipcode Postalcode WeatherID Coordinates Icao WoeID Geocode
)
FORMAT_MAP =
{
  :short_zipcode => "ShortZipcode", :zipcode => "Zipcode",
  :postalcode => "Postalcode", :weather_id => "WeatherID",
  :coordinates => "Coordinates", :icao => "Icao",
  :woe_id => "WoeID", :geocode => "Geocode"
}

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(query = nil) ⇒ Query

Returns a new instance of Query.



37
38
39
40
41
42
# File 'lib/barometer/query.rb', line 37

def initialize(query=nil)
  return unless query
  @q = query
  self.analyze!
  @conversions = {}
end

Instance Attribute Details

#conversionsObject

Returns the value of attribute conversions.



35
36
37
# File 'lib/barometer/query.rb', line 35

def conversions
  @conversions
end

#country_codeObject

Returns the value of attribute country_code.



34
35
36
# File 'lib/barometer/query.rb', line 34

def country_code
  @country_code
end

#formatObject

Returns the value of attribute format.



34
35
36
# File 'lib/barometer/query.rb', line 34

def format
  @format
end

#geoObject

Returns the value of attribute geo.



35
36
37
# File 'lib/barometer/query.rb', line 35

def geo
  @geo
end

#qObject



44
45
46
# File 'lib/barometer/query.rb', line 44

def q
  format ? Barometer::Query::Format.const_get(FORMAT_MAP[format.to_sym].to_s).convert_query(@q) : @q
end

#timezoneObject

Returns the value of attribute timezone.



35
36
37
# File 'lib/barometer/query.rb', line 35

def timezone
  @timezone
end

Instance Method Details

#analyze!Object

analyze the saved query to determine the format. this delegates the detection to each formats class until th right one is found



52
53
54
55
56
57
58
59
60
61
# File 'lib/barometer/query.rb', line 52

def analyze!
  return unless @q
  FORMATS.each do |format|
    if Query::Format.const_get(format.to_s).is?(@q)
      @format = Query::Format.const_get(format.to_s).format
      @country_code = Query::Format.const_get(format.to_s).country_code(@q)
      break
    end
  end
end

#convert!(preferred_formats = nil) ⇒ Object

take a list of acceptable (and ordered by preference) formats and convert the current query (q) into the most preferred and acceptable format. a side effect of the conversions may reveal the country_code, if so save it

Raises:

  • (ArgumentError)


67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/barometer/query.rb', line 67

def convert!(preferred_formats=nil)
  raise ArgumentError unless (preferred_formats && preferred_formats.size > 0)
  
  # why convert if we are already there?
  # (except in the case that the serivce excepts coordinates and we have a
  # a geocode ... the google geocode results are superior)
  #
  skip_conversion = false
  unless (@format.to_sym == Query::Format::Geocode.format) &&
         preferred_formats.include?(Query::Format::Coordinates.format)
    if preferred_formats.include?(@format.to_sym)
      skip_conversion = true
      converted_query = self.dup
    end
  end
  
  unless skip_conversion
    # go through each acceptable format and try to convert to that
    converted = false
    converted_query = Barometer::Query.new
    preferred_formats.each do |preferred_format|
      klass = FORMAT_MAP[preferred_format.to_sym]
      # if we discover that the format we have is the preferred format, return it
      if preferred_format == @format
        converted = true
        converted_query = Barometer::Query.new(@q)
      end
      unless converted
        unless converted_query = get_conversion(preferred_format)
          converted_query = Query::Format.const_get(klass.to_s).to(self)
        end  
        converted = true if converted_query
      end
      if converted
        converted_query.country_code ||= Query::Format.const_get(klass.to_s).country_code(converted_query.q)
        post_conversion(converted_query)
        break
      end
    end
  end
  
  # force geocode?, unless we already did
  #
  if Barometer.force_geocode && !@geo
    if converted_query && converted_query.geo
      @geo = converted_query.geo
    elsif converted_query
      puts "enhance geocode: #{converted_query.q}" if Barometer::debug?
      geo_query = Query::Format::Coordinates.to(converted_query)
      @geo = geo_query.geo if (geo_query && geo_query.geo)
      converted_query.geo = @geo.dup
    end
  end
  
  # enhance timezone?, unless we already did
  #
  if Barometer.enhance_timezone && !@timezone
    if converted_query && converted_query.timezone
      @geo = converted_query.timezone
    elsif @geo && @geo.latitude && @geo.longitude
      puts "enhance timezone: #{@geo.latitude}, #{@geo.longitude}" if Barometer::debug?
      @timezone = WebService::Timezone.fetch(@geo.latitude,@geo.longitude)
      converted_query.timezone = @timezone.dup
    end
  end
  
  converted_query
end

#get_conversion(format) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/barometer/query.rb', line 147

def get_conversion(format)
  return nil unless format && @conversions
  puts "found: #{self.format} -> #{format.to_sym} = #{self.q} -> #{@conversions[format.to_sym]}" if Barometer::debug? && @conversions.has_key?(format.to_sym)
  # re-constuct converted query
  if q = @conversions[format.to_sym]
    converted_query = self.dup
    converted_query.q = q
    converted_query.format = format
    converted_query
  else
    nil
  end
end

#latitudeObject



161
162
163
164
# File 'lib/barometer/query.rb', line 161

def latitude
  return nil unless self.format == Query::Format::Coordinates.format
  Query::Format::Coordinates.parse_latitude(self.q)
end

#longitudeObject



166
167
168
169
# File 'lib/barometer/query.rb', line 166

def longitude
  return nil unless self.format == Query::Format::Coordinates.format
  Query::Format::Coordinates.parse_longitude(self.q)
end

#post_conversion(converted_query) ⇒ Object

save the important parts of the conversion … by saving conversion we can avoid doing the same conversion multiple times



139
140
141
142
143
144
145
# File 'lib/barometer/query.rb', line 139

def post_conversion(converted_query)
  return unless (converted_query && converted_query.q && converted_query.format)
  @conversions = {} unless @conversions
  return if @conversions.has_key?(converted_query.format.to_sym)
  puts "store: #{self.format} -> #{converted_query.format.to_sym} = #{self.q} -> #{converted_query.q}" if Barometer::debug?
  @conversions[converted_query.format.to_sym] = converted_query.q
end