barometer 0.3.2 → 0.5.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/README.rdoc +78 -70
- data/VERSION.yml +2 -2
- data/bin/barometer +100 -37
- data/lib/barometer.rb +12 -8
- data/lib/barometer/base.rb +48 -20
- data/lib/barometer/data.rb +5 -1
- data/lib/barometer/data/current.rb +23 -15
- data/lib/barometer/data/distance.rb +15 -5
- data/lib/barometer/data/forecast.rb +23 -5
- data/lib/barometer/data/geo.rb +16 -54
- data/lib/barometer/data/local_datetime.rb +137 -0
- data/lib/barometer/data/local_time.rb +134 -0
- data/lib/barometer/data/location.rb +6 -1
- data/lib/barometer/data/measurement.rb +71 -42
- data/lib/barometer/data/night.rb +69 -0
- data/lib/barometer/data/pressure.rb +15 -5
- data/lib/barometer/data/speed.rb +16 -5
- data/lib/barometer/data/sun.rb +8 -20
- data/lib/barometer/data/temperature.rb +22 -9
- data/lib/barometer/data/units.rb +10 -19
- data/lib/barometer/data/zone.rb +135 -9
- data/lib/barometer/formats.rb +12 -0
- data/lib/barometer/formats/coordinates.rb +42 -0
- data/lib/barometer/formats/format.rb +46 -0
- data/lib/barometer/formats/geocode.rb +51 -0
- data/lib/barometer/formats/icao.rb +37 -0
- data/lib/barometer/formats/postalcode.rb +22 -0
- data/lib/barometer/formats/short_zipcode.rb +17 -0
- data/lib/barometer/formats/weather_id.rb +107 -0
- data/lib/barometer/formats/zipcode.rb +31 -0
- data/lib/barometer/query.rb +61 -232
- data/lib/barometer/services.rb +14 -4
- data/lib/barometer/translations/icao_country_codes.yml +9 -0
- data/lib/barometer/translations/weather_country_codes.yml +17 -0
- data/lib/barometer/weather.rb +51 -30
- data/lib/barometer/{services → weather_services}/google.rb +23 -26
- data/lib/barometer/weather_services/noaa.rb +6 -0
- data/lib/barometer/{services → weather_services}/service.rb +101 -92
- data/lib/barometer/weather_services/weather_bug.rb +6 -0
- data/lib/barometer/weather_services/weather_dot_com.rb +261 -0
- data/lib/barometer/{services → weather_services}/wunderground.rb +58 -76
- data/lib/barometer/{services → weather_services}/yahoo.rb +91 -121
- data/lib/barometer/web_services/geocode.rb +33 -0
- data/lib/barometer/web_services/weather_id.rb +37 -0
- data/lib/barometer/web_services/web_service.rb +32 -0
- data/lib/demometer/demometer.rb +31 -4
- data/lib/demometer/views/forecast.erb +20 -0
- data/lib/demometer/views/index.erb +10 -3
- data/lib/demometer/views/measurement.erb +8 -3
- data/lib/demometer/views/readme.erb +63 -24
- data/spec/barometer_spec.rb +18 -36
- data/spec/{data_current_spec.rb → data/current_spec.rb} +73 -49
- data/spec/{data_distance_spec.rb → data/distance_spec.rb} +30 -30
- data/spec/{data_forecast_spec.rb → data/forecast_spec.rb} +57 -15
- data/spec/data/geo_spec.rb +91 -0
- data/spec/data/local_datetime_spec.rb +269 -0
- data/spec/data/local_time_spec.rb +239 -0
- data/spec/{data_location_spec.rb → data/location_spec.rb} +12 -1
- data/spec/{data_measurement_spec.rb → data/measurement_spec.rb} +135 -66
- data/spec/data/night_measurement_spec.rb +136 -0
- data/spec/{data_pressure_spec.rb → data/pressure_spec.rb} +29 -29
- data/spec/{data_speed_spec.rb → data/speed_spec.rb} +30 -30
- data/spec/data/sun_spec.rb +49 -0
- data/spec/{data_temperature_spec.rb → data/temperature_spec.rb} +44 -44
- data/spec/{units_spec.rb → data/units_spec.rb} +6 -6
- data/spec/{data_zone_spec.rb → data/zone_spec.rb} +15 -15
- data/spec/fixtures/formats/weather_id/90210.xml +1 -0
- data/spec/fixtures/formats/weather_id/atlanta.xml +1 -0
- data/spec/fixtures/formats/weather_id/from_USGA0028.xml +1 -0
- data/spec/fixtures/formats/weather_id/new_york.xml +1 -0
- data/spec/fixtures/{geocode_40_73.xml → geocode/40_73.xml} +0 -0
- data/spec/fixtures/{geocode_90210.xml → geocode/90210.xml} +0 -0
- data/spec/fixtures/{geocode_T5B4M9.xml → geocode/T5B4M9.xml} +0 -0
- data/spec/fixtures/geocode/atlanta.xml +1 -0
- data/spec/fixtures/{geocode_calgary_ab.xml → geocode/calgary_ab.xml} +0 -0
- data/spec/fixtures/{geocode_ksfo.xml → geocode/ksfo.xml} +0 -0
- data/spec/fixtures/{geocode_newyork_ny.xml → geocode/newyork_ny.xml} +0 -0
- data/spec/fixtures/{google_calgary_ab.xml → services/google/calgary_ab.xml} +0 -0
- data/spec/fixtures/services/weather_dot_com/90210.xml +1 -0
- data/spec/fixtures/{current_calgary_ab.xml → services/wunderground/current_calgary_ab.xml} +0 -0
- data/spec/fixtures/{forecast_calgary_ab.xml → services/wunderground/forecast_calgary_ab.xml} +0 -0
- data/spec/fixtures/{yahoo_90210.xml → services/yahoo/90210.xml} +0 -0
- data/spec/formats/coordinates_spec.rb +158 -0
- data/spec/formats/format_spec.rb +73 -0
- data/spec/formats/geocode_spec.rb +179 -0
- data/spec/formats/icao_spec.rb +61 -0
- data/spec/formats/postalcode_spec.rb +59 -0
- data/spec/formats/short_zipcode_spec.rb +53 -0
- data/spec/formats/weather_id_spec.rb +191 -0
- data/spec/formats/zipcode_spec.rb +111 -0
- data/spec/query_spec.rb +261 -288
- data/spec/spec_helper.rb +128 -4
- data/spec/{service_google_spec.rb → weather_services/google_spec.rb} +46 -46
- data/spec/weather_services/services_spec.rb +1118 -0
- data/spec/weather_services/weather_dot_com_spec.rb +327 -0
- data/spec/weather_services/wunderground_spec.rb +332 -0
- data/spec/{service_yahoo_spec.rb → weather_services/yahoo_spec.rb} +65 -81
- data/spec/weather_spec.rb +73 -61
- data/spec/web_services/geocode_spec.rb +45 -0
- data/spec/web_services/web_services_spec.rb +26 -0
- metadata +88 -36
- data/lib/barometer/services/noaa.rb +0 -6
- data/lib/barometer/services/weather_bug.rb +0 -6
- data/lib/barometer/services/weather_dot_com.rb +0 -6
- data/spec/data_geo_spec.rb +0 -94
- data/spec/data_sun_spec.rb +0 -76
- data/spec/service_wunderground_spec.rb +0 -330
- data/spec/services_spec.rb +0 -1106
@@ -0,0 +1,261 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# = Weather.com
|
4
|
+
# www.weather.com
|
5
|
+
#
|
6
|
+
# - key required: YES (partnerid & licensekey)
|
7
|
+
# - registration required: YES
|
8
|
+
# - supported countries: US (by zipcode), International (by Weather Location ID)
|
9
|
+
#
|
10
|
+
# === performs geo coding
|
11
|
+
# - city: PARTIAL (just a name)
|
12
|
+
# - coordinates: YES
|
13
|
+
#
|
14
|
+
# === time info
|
15
|
+
# - sun rise/set: YES
|
16
|
+
# - provides timezone: NO, but provides a utc offset
|
17
|
+
# - requires TZInfo: NO
|
18
|
+
#
|
19
|
+
# == resources
|
20
|
+
# - API: ?
|
21
|
+
#
|
22
|
+
# === Possible queries:
|
23
|
+
# - http://xoap.weather.com/weather/local/30339?cc=*&dayf=5&link=xoap&prod=xoap&par=[PartnerID]&key=[LicenseKey]
|
24
|
+
#
|
25
|
+
# where query can be:
|
26
|
+
# - zipcode (US) [5 digits only]
|
27
|
+
# - Weather Location ID (International)
|
28
|
+
#
|
29
|
+
# = Weather.com terms of use
|
30
|
+
# ???
|
31
|
+
#
|
32
|
+
# == notes
|
33
|
+
# - the Weather Location ID is a propreitary number (possibly shared with yahoo.com)
|
34
|
+
#
|
35
|
+
# == TODO
|
36
|
+
# - improve "forecasted_wet_by_icon?" to determine if day or night and use right code
|
37
|
+
# - improve "forecasted_sunny_by_icon?" to determine if day or night and use right code
|
38
|
+
# - improve "forcasted_wet_by_humidity?" to use forecasted values
|
39
|
+
# - improve "forcasted_windy?" to use forecasted values
|
40
|
+
#
|
41
|
+
class WeatherService::WeatherDotCom < WeatherService
|
42
|
+
|
43
|
+
@@partner_key = nil
|
44
|
+
@@license_key = nil
|
45
|
+
|
46
|
+
def self.source_name; :weather_dot_com; end
|
47
|
+
def self.accepted_formats; [:short_zipcode, :weather_id]; end
|
48
|
+
|
49
|
+
def self.keys=(keys)
|
50
|
+
raise ArgumentError unless keys.is_a?(Hash)
|
51
|
+
keys.each do |key, value|
|
52
|
+
@@partner_key = value.to_s if key.to_s.downcase == "partner"
|
53
|
+
@@license_key = value.to_s if key.to_s.downcase == "license"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.has_keys?; !@@partner_key.nil? && !@@license_key.nil?; end
|
58
|
+
def self.requires_keys?; true; end
|
59
|
+
|
60
|
+
def self.wet_icon_codes
|
61
|
+
codes = (0..18).to_a + [35] + (37..43).to_a + (45..47).to_a
|
62
|
+
codes.collect {|c| c.to_s}
|
63
|
+
end
|
64
|
+
def self.sunny_icon_codes
|
65
|
+
codes = [19, 22, 28, 30, 32, 34, 36]
|
66
|
+
codes.collect {|c| c.to_s}
|
67
|
+
end
|
68
|
+
|
69
|
+
def self._measure(measurement, query, metric=true)
|
70
|
+
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
71
|
+
raise ArgumentError unless query.is_a?(Barometer::Query)
|
72
|
+
measurement.source = self.source_name
|
73
|
+
|
74
|
+
begin
|
75
|
+
result = self.fetch(query.q, metric)
|
76
|
+
rescue Timeout::Error => e
|
77
|
+
return measurement
|
78
|
+
end
|
79
|
+
|
80
|
+
measurement.current = self.build_current(result, metric)
|
81
|
+
measurement.forecast = self.build_forecast(result, metric)
|
82
|
+
measurement.location = self.build_location(result, query.geo)
|
83
|
+
measurement.current.sun = self.build_sun(result)
|
84
|
+
|
85
|
+
# add links
|
86
|
+
if result && result['lnks'] && result['lnks']['link']
|
87
|
+
result['lnks']['link'].each do |link_hash|
|
88
|
+
measurement.links[link_hash['t']] = link_hash['l']
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# set local time of measurement
|
93
|
+
local_time = self.build_local_time(result)
|
94
|
+
measurement.measured_at = local_time
|
95
|
+
measurement.current.current_at = local_time
|
96
|
+
|
97
|
+
measurement
|
98
|
+
end
|
99
|
+
|
100
|
+
# WARNING
|
101
|
+
# this is a best guess method. the data provided for time conversions
|
102
|
+
# leaves a lot to be desired. some time zones, offsets, local times are
|
103
|
+
# out to lunch. eg. Tahiti (all times seem to be 30 min off), but there
|
104
|
+
# is no way to determine this
|
105
|
+
#
|
106
|
+
# regardless of the above, this method will trust the data given to it
|
107
|
+
#
|
108
|
+
def self.build_local_time(data)
|
109
|
+
(data && data['loc']) ? Data::LocalTime.parse(data['loc']['tm']) : nil
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.build_current(data, metric=true)
|
113
|
+
raise ArgumentError unless data.is_a?(Hash)
|
114
|
+
current = Data::CurrentMeasurement.new
|
115
|
+
if data
|
116
|
+
if data['cc']
|
117
|
+
current.updated_at = Data::LocalDateTime.parse(data['cc']['lsup'])
|
118
|
+
current.icon = data['cc']['icon']
|
119
|
+
current.condition = data['cc']['t']
|
120
|
+
current.humidity = data['cc']['hmid'].to_i
|
121
|
+
current.temperature = Data::Temperature.new(metric)
|
122
|
+
current.temperature << data['cc']['tmp']
|
123
|
+
current.dew_point = Data::Temperature.new(metric)
|
124
|
+
current.dew_point << data['cc']['dewp']
|
125
|
+
current.wind_chill = Data::Temperature.new(metric)
|
126
|
+
current.wind_chill << data['cc']['flik']
|
127
|
+
current.visibility = Data::Distance.new(metric)
|
128
|
+
current.visibility << data['cc']['vis']
|
129
|
+
if data['cc']['wind']
|
130
|
+
current.wind = Data::Speed.new(metric)
|
131
|
+
current.wind << data['cc']['wind']['s']
|
132
|
+
current.wind.degrees = data['cc']['wind']['d'].to_f
|
133
|
+
current.wind.direction = data['cc']['wind']['t']
|
134
|
+
end
|
135
|
+
if data['cc']['bar']
|
136
|
+
current.pressure = Data::Pressure.new(metric)
|
137
|
+
current.pressure << data['cc']['bar']['r']
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
current
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.build_forecast(data, metric=true)
|
145
|
+
raise ArgumentError unless data.is_a?(Hash)
|
146
|
+
forecasts = []
|
147
|
+
|
148
|
+
if data && data['dayf'] && data['dayf']['day']
|
149
|
+
local_date = data['dayf']['lsup']
|
150
|
+
data['dayf']['day'].each do |forecast|
|
151
|
+
forecast_measurement = Data::ForecastMeasurement.new
|
152
|
+
forecast_measurement.date = Date.parse(forecast['dt'])
|
153
|
+
|
154
|
+
forecast_measurement.high = Data::Temperature.new(metric)
|
155
|
+
forecast_measurement.high << forecast['hi']
|
156
|
+
forecast_measurement.low = Data::Temperature.new(metric)
|
157
|
+
forecast_measurement.low << forecast['low']
|
158
|
+
|
159
|
+
# build sun
|
160
|
+
rise_local_time = Data::LocalTime.parse(forecast['sunr'])
|
161
|
+
set_local_time = Data::LocalTime.parse(forecast['suns'])
|
162
|
+
sun = Data::Sun.new(rise_local_time, set_local_time)
|
163
|
+
forecast_measurement.sun = sun
|
164
|
+
|
165
|
+
if forecast['part']
|
166
|
+
forecast['part'].each do |part|
|
167
|
+
if part['p'] == 'd'
|
168
|
+
# add this to the ForecastMeasurement
|
169
|
+
forecast_measurement.condition = part['t']
|
170
|
+
forecast_measurement.icon = part['icon']
|
171
|
+
forecast_measurement.pop = part['ppcp'].to_i
|
172
|
+
forecast_measurement.humidity = part['hmid'].to_i
|
173
|
+
|
174
|
+
if part['wind']
|
175
|
+
forecast_measurement.wind = Data::Speed.new(metric)
|
176
|
+
forecast_measurement.wind << part['wind']['s']
|
177
|
+
forecast_measurement.wind.degrees = part['wind']['d'].to_i
|
178
|
+
forecast_measurement.wind.direction = part['wind']['t']
|
179
|
+
end
|
180
|
+
|
181
|
+
elsif part['p'] == 'n'
|
182
|
+
# add this to the NightMeasurement
|
183
|
+
forecast_measurement.night = Data::NightMeasurement.new
|
184
|
+
forecast_measurement.night.condition = part['t']
|
185
|
+
forecast_measurement.night.icon = part['icon']
|
186
|
+
forecast_measurement.night.pop = part['ppcp'].to_i
|
187
|
+
forecast_measurement.night.humidity = part['hmid'].to_i
|
188
|
+
|
189
|
+
if part['wind']
|
190
|
+
forecast_measurement.night.wind = Data::Speed.new(metric)
|
191
|
+
forecast_measurement.night.wind << part['wind']['s']
|
192
|
+
forecast_measurement.night.wind.degrees = part['wind']['d'].to_i
|
193
|
+
forecast_measurement.night.wind.direction = part['wind']['t']
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
forecasts << forecast_measurement
|
200
|
+
end
|
201
|
+
end
|
202
|
+
forecasts
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.build_location(data, geo=nil)
|
206
|
+
raise ArgumentError unless data.is_a?(Hash)
|
207
|
+
raise ArgumentError unless (geo.nil? || geo.is_a?(Data::Geo))
|
208
|
+
location = Data::Location.new
|
209
|
+
# use the geocoded data if available, otherwise get data from result
|
210
|
+
if geo
|
211
|
+
location.city = geo.locality
|
212
|
+
location.state_code = geo.region
|
213
|
+
location.country = geo.country
|
214
|
+
location.country_code = geo.country_code
|
215
|
+
location.latitude = geo.latitude
|
216
|
+
location.longitude = geo.longitude
|
217
|
+
else
|
218
|
+
if data && data['loc']
|
219
|
+
location.name = data['loc']['dnam']
|
220
|
+
location.latitude = data['loc']['lat']
|
221
|
+
location.longitude = data['loc']['lon']
|
222
|
+
end
|
223
|
+
end
|
224
|
+
location
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.build_sun(data)
|
228
|
+
raise ArgumentError unless data.is_a?(Hash)
|
229
|
+
sun = nil
|
230
|
+
if data
|
231
|
+
if data['loc']
|
232
|
+
rise_local_time = Data::LocalTime.parse(data['loc']['sunr'])
|
233
|
+
set_local_time = Data::LocalTime.parse(data['loc']['suns'])
|
234
|
+
end
|
235
|
+
sun = Data::Sun.new(rise_local_time, set_local_time)
|
236
|
+
end
|
237
|
+
sun || Data::Sun.new
|
238
|
+
end
|
239
|
+
|
240
|
+
# use HTTParty to get the current weather
|
241
|
+
#
|
242
|
+
def self.fetch(query, metric=true)
|
243
|
+
self.get(
|
244
|
+
"http://xoap.weather.com/weather/local/#{query}",
|
245
|
+
:query => { :par => @@partner_key, :key => @@license_key,
|
246
|
+
:prod => "xoap", :link => "xoap", :cc => "*",
|
247
|
+
:dayf => "5", :unit => (metric ? 'm' : 's')
|
248
|
+
},
|
249
|
+
:format => :xml,
|
250
|
+
:timeout => Barometer.timeout
|
251
|
+
)['weather']
|
252
|
+
end
|
253
|
+
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# FUTURE DATA TO SUPPORT?
|
258
|
+
# "cc"=>
|
259
|
+
# {"obst"=>"Santa Monica, CA",
|
260
|
+
# "uv"=>{"i"=>"0", "t"=>"Low"},
|
261
|
+
# "moon"=>{"icon"=>"9", "t"=>"Waxing Gibbous"}
|
@@ -1,4 +1,6 @@
|
|
1
1
|
module Barometer
|
2
|
+
#
|
3
|
+
# [DEFAULT PROVIDER]
|
2
4
|
#
|
3
5
|
# = Weather Underground
|
4
6
|
# www.wunderground.com
|
@@ -16,6 +18,9 @@ module Barometer
|
|
16
18
|
# - sun rise/set: YES (today only)
|
17
19
|
# - provides timezone: YES
|
18
20
|
# - requires TZInfo: YES
|
21
|
+
# *NOTE: If accuarcy of times and converting, this service is the top choice.
|
22
|
+
# They provide the full timezone name that is needed for the most
|
23
|
+
# accurate time conversions.
|
19
24
|
#
|
20
25
|
# == resources
|
21
26
|
# - API: http://wiki.wunderground.com/index.php/API_-_XML
|
@@ -36,19 +41,19 @@ module Barometer
|
|
36
41
|
# - airport code (3-letter or 4-letter)
|
37
42
|
# - lat,lon
|
38
43
|
#
|
39
|
-
|
44
|
+
# = Wunderground terms of use
|
45
|
+
# Unable to locate.
|
46
|
+
#
|
47
|
+
class WeatherService::Wunderground < WeatherService
|
40
48
|
|
49
|
+
def self.source_name; :wunderground; end
|
41
50
|
def self.accepted_formats
|
42
51
|
[:zipcode, :postalcode, :icao, :coordinates, :geocode]
|
43
52
|
end
|
44
53
|
|
45
|
-
def self.source_name
|
46
|
-
:wunderground
|
47
|
-
end
|
48
|
-
|
49
54
|
# these are the icon codes that indicate "wet", used by wet? function
|
50
55
|
def self.wet_icon_codes
|
51
|
-
%w(flurries rain sleet snow tstorms nt_flurries nt_rain nt_sleet nt_snow nt_tstorms chancerain)
|
56
|
+
%w(flurries rain sleet snow tstorms nt_flurries nt_rain nt_sleet nt_snow nt_tstorms chancerain chancetstorms)
|
52
57
|
end
|
53
58
|
# these are the icon codes that indicate "sun", used by sunny? function
|
54
59
|
def self.sunny_icon_codes
|
@@ -56,21 +61,19 @@ module Barometer
|
|
56
61
|
end
|
57
62
|
|
58
63
|
def self._measure(measurement, query, metric=true)
|
59
|
-
raise ArgumentError unless measurement.is_a?(
|
64
|
+
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
60
65
|
raise ArgumentError unless query.is_a?(Barometer::Query)
|
61
66
|
measurement.source = self.source_name
|
62
67
|
|
63
|
-
# get current measurement
|
64
68
|
begin
|
65
|
-
current_result = self.get_current(query.
|
69
|
+
current_result = self.get_current(query.q)
|
66
70
|
measurement.current = self.build_current(current_result, metric)
|
67
71
|
rescue Timeout::Error => e
|
68
72
|
return measurement
|
69
73
|
end
|
70
74
|
|
71
|
-
# get forecast measurement
|
72
75
|
begin
|
73
|
-
forecast_result = self.get_forecast(query.
|
76
|
+
forecast_result = self.get_forecast(query.q)
|
74
77
|
measurement.forecast = self.build_forecast(forecast_result, metric)
|
75
78
|
rescue Timeout::Error => e
|
76
79
|
return measurement
|
@@ -80,7 +83,10 @@ module Barometer
|
|
80
83
|
measurement.station = self.build_station(current_result)
|
81
84
|
measurement.timezone = self.build_timezone(forecast_result)
|
82
85
|
|
83
|
-
|
86
|
+
if current_result["credit"] && current_result["credit_URL"]
|
87
|
+
measurement.links[current_result["credit"]] = current_result["credit_URL"]
|
88
|
+
end
|
89
|
+
|
84
90
|
sun = nil
|
85
91
|
if measurement.current
|
86
92
|
sun = self.build_sun(forecast_result, measurement.timezone)
|
@@ -88,48 +94,49 @@ module Barometer
|
|
88
94
|
end
|
89
95
|
# use todays sun data for all future days
|
90
96
|
if measurement.forecast && sun
|
91
|
-
start_date = Date.parse(measurement.current.time)
|
92
97
|
measurement.forecast.each do |forecast|
|
93
|
-
|
94
|
-
forecast.sun = Barometer::Sun.add_days!(sun,days_in_future.to_i)
|
98
|
+
forecast.sun = sun
|
95
99
|
end
|
96
100
|
end
|
97
101
|
|
102
|
+
local_time = measurement.timezone ? Data::LocalTime.parse(
|
103
|
+
measurement.timezone.utc_to_local(Time.now.utc)
|
104
|
+
) : nil
|
105
|
+
measurement.measured_at = local_time
|
106
|
+
measurement.current.current_at = local_time
|
107
|
+
|
98
108
|
measurement
|
99
109
|
end
|
100
|
-
|
110
|
+
|
101
111
|
def self.build_current(data, metric=true)
|
102
112
|
raise ArgumentError unless data.is_a?(Hash)
|
103
113
|
|
104
|
-
current = CurrentMeasurement.new
|
105
|
-
|
106
|
-
# current_result['observation_time_rfc822'].blank?
|
107
|
-
current.time = data['observation_time_rfc822']
|
108
|
-
current.local_time = data['observation_time']
|
114
|
+
current = Data::CurrentMeasurement.new
|
115
|
+
current.updated_at = Data::LocalDateTime.parse(data['observation_time']) if data['observation_time']
|
109
116
|
current.humidity = data['relative_humidity'].to_i
|
110
117
|
current.icon = data['icon'] if data['icon']
|
111
118
|
|
112
|
-
current.temperature = Temperature.new(metric)
|
119
|
+
current.temperature = Data::Temperature.new(metric)
|
113
120
|
current.temperature << [data['temp_c'], data['temp_f']]
|
114
121
|
|
115
|
-
current.wind = Speed.new(metric)
|
122
|
+
current.wind = Data::Speed.new(metric)
|
116
123
|
current.wind.mph = data['wind_mph'].to_f
|
117
124
|
current.wind.degrees = data['wind_degrees'].to_i
|
118
125
|
current.wind.direction = data['wind_dir']
|
119
126
|
|
120
|
-
current.pressure = Pressure.new(metric)
|
127
|
+
current.pressure = Data::Pressure.new(metric)
|
121
128
|
current.pressure << [data['pressure_mb'], data['pressure_in']]
|
122
129
|
|
123
|
-
current.dew_point = Temperature.new(metric)
|
130
|
+
current.dew_point = Data::Temperature.new(metric)
|
124
131
|
current.dew_point << [data['dewpoint_c'], data['dewpoint_f']]
|
125
132
|
|
126
|
-
current.heat_index = Temperature.new(metric)
|
133
|
+
current.heat_index = Data::Temperature.new(metric)
|
127
134
|
current.heat_index << [data['heat_index_c'], data['heat_index_f']]
|
128
135
|
|
129
|
-
current.wind_chill = Temperature.new(metric)
|
136
|
+
current.wind_chill = Data::Temperature.new(metric)
|
130
137
|
current.wind_chill << [data['windchill_c'], data['windchill_f']]
|
131
138
|
|
132
|
-
current.visibility = Distance.new(metric)
|
139
|
+
current.visibility = Data::Distance.new(metric)
|
133
140
|
current.visibility << [data['visibility_km'], data['visibility_mi']]
|
134
141
|
|
135
142
|
current
|
@@ -143,15 +150,15 @@ module Barometer
|
|
143
150
|
data['simpleforecast']['forecastday']
|
144
151
|
|
145
152
|
data['simpleforecast']['forecastday'].each do |forecast|
|
146
|
-
forecast_measurement = ForecastMeasurement.new
|
153
|
+
forecast_measurement = Data::ForecastMeasurement.new
|
147
154
|
forecast_measurement.icon = forecast['icon']
|
148
155
|
forecast_measurement.date = Date.parse(forecast['date']['pretty'])
|
149
156
|
forecast_measurement.pop = forecast['pop'].to_i
|
150
157
|
|
151
|
-
forecast_measurement.high = Temperature.new(metric)
|
158
|
+
forecast_measurement.high = Data::Temperature.new(metric)
|
152
159
|
forecast_measurement.high << [forecast['high']['celsius'],forecast['high']['fahrenheit']]
|
153
160
|
|
154
|
-
forecast_measurement.low = Temperature.new(metric)
|
161
|
+
forecast_measurement.low = Data::Temperature.new(metric)
|
155
162
|
forecast_measurement.low << [forecast['low']['celsius'],forecast['low']['fahrenheit']]
|
156
163
|
|
157
164
|
forecasts << forecast_measurement
|
@@ -162,7 +169,7 @@ module Barometer
|
|
162
169
|
|
163
170
|
def self.build_location(data)
|
164
171
|
raise ArgumentError unless data.is_a?(Hash)
|
165
|
-
location = Location.new
|
172
|
+
location = Data::Location.new
|
166
173
|
if data['display_location']
|
167
174
|
location.name = data['display_location']['full']
|
168
175
|
location.city = data['display_location']['city']
|
@@ -178,7 +185,7 @@ module Barometer
|
|
178
185
|
|
179
186
|
def self.build_station(data)
|
180
187
|
raise ArgumentError unless data.is_a?(Hash)
|
181
|
-
station = Location.new
|
188
|
+
station = Data::Location.new
|
182
189
|
station.id = data['station_id']
|
183
190
|
if data['observation_location']
|
184
191
|
station.name = data['observation_location']['full']
|
@@ -193,15 +200,6 @@ module Barometer
|
|
193
200
|
station
|
194
201
|
end
|
195
202
|
|
196
|
-
# <forecastday>
|
197
|
-
# <date>
|
198
|
-
# <pretty_short>9:00 PM CST</pretty_short>
|
199
|
-
# <pretty>9:00 PM CST on January 15, 2008</pretty>
|
200
|
-
# <isdst>0</isdst>
|
201
|
-
# <tz_short>CST</tz_short>
|
202
|
-
# <tz_long>America/Chicago</tz_long>
|
203
|
-
# </date>
|
204
|
-
# </forecastday>
|
205
203
|
def self.build_timezone(data)
|
206
204
|
raise ArgumentError unless data.is_a?(Hash)
|
207
205
|
timezone = nil
|
@@ -209,62 +207,45 @@ module Barometer
|
|
209
207
|
data['simpleforecast']['forecastday'] &&
|
210
208
|
data['simpleforecast']['forecastday'].first &&
|
211
209
|
data['simpleforecast']['forecastday'].first['date']
|
212
|
-
timezone =
|
210
|
+
timezone = Data::Zone.new(
|
213
211
|
data['simpleforecast']['forecastday'].first['date']['tz_long']
|
214
212
|
)
|
215
213
|
end
|
216
|
-
timezone
|
214
|
+
timezone || Data::Zone.new(nil)
|
217
215
|
end
|
218
216
|
|
219
217
|
def self.build_sun(data, timezone)
|
220
218
|
raise ArgumentError unless data.is_a?(Hash)
|
221
|
-
raise ArgumentError unless timezone.is_a?(
|
222
|
-
|
219
|
+
raise ArgumentError unless timezone.is_a?(Data::Zone)
|
223
220
|
sun = nil
|
224
221
|
if data
|
225
|
-
|
226
|
-
if data['simpleforecast'] &&
|
227
|
-
data['simpleforecast']['forecastday'] &&
|
228
|
-
data['simpleforecast']['forecastday'].first &&
|
229
|
-
data['simpleforecast']['forecastday'].first['date']
|
230
|
-
|
231
|
-
# construct current date
|
232
|
-
date_data = data['simpleforecast']['forecastday'].first['date']
|
233
|
-
time = Time.local(
|
234
|
-
date_data['year'], date_data['month'], date_data['day'],
|
235
|
-
date_data['hour'], date_data['min'], date_data['sec']
|
236
|
-
)
|
237
|
-
end
|
238
|
-
if time && data['moon_phase']
|
239
|
-
# get the sun rise and set times (ie "6:32 am")
|
222
|
+
if data['moon_phase']
|
240
223
|
if data['moon_phase']['sunrise']
|
241
|
-
rise =
|
242
|
-
|
243
|
-
data['moon_phase']['sunrise']['
|
244
|
-
data['moon_phase']['sunrise']['minute']
|
224
|
+
rise = Data::LocalTime.new(
|
225
|
+
data['moon_phase']['sunrise']['hour'].to_i,
|
226
|
+
data['moon_phase']['sunrise']['minute'].to_i
|
245
227
|
)
|
246
228
|
end
|
247
229
|
if data['moon_phase']['sunset']
|
248
|
-
set =
|
249
|
-
|
250
|
-
data['moon_phase']['sunset']['
|
251
|
-
data['moon_phase']['sunset']['minute']
|
230
|
+
set = Data::LocalTime.new(
|
231
|
+
data['moon_phase']['sunset']['hour'].to_i,
|
232
|
+
data['moon_phase']['sunset']['minute'].to_i
|
252
233
|
)
|
253
234
|
end
|
254
235
|
|
255
|
-
sun = Sun.new(
|
256
|
-
|
257
|
-
|
236
|
+
sun = Data::Sun.new(
|
237
|
+
rise,
|
238
|
+
set
|
258
239
|
)
|
259
240
|
end
|
260
241
|
end
|
261
|
-
|
262
|
-
sun || Sun.new
|
242
|
+
sun || Data::Sun.new
|
263
243
|
end
|
264
244
|
|
265
245
|
# use HTTParty to get the current weather
|
266
246
|
def self.get_current(query)
|
267
|
-
|
247
|
+
return unless query
|
248
|
+
self.get(
|
268
249
|
"http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml",
|
269
250
|
:query => {:query => query},
|
270
251
|
:format => :xml,
|
@@ -274,7 +255,8 @@ module Barometer
|
|
274
255
|
|
275
256
|
# use HTTParty to get the forecasted weather
|
276
257
|
def self.get_forecast(query)
|
277
|
-
|
258
|
+
return unless query
|
259
|
+
self.get(
|
278
260
|
"http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml",
|
279
261
|
:query => {:query => query},
|
280
262
|
:format => :xml,
|