barometer 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +266 -0
- data/VERSION.yml +4 -0
- data/bin/barometer +63 -0
- data/lib/barometer.rb +52 -0
- data/lib/barometer/base.rb +52 -0
- data/lib/barometer/data.rb +15 -0
- data/lib/barometer/data/current.rb +93 -0
- data/lib/barometer/data/distance.rb +131 -0
- data/lib/barometer/data/forecast.rb +66 -0
- data/lib/barometer/data/geo.rb +98 -0
- data/lib/barometer/data/location.rb +20 -0
- data/lib/barometer/data/measurement.rb +161 -0
- data/lib/barometer/data/pressure.rb +133 -0
- data/lib/barometer/data/speed.rb +147 -0
- data/lib/barometer/data/sun.rb +35 -0
- data/lib/barometer/data/temperature.rb +164 -0
- data/lib/barometer/data/units.rb +55 -0
- data/lib/barometer/data/zone.rb +124 -0
- data/lib/barometer/extensions/graticule.rb +50 -0
- data/lib/barometer/extensions/httparty.rb +21 -0
- data/lib/barometer/query.rb +228 -0
- data/lib/barometer/services.rb +6 -0
- data/lib/barometer/services/google.rb +146 -0
- data/lib/barometer/services/noaa.rb +6 -0
- data/lib/barometer/services/service.rb +324 -0
- data/lib/barometer/services/weather_bug.rb +6 -0
- data/lib/barometer/services/weather_dot_com.rb +6 -0
- data/lib/barometer/services/wunderground.rb +285 -0
- data/lib/barometer/services/yahoo.rb +274 -0
- data/lib/barometer/weather.rb +187 -0
- data/spec/barometer_spec.rb +162 -0
- data/spec/data_current_spec.rb +225 -0
- data/spec/data_distance_spec.rb +336 -0
- data/spec/data_forecast_spec.rb +150 -0
- data/spec/data_geo_spec.rb +90 -0
- data/spec/data_location_spec.rb +59 -0
- data/spec/data_measurement_spec.rb +411 -0
- data/spec/data_pressure_spec.rb +336 -0
- data/spec/data_speed_spec.rb +374 -0
- data/spec/data_sun_spec.rb +76 -0
- data/spec/data_temperature_spec.rb +396 -0
- data/spec/data_zone_spec.rb +133 -0
- data/spec/fixtures/current_calgary_ab.xml +1 -0
- data/spec/fixtures/forecast_calgary_ab.xml +1 -0
- data/spec/fixtures/geocode_40_73.xml +1 -0
- data/spec/fixtures/geocode_90210.xml +1 -0
- data/spec/fixtures/geocode_T5B4M9.xml +1 -0
- data/spec/fixtures/geocode_calgary_ab.xml +1 -0
- data/spec/fixtures/geocode_newyork_ny.xml +1 -0
- data/spec/fixtures/google_calgary_ab.xml +1 -0
- data/spec/fixtures/yahoo_90210.xml +1 -0
- data/spec/query_spec.rb +469 -0
- data/spec/service_google_spec.rb +144 -0
- data/spec/service_wunderground_spec.rb +330 -0
- data/spec/service_yahoo_spec.rb +299 -0
- data/spec/services_spec.rb +1106 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/units_spec.rb +101 -0
- data/spec/weather_spec.rb +265 -0
- metadata +119 -0
@@ -0,0 +1,285 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# = Weather Underground
|
4
|
+
# www.wunderground.com
|
5
|
+
#
|
6
|
+
# - key required: NO
|
7
|
+
# - registration required: NO
|
8
|
+
# - supported countries: ALL
|
9
|
+
#
|
10
|
+
# === performs geo coding
|
11
|
+
# - city: YES
|
12
|
+
# - coordinates: YES
|
13
|
+
# NOTE: provides geo data for location and weather station
|
14
|
+
#
|
15
|
+
# === time info
|
16
|
+
# - sun rise/set: YES (today only)
|
17
|
+
# - provides timezone: YES
|
18
|
+
# - requires TZInfo: YES
|
19
|
+
#
|
20
|
+
# == resources
|
21
|
+
# - API: http://wiki.wunderground.com/index.php/API_-_XML
|
22
|
+
#
|
23
|
+
# === Possible queries:
|
24
|
+
# - http://api.wunderground.com/auto/wui/geo/GeoLookupXML/index.xml?query=94107
|
25
|
+
# - http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml?query=KSFO
|
26
|
+
# - http://api.wunderground.com/weatherstation/WXCurrentObXML.asp?ID=KCASANFR70
|
27
|
+
# - http://api.wunderground.com/auto/wui/geo/AlertsXML/index.xml?query=86445
|
28
|
+
# - http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml?query=Chicago,IL
|
29
|
+
#
|
30
|
+
# where query can be:
|
31
|
+
# - zipcode (US or Canadian)
|
32
|
+
# - city state; city, state
|
33
|
+
# - city
|
34
|
+
# - state
|
35
|
+
# - country
|
36
|
+
# - airport code (3-letter or 4-letter)
|
37
|
+
# - lat,lon
|
38
|
+
#
|
39
|
+
class Wunderground < Service
|
40
|
+
|
41
|
+
def self.accepted_formats
|
42
|
+
[:zipcode, :postalcode, :coordinates, :geocode]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.source_name
|
46
|
+
:wunderground
|
47
|
+
end
|
48
|
+
|
49
|
+
# these are the icon codes that indicate "wet", used by wet? function
|
50
|
+
def self.wet_icon_codes
|
51
|
+
%w(flurries rain sleet snow tstorms nt_flurries nt_rain nt_sleet nt_snow nt_tstorms)
|
52
|
+
end
|
53
|
+
def self.sunny_icon_codes
|
54
|
+
%w(clear mostlysunny partlysunny sunny partlycloudy)
|
55
|
+
end
|
56
|
+
|
57
|
+
def self._measure(measurement, query, metric=true)
|
58
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
59
|
+
raise ArgumentError unless query.is_a?(Barometer::Query)
|
60
|
+
measurement.source = self.source_name
|
61
|
+
|
62
|
+
# get current measurement
|
63
|
+
begin
|
64
|
+
current_result = self.get_current(query.preferred)
|
65
|
+
measurement.current = self.build_current(current_result, metric)
|
66
|
+
rescue Timeout::Error => e
|
67
|
+
return measurement
|
68
|
+
end
|
69
|
+
|
70
|
+
# get forecast measurement
|
71
|
+
begin
|
72
|
+
forecast_result = self.get_forecast(query.preferred)
|
73
|
+
measurement.forecast = self.build_forecast(forecast_result, metric)
|
74
|
+
rescue Timeout::Error => e
|
75
|
+
return measurement
|
76
|
+
end
|
77
|
+
|
78
|
+
measurement.location = self.build_location(current_result)
|
79
|
+
measurement.station = self.build_station(current_result)
|
80
|
+
measurement.timezone = self.build_timezone(forecast_result)
|
81
|
+
|
82
|
+
# add sun data to current
|
83
|
+
sun = nil
|
84
|
+
if measurement.current
|
85
|
+
sun = self.build_sun(forecast_result, measurement.timezone)
|
86
|
+
measurement.current.sun = sun
|
87
|
+
end
|
88
|
+
# use todays sun data for all future days
|
89
|
+
if measurement.forecast && sun
|
90
|
+
start_date = Date.parse(measurement.current.time)
|
91
|
+
measurement.forecast.each do |forecast|
|
92
|
+
days_in_future = forecast.date - start_date
|
93
|
+
forecast.sun = Barometer::Sun.add_days!(sun,days_in_future.to_i)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
measurement
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.build_current(data, metric=true)
|
101
|
+
raise ArgumentError unless data.is_a?(Hash)
|
102
|
+
|
103
|
+
current = CurrentMeasurement.new
|
104
|
+
#current.time = Time.parse(current_result['observation_time_rfc822']) unless
|
105
|
+
# current_result['observation_time_rfc822'].blank?
|
106
|
+
current.time = data['observation_time_rfc822']
|
107
|
+
current.local_time = data['observation_time']
|
108
|
+
current.humidity = data['relative_humidity'].to_i
|
109
|
+
current.icon = data['icon'] if data['icon']
|
110
|
+
|
111
|
+
current.temperature = Temperature.new(metric)
|
112
|
+
current.temperature << [data['temp_c'], data['temp_f']]
|
113
|
+
|
114
|
+
current.wind = Speed.new(metric)
|
115
|
+
current.wind.mph = data['wind_mph'].to_f
|
116
|
+
current.wind.degrees = data['wind_degrees'].to_i
|
117
|
+
current.wind.direction = data['wind_dir']
|
118
|
+
|
119
|
+
current.pressure = Pressure.new(metric)
|
120
|
+
current.pressure << [data['pressure_mb'], data['pressure_in']]
|
121
|
+
|
122
|
+
current.dew_point = Temperature.new(metric)
|
123
|
+
current.dew_point << [data['dewpoint_c'], data['dewpoint_f']]
|
124
|
+
|
125
|
+
current.heat_index = Temperature.new(metric)
|
126
|
+
current.heat_index << [data['heat_index_c'], data['heat_index_f']]
|
127
|
+
|
128
|
+
current.wind_chill = Temperature.new(metric)
|
129
|
+
current.wind_chill << [data['windchill_c'], data['windchill_f']]
|
130
|
+
|
131
|
+
current.visibility = Distance.new(metric)
|
132
|
+
current.visibility << [data['visibility_km'], data['visibility_mi']]
|
133
|
+
|
134
|
+
current
|
135
|
+
end
|
136
|
+
|
137
|
+
def self.build_forecast(data, metric=true)
|
138
|
+
raise ArgumentError unless data.is_a?(Hash)
|
139
|
+
forecasts = []
|
140
|
+
# go through each forecast and create an instance
|
141
|
+
if data && data['simpleforecast'] &&
|
142
|
+
data['simpleforecast']['forecastday']
|
143
|
+
|
144
|
+
data['simpleforecast']['forecastday'].each do |forecast|
|
145
|
+
forecast_measurement = ForecastMeasurement.new
|
146
|
+
forecast_measurement.icon = forecast['icon']
|
147
|
+
forecast_measurement.date = Date.parse(forecast['date']['pretty'])
|
148
|
+
forecast_measurement.pop = forecast['pop'].to_i
|
149
|
+
|
150
|
+
forecast_measurement.high = Temperature.new(metric)
|
151
|
+
forecast_measurement.high << [forecast['high']['celsius'],forecast['high']['fahrenheit']]
|
152
|
+
|
153
|
+
forecast_measurement.low = Temperature.new(metric)
|
154
|
+
forecast_measurement.low << [forecast['low']['celsius'],forecast['low']['fahrenheit']]
|
155
|
+
|
156
|
+
forecasts << forecast_measurement
|
157
|
+
end
|
158
|
+
end
|
159
|
+
forecasts
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.build_location(data)
|
163
|
+
raise ArgumentError unless data.is_a?(Hash)
|
164
|
+
location = Location.new
|
165
|
+
if data['display_location']
|
166
|
+
location.name = data['display_location']['full']
|
167
|
+
location.city = data['display_location']['city']
|
168
|
+
location.state_name = data['display_location']['state_name']
|
169
|
+
location.state_code = data['display_location']['state']
|
170
|
+
location.country_code = data['display_location']['country']
|
171
|
+
location.zip_code = data['display_location']['zip']
|
172
|
+
location.latitude = data['display_location']['latitude']
|
173
|
+
location.longitude = data['display_location']['longitude']
|
174
|
+
end
|
175
|
+
location
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.build_station(data)
|
179
|
+
raise ArgumentError unless data.is_a?(Hash)
|
180
|
+
station = Location.new
|
181
|
+
station.id = data['station_id']
|
182
|
+
if data['observation_location']
|
183
|
+
station.name = data['observation_location']['full']
|
184
|
+
station.city = data['observation_location']['city']
|
185
|
+
station.state_name = data['observation_location']['state_name']
|
186
|
+
station.state_code = data['observation_location']['state']
|
187
|
+
station.country_code = data['observation_location']['country']
|
188
|
+
station.zip_code = data['observation_location']['zip']
|
189
|
+
station.latitude = data['observation_location']['latitude']
|
190
|
+
station.longitude = data['observation_location']['longitude']
|
191
|
+
end
|
192
|
+
station
|
193
|
+
end
|
194
|
+
|
195
|
+
# <forecastday>
|
196
|
+
# <date>
|
197
|
+
# <pretty_short>9:00 PM CST</pretty_short>
|
198
|
+
# <pretty>9:00 PM CST on January 15, 2008</pretty>
|
199
|
+
# <isdst>0</isdst>
|
200
|
+
# <tz_short>CST</tz_short>
|
201
|
+
# <tz_long>America/Chicago</tz_long>
|
202
|
+
# </date>
|
203
|
+
# </forecastday>
|
204
|
+
def self.build_timezone(data)
|
205
|
+
raise ArgumentError unless data.is_a?(Hash)
|
206
|
+
timezone = nil
|
207
|
+
if data && data['simpleforecast'] &&
|
208
|
+
data['simpleforecast']['forecastday'] &&
|
209
|
+
data['simpleforecast']['forecastday'].first &&
|
210
|
+
data['simpleforecast']['forecastday'].first['date']
|
211
|
+
timezone = Barometer::Zone.new(
|
212
|
+
data['simpleforecast']['forecastday'].first['date']['tz_long']
|
213
|
+
)
|
214
|
+
end
|
215
|
+
timezone
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.build_sun(data, timezone)
|
219
|
+
raise ArgumentError unless data.is_a?(Hash)
|
220
|
+
raise ArgumentError unless timezone.is_a?(Barometer::Zone)
|
221
|
+
|
222
|
+
sun = nil
|
223
|
+
if data
|
224
|
+
time = nil
|
225
|
+
if data['simpleforecast'] &&
|
226
|
+
data['simpleforecast']['forecastday'] &&
|
227
|
+
data['simpleforecast']['forecastday'].first &&
|
228
|
+
data['simpleforecast']['forecastday'].first['date']
|
229
|
+
|
230
|
+
# construct current date
|
231
|
+
date_data = data['simpleforecast']['forecastday'].first['date']
|
232
|
+
time = Time.local(
|
233
|
+
date_data['year'], date_data['month'], date_data['day'],
|
234
|
+
date_data['hour'], date_data['min'], date_data['sec']
|
235
|
+
)
|
236
|
+
end
|
237
|
+
if time && data['moon_phase']
|
238
|
+
# get the sun rise and set times (ie "6:32 am")
|
239
|
+
if data['moon_phase']['sunrise']
|
240
|
+
rise = Time.local(
|
241
|
+
time.year, time.month, time.day,
|
242
|
+
data['moon_phase']['sunrise']['hour'],
|
243
|
+
data['moon_phase']['sunrise']['minute']
|
244
|
+
)
|
245
|
+
end
|
246
|
+
if data['moon_phase']['sunset']
|
247
|
+
set = Time.local(
|
248
|
+
time.year, time.month, time.day,
|
249
|
+
data['moon_phase']['sunset']['hour'],
|
250
|
+
data['moon_phase']['sunset']['minute']
|
251
|
+
)
|
252
|
+
end
|
253
|
+
|
254
|
+
sun = Sun.new(
|
255
|
+
timezone.tz.local_to_utc(rise),
|
256
|
+
timezone.tz.local_to_utc(set)
|
257
|
+
)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
261
|
+
sun || Sun.new
|
262
|
+
end
|
263
|
+
|
264
|
+
# use HTTParty to get the current weather
|
265
|
+
def self.get_current(query)
|
266
|
+
Barometer::Wunderground.get(
|
267
|
+
"http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml",
|
268
|
+
:query => {:query => query},
|
269
|
+
:format => :xml,
|
270
|
+
:timeout => Barometer.timeout
|
271
|
+
)['current_observation']
|
272
|
+
end
|
273
|
+
|
274
|
+
# use HTTParty to get the forecasted weather
|
275
|
+
def self.get_forecast(query)
|
276
|
+
Barometer::Wunderground.get(
|
277
|
+
"http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml",
|
278
|
+
:query => {:query => query},
|
279
|
+
:format => :xml,
|
280
|
+
:timeout => Barometer.timeout
|
281
|
+
)['forecast']
|
282
|
+
end
|
283
|
+
|
284
|
+
end
|
285
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# = Yahoo Weather
|
4
|
+
# www.yahoo.com
|
5
|
+
#
|
6
|
+
# - key required: NO
|
7
|
+
# - registration required: NO
|
8
|
+
# - supported countries: US (by zipcode), International (by Yahoo Location ID)
|
9
|
+
#
|
10
|
+
# === performs geo coding
|
11
|
+
# - city: YES
|
12
|
+
# - coordinates: YES
|
13
|
+
#
|
14
|
+
# === time info
|
15
|
+
# - sun rise/set: YES (today only)
|
16
|
+
# - provides timezone: PARTIAL (just short code)
|
17
|
+
# - requires TZInfo: NO
|
18
|
+
# NOTE: since this only supports US, the short code can be used
|
19
|
+
# to convert times (until yahoo location id support is added)
|
20
|
+
#
|
21
|
+
# == resources
|
22
|
+
# - API: http://developer.yahoo.com/weather/
|
23
|
+
#
|
24
|
+
# === Possible queries:
|
25
|
+
# - http://weather.yahooapis.com/forecastrss?p=94089
|
26
|
+
# - http://weather.yahooapis.com/forecastrss?p=USCA1116
|
27
|
+
# - http://weather.yahooapis.com/forecastrss?p=FRXX0076&u=c
|
28
|
+
#
|
29
|
+
# where query can be:
|
30
|
+
# - zipcode (US)
|
31
|
+
# - Yahoo Location ID (International) - not currently supported
|
32
|
+
#
|
33
|
+
# == notes
|
34
|
+
# - the Yahoo Location ID is a propreitary number (possibly shared with weather.com)
|
35
|
+
# so this driver currently does not provide a way to get/use this number,
|
36
|
+
# therefore International support is currently missing
|
37
|
+
#
|
38
|
+
class Yahoo < Service
|
39
|
+
|
40
|
+
def self.accepted_formats
|
41
|
+
[:zipcode]
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.source_name
|
45
|
+
:yahoo
|
46
|
+
end
|
47
|
+
|
48
|
+
# these are the icon codes that indicate "wet", used by wet? function
|
49
|
+
def self.wet_icon_codes
|
50
|
+
codes = [1] + (3..18).to_a + [35] + (37..43).to_a + (45..47).to_a
|
51
|
+
codes.collect {|c| c.to_s}
|
52
|
+
end
|
53
|
+
def self.sunny_icon_codes
|
54
|
+
codes = (29..34).to_a + [36]
|
55
|
+
codes.collect {|c| c.to_s}
|
56
|
+
end
|
57
|
+
|
58
|
+
# override, only currently supports US
|
59
|
+
def self.supports_country?(query=nil)
|
60
|
+
query && query.country_code && query.country_code.downcase == "us"
|
61
|
+
end
|
62
|
+
|
63
|
+
def self._measure(measurement, query, metric=true)
|
64
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
65
|
+
raise ArgumentError unless query.is_a?(Barometer::Query)
|
66
|
+
measurement.source = self.source_name
|
67
|
+
|
68
|
+
begin
|
69
|
+
result = self.get_all(query.preferred, metric)
|
70
|
+
rescue Timeout::Error => e
|
71
|
+
return measurement
|
72
|
+
end
|
73
|
+
|
74
|
+
measurement.current = self.build_current(result, metric)
|
75
|
+
measurement.forecast = self.build_forecast(result, metric)
|
76
|
+
measurement.location = self.build_location(result, query.geo)
|
77
|
+
|
78
|
+
# add to current
|
79
|
+
sun = nil
|
80
|
+
if measurement.current
|
81
|
+
sun = self.build_sun(result)
|
82
|
+
measurement.current.sun = sun
|
83
|
+
end
|
84
|
+
# use todays sun data for all future days
|
85
|
+
if measurement.forecast && sun
|
86
|
+
start_date = Date.parse(measurement.current.local_time)
|
87
|
+
measurement.forecast.each do |forecast|
|
88
|
+
days_in_future = forecast.date - start_date
|
89
|
+
forecast.sun = Barometer::Sun.add_days!(sun,days_in_future.to_i)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
measurement
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.build_current(data, metric=true)
|
97
|
+
raise ArgumentError unless data.is_a?(Hash)
|
98
|
+
current = CurrentMeasurement.new
|
99
|
+
if data
|
100
|
+
if data['item'] && data['item']['yweather:condition']
|
101
|
+
condition_result = data['item']['yweather:condition']
|
102
|
+
current.local_time = condition_result['date']
|
103
|
+
current.icon = condition_result['code']
|
104
|
+
current.condition = condition_result['text']
|
105
|
+
current.temperature = Temperature.new(metric)
|
106
|
+
current.temperature << condition_result['temp']
|
107
|
+
end
|
108
|
+
if data['yweather:atmosphere']
|
109
|
+
atmosphere_result = data['yweather:atmosphere']
|
110
|
+
current.humidity = atmosphere_result['humidity'].to_i
|
111
|
+
current.pressure = Pressure.new(metric)
|
112
|
+
current.pressure << atmosphere_result['pressure']
|
113
|
+
current.visibility = Distance.new(metric)
|
114
|
+
current.visibility << atmosphere_result['visibility']
|
115
|
+
end
|
116
|
+
if data['yweather:wind']
|
117
|
+
wind_result = data['yweather:wind']
|
118
|
+
current.wind = Speed.new(metric)
|
119
|
+
current.wind << wind_result['speed']
|
120
|
+
current.wind.degrees = wind_result['degrees'].to_f
|
121
|
+
current.wind_chill = Temperature.new(metric)
|
122
|
+
current.wind_chill << wind_result['chill']
|
123
|
+
end
|
124
|
+
end
|
125
|
+
current
|
126
|
+
end
|
127
|
+
|
128
|
+
def self.build_forecast(data, metric=true)
|
129
|
+
raise ArgumentError unless data.is_a?(Hash)
|
130
|
+
forecasts = []
|
131
|
+
|
132
|
+
if data && data['item'] && data['item']['yweather:forecast']
|
133
|
+
forecast_result = data['item']['yweather:forecast']
|
134
|
+
|
135
|
+
forecast_result.each do |forecast|
|
136
|
+
forecast_measurement = ForecastMeasurement.new
|
137
|
+
forecast_measurement.icon = forecast['code']
|
138
|
+
forecast_measurement.date = Date.parse(forecast['date'])
|
139
|
+
forecast_measurement.condition = forecast['text']
|
140
|
+
forecast_measurement.high = Temperature.new(metric)
|
141
|
+
forecast_measurement.high << forecast['high'].to_f
|
142
|
+
forecast_measurement.low = Temperature.new(metric)
|
143
|
+
forecast_measurement.low << forecast['low'].to_f
|
144
|
+
forecasts << forecast_measurement
|
145
|
+
end
|
146
|
+
end
|
147
|
+
forecasts
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.build_location(data, geo=nil)
|
151
|
+
raise ArgumentError unless data.is_a?(Hash)
|
152
|
+
raise ArgumentError unless (geo.nil? || geo.is_a?(Barometer::Geo))
|
153
|
+
location = Location.new
|
154
|
+
# use the geocoded data if available, otherwise get data from result
|
155
|
+
if geo
|
156
|
+
location.city = geo.locality
|
157
|
+
location.state_code = geo.region
|
158
|
+
location.country = geo.country
|
159
|
+
location.country_code = geo.country_code
|
160
|
+
location.latitude = geo.latitude
|
161
|
+
location.longitude = geo.longitude
|
162
|
+
else
|
163
|
+
if data && data['yweather:location']
|
164
|
+
location.city = data['yweather:location']['city']
|
165
|
+
location.state_code = data['yweather:location']['region']
|
166
|
+
location.country_code = data['yweather:location']['country']
|
167
|
+
if data['item']
|
168
|
+
location.latitude = data['item']['geo:lat']
|
169
|
+
location.longitude = data['item']['geo:long']
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
location
|
174
|
+
end
|
175
|
+
|
176
|
+
def self.build_sun(data)
|
177
|
+
raise ArgumentError unless data.is_a?(Hash)
|
178
|
+
sun = nil
|
179
|
+
if data && data['yweather:astronomy'] && data['item']
|
180
|
+
# get the TIME ZONE CODE
|
181
|
+
zone_match = data['item']['pubDate'].match(/ ([A-Z]*)$/)
|
182
|
+
zone = zone_match[1] if zone_match
|
183
|
+
# get the sun rise and set
|
184
|
+
rise = Barometer::Zone.merge(
|
185
|
+
data['yweather:astronomy']['sunrise'],
|
186
|
+
data['item']['pubDate'],
|
187
|
+
zone
|
188
|
+
)
|
189
|
+
set = Barometer::Zone.merge(
|
190
|
+
data['yweather:astronomy']['sunset'],
|
191
|
+
data['item']['pubDate'],
|
192
|
+
zone
|
193
|
+
)
|
194
|
+
sun = Sun.new(rise, set)
|
195
|
+
end
|
196
|
+
sun || Sun.new
|
197
|
+
end
|
198
|
+
|
199
|
+
# def self.build_timezone(data)
|
200
|
+
# raise ArgumentError unless data.is_a?(Hash)
|
201
|
+
#
|
202
|
+
# timezone = nil
|
203
|
+
# if data && data['simpleforecast'] &&
|
204
|
+
# data['simpleforecast']['forecastday'] &&
|
205
|
+
# data['simpleforecast']['forecastday'].first &&
|
206
|
+
# data['simpleforecast']['forecastday'].first['date']
|
207
|
+
# timezone = Barometer::Zone.new(Time.now.utc,data['simpleforecast']['forecastday'].first['date']['tz_long'])
|
208
|
+
# end
|
209
|
+
# timezone
|
210
|
+
# end
|
211
|
+
|
212
|
+
# use HTTParty to get the current weather
|
213
|
+
def self.get_all(query, metric=true)
|
214
|
+
Barometer::Yahoo.get(
|
215
|
+
"http://weather.yahooapis.com/forecastrss",
|
216
|
+
:query => {:p => query, :u => (metric ? 'c' : 'f')},
|
217
|
+
:format => :xml,
|
218
|
+
:timeout => Barometer.timeout
|
219
|
+
)['rss']['channel']
|
220
|
+
end
|
221
|
+
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
# Condition Codes
|
226
|
+
# 0 tornado
|
227
|
+
# 1 tropical storm
|
228
|
+
# 2 hurricane
|
229
|
+
# 3 severe thunderstorms
|
230
|
+
# 4 thunderstorms
|
231
|
+
# 5 mixed rain and snow
|
232
|
+
# 6 mixed rain and sleet
|
233
|
+
# 7 mixed snow and sleet
|
234
|
+
# 8 freezing drizzle
|
235
|
+
# 9 drizzle
|
236
|
+
# 10 freezing rain
|
237
|
+
# 11 showers
|
238
|
+
# 12 showers
|
239
|
+
# 13 snow flurries
|
240
|
+
# 14 light snow showers
|
241
|
+
# 15 blowing snow
|
242
|
+
# 16 snow
|
243
|
+
# 17 hail
|
244
|
+
# 18 sleet
|
245
|
+
# 19 dust
|
246
|
+
# 20 foggy
|
247
|
+
# 21 haze
|
248
|
+
# 22 smoky
|
249
|
+
# 23 blustery
|
250
|
+
# 24 windy
|
251
|
+
# 25 cold
|
252
|
+
# 26 cloudy
|
253
|
+
# 27 mostly cloudy (night)
|
254
|
+
# 28 mostly cloudy (day)
|
255
|
+
# 29 partly cloudy (night)
|
256
|
+
# 30 partly cloudy (day)
|
257
|
+
# 31 clear (night)
|
258
|
+
# 32 sunny
|
259
|
+
# 33 fair (night)
|
260
|
+
# 34 fair (day)
|
261
|
+
# 35 mixed rain and hail
|
262
|
+
# 36 hot
|
263
|
+
# 37 isolated thunderstorms
|
264
|
+
# 38 scattered thunderstorms
|
265
|
+
# 39 scattered thunderstorms
|
266
|
+
# 40 scattered showers
|
267
|
+
# 41 heavy snow
|
268
|
+
# 42 scattered snow showers
|
269
|
+
# 43 heavy snow
|
270
|
+
# 44 partly cloudy
|
271
|
+
# 45 thundershowers
|
272
|
+
# 46 snow showers
|
273
|
+
# 47 isolated thundershowers
|
274
|
+
# 3200 not available
|