attack-barometer 0.5.0 → 0.6.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 +51 -9
- data/VERSION.yml +1 -1
- data/bin/barometer +57 -7
- data/lib/barometer/base.rb +3 -0
- data/lib/barometer/data/sun.rb +10 -0
- data/lib/barometer/data/zone.rb +79 -188
- data/lib/barometer/data.rb +11 -6
- data/lib/barometer/formats/coordinates.rb +4 -1
- data/lib/barometer/formats/geocode.rb +9 -7
- data/lib/barometer/formats/icao.rb +2 -2
- data/lib/barometer/formats/weather_id.rb +2 -2
- data/lib/barometer/measurements/common.rb +113 -0
- data/lib/barometer/{data → measurements}/current.rb +17 -42
- data/lib/barometer/measurements/forecast.rb +62 -0
- data/lib/barometer/measurements/forecast_array.rb +72 -0
- data/lib/barometer/{data → measurements}/measurement.rb +57 -45
- data/lib/barometer/measurements/night.rb +27 -0
- data/lib/barometer/query.rb +55 -5
- data/lib/barometer/services.rb +3 -1
- data/lib/barometer/translations/zone_codes.yml +360 -0
- data/lib/barometer/weather.rb +5 -4
- data/lib/barometer/weather_services/google.rb +19 -35
- data/lib/barometer/weather_services/service.rb +113 -255
- data/lib/barometer/weather_services/weather_bug.rb +291 -2
- data/lib/barometer/weather_services/weather_dot_com.rb +45 -54
- data/lib/barometer/weather_services/wunderground.rb +83 -89
- data/lib/barometer/weather_services/yahoo.rb +44 -91
- data/lib/barometer/web_services/geocode.rb +1 -0
- data/lib/barometer/web_services/timezone.rb +40 -0
- data/lib/barometer/web_services/weather_id.rb +17 -2
- data/lib/barometer.rb +11 -0
- data/lib/demometer/demometer.rb +28 -0
- data/lib/demometer/public/css/master.css +259 -1
- data/lib/demometer/views/index.erb +2 -0
- data/lib/demometer/views/layout.erb +3 -2
- data/lib/demometer/views/measurement.erb +4 -1
- data/lib/demometer/views/readme.erb +116 -88
- data/spec/data/sun_spec.rb +53 -0
- data/spec/data/zone_spec.rb +330 -100
- data/spec/fixtures/formats/weather_id/ksfo.xml +1 -0
- data/spec/fixtures/services/weather_bug/90210_current.xml +1 -0
- data/spec/fixtures/services/weather_bug/90210_forecast.xml +1 -0
- data/spec/formats/weather_id_spec.rb +10 -5
- data/spec/measurements/common_spec.rb +352 -0
- data/spec/{data → measurements}/current_spec.rb +40 -103
- data/spec/measurements/forecast_array_spec.rb +165 -0
- data/spec/measurements/forecast_spec.rb +135 -0
- data/spec/{data → measurements}/measurement_spec.rb +86 -107
- data/spec/measurements/night_measurement_spec.rb +49 -0
- data/spec/query_spec.rb +12 -2
- data/spec/spec_helper.rb +28 -1
- data/spec/weather_services/google_spec.rb +27 -117
- data/spec/weather_services/services_spec.rb +49 -1024
- data/spec/weather_services/weather_bug_spec.rb +274 -0
- data/spec/weather_services/weather_dot_com_spec.rb +45 -125
- data/spec/weather_services/wunderground_spec.rb +42 -136
- data/spec/weather_services/yahoo_spec.rb +26 -116
- data/spec/weather_spec.rb +45 -45
- metadata +23 -11
- data/lib/barometer/data/forecast.rb +0 -84
- data/lib/barometer/data/night.rb +0 -69
- data/lib/barometer/extensions/graticule.rb +0 -51
- data/spec/data/forecast_spec.rb +0 -192
- data/spec/data/night_measurement_spec.rb +0 -136
@@ -46,72 +46,63 @@ module Barometer
|
|
46
46
|
#
|
47
47
|
class WeatherService::Wunderground < WeatherService
|
48
48
|
|
49
|
-
|
50
|
-
|
49
|
+
#########################################################################
|
50
|
+
# PRIVATE
|
51
|
+
# If class methods could be private, the remaining methods would be.
|
52
|
+
#
|
53
|
+
|
54
|
+
def self._source_name; :wunderground; end
|
55
|
+
def self._accepted_formats
|
51
56
|
[:zipcode, :postalcode, :icao, :coordinates, :geocode]
|
52
57
|
end
|
53
58
|
|
54
59
|
# these are the icon codes that indicate "wet", used by wet? function
|
55
|
-
def self.
|
60
|
+
def self._wet_icon_codes
|
56
61
|
%w(flurries rain sleet snow tstorms nt_flurries nt_rain nt_sleet nt_snow nt_tstorms chancerain chancetstorms)
|
57
62
|
end
|
58
63
|
# these are the icon codes that indicate "sun", used by sunny? function
|
59
|
-
def self.
|
64
|
+
def self._sunny_icon_codes
|
60
65
|
%w(clear mostlysunny partlysunny sunny partlycloudy)
|
61
66
|
end
|
62
67
|
|
63
|
-
def self.
|
64
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
65
|
-
raise ArgumentError unless query.is_a?(Barometer::Query)
|
66
|
-
|
67
|
-
|
68
|
-
begin
|
69
|
-
current_result = self.get_current(query.q)
|
70
|
-
measurement.current = self.build_current(current_result, metric)
|
71
|
-
rescue Timeout::Error => e
|
72
|
-
return measurement
|
73
|
-
end
|
74
|
-
|
75
|
-
begin
|
76
|
-
forecast_result = self.get_forecast(query.q)
|
77
|
-
measurement.forecast = self.build_forecast(forecast_result, metric)
|
78
|
-
rescue Timeout::Error => e
|
79
|
-
return measurement
|
80
|
-
end
|
81
|
-
|
82
|
-
measurement.location = self.build_location(current_result)
|
83
|
-
measurement.station = self.build_station(current_result)
|
84
|
-
measurement.timezone = self.build_timezone(forecast_result)
|
85
|
-
|
86
|
-
if current_result["credit"] && current_result["credit_URL"]
|
87
|
-
measurement.links[current_result["credit"]] = current_result["credit_URL"]
|
88
|
-
end
|
89
|
-
|
90
|
-
sun = nil
|
91
|
-
if measurement.current
|
92
|
-
sun = self.build_sun(forecast_result, measurement.timezone)
|
93
|
-
measurement.current.sun = sun
|
94
|
-
end
|
68
|
+
def self._build_extra(measurement, result, metric=true)
|
69
|
+
#raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
70
|
+
#raise ArgumentError unless query.is_a?(Barometer::Query)
|
71
|
+
|
95
72
|
# use todays sun data for all future days
|
96
|
-
if measurement.forecast && sun
|
73
|
+
if measurement.forecast && measurement.current.sun
|
97
74
|
measurement.forecast.each do |forecast|
|
98
|
-
forecast.sun = sun
|
75
|
+
forecast.sun = measurement.current.sun
|
99
76
|
end
|
100
77
|
end
|
101
78
|
|
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
|
-
|
108
79
|
measurement
|
109
80
|
end
|
81
|
+
|
82
|
+
def self._parse_full_timezone(data)
|
83
|
+
raise ArgumentError unless data.is_a?(Hash)
|
84
|
+
if data && data['simpleforecast'] &&
|
85
|
+
data['simpleforecast']['forecastday'] &&
|
86
|
+
data['simpleforecast']['forecastday'].first &&
|
87
|
+
data['simpleforecast']['forecastday'].first['date']
|
88
|
+
Data::Zone.new(
|
89
|
+
data['simpleforecast']['forecastday'].first['date']['tz_long']
|
90
|
+
)
|
91
|
+
end
|
92
|
+
end
|
110
93
|
|
111
|
-
def self.
|
94
|
+
def self._build_links(data)
|
95
|
+
links = {}
|
96
|
+
if data["credit"] && data["credit_URL"]
|
97
|
+
links[data["credit"]] = data["credit_URL"]
|
98
|
+
end
|
99
|
+
links
|
100
|
+
end
|
101
|
+
|
102
|
+
def self._build_current(data, metric=true)
|
112
103
|
raise ArgumentError unless data.is_a?(Hash)
|
113
104
|
|
114
|
-
current =
|
105
|
+
current = Measurement::Current.new
|
115
106
|
current.updated_at = Data::LocalDateTime.parse(data['observation_time']) if data['observation_time']
|
116
107
|
current.humidity = data['relative_humidity'].to_i
|
117
108
|
current.icon = data['icon'] if data['icon']
|
@@ -142,15 +133,15 @@ module Barometer
|
|
142
133
|
current
|
143
134
|
end
|
144
135
|
|
145
|
-
def self.
|
136
|
+
def self._build_forecast(data, metric=true)
|
146
137
|
raise ArgumentError unless data.is_a?(Hash)
|
147
|
-
forecasts =
|
138
|
+
forecasts = Measurement::ForecastArray.new
|
148
139
|
# go through each forecast and create an instance
|
149
140
|
if data && data['simpleforecast'] &&
|
150
141
|
data['simpleforecast']['forecastday']
|
151
142
|
|
152
143
|
data['simpleforecast']['forecastday'].each do |forecast|
|
153
|
-
forecast_measurement =
|
144
|
+
forecast_measurement = Measurement::Forecast.new
|
154
145
|
forecast_measurement.icon = forecast['icon']
|
155
146
|
forecast_measurement.date = Date.parse(forecast['date']['pretty'])
|
156
147
|
forecast_measurement.pop = forecast['pop'].to_i
|
@@ -166,8 +157,8 @@ module Barometer
|
|
166
157
|
end
|
167
158
|
forecasts
|
168
159
|
end
|
169
|
-
|
170
|
-
def self.
|
160
|
+
|
161
|
+
def self._build_location(data, geo=nil)
|
171
162
|
raise ArgumentError unless data.is_a?(Hash)
|
172
163
|
location = Data::Location.new
|
173
164
|
if data['display_location']
|
@@ -183,7 +174,7 @@ module Barometer
|
|
183
174
|
location
|
184
175
|
end
|
185
176
|
|
186
|
-
def self.
|
177
|
+
def self._build_station(data)
|
187
178
|
raise ArgumentError unless data.is_a?(Hash)
|
188
179
|
station = Data::Location.new
|
189
180
|
station.id = data['station_id']
|
@@ -200,69 +191,72 @@ module Barometer
|
|
200
191
|
station
|
201
192
|
end
|
202
193
|
|
203
|
-
def self.
|
204
|
-
raise ArgumentError unless data.is_a?(Hash)
|
205
|
-
timezone = nil
|
206
|
-
if data && data['simpleforecast'] &&
|
207
|
-
data['simpleforecast']['forecastday'] &&
|
208
|
-
data['simpleforecast']['forecastday'].first &&
|
209
|
-
data['simpleforecast']['forecastday'].first['date']
|
210
|
-
timezone = Data::Zone.new(
|
211
|
-
data['simpleforecast']['forecastday'].first['date']['tz_long']
|
212
|
-
)
|
213
|
-
end
|
214
|
-
timezone || Data::Zone.new(nil)
|
215
|
-
end
|
216
|
-
|
217
|
-
def self.build_sun(data, timezone)
|
194
|
+
def self._build_sun(data)
|
218
195
|
raise ArgumentError unless data.is_a?(Hash)
|
219
|
-
raise ArgumentError unless timezone.is_a?(Data::Zone)
|
220
196
|
sun = nil
|
221
197
|
if data
|
222
198
|
if data['moon_phase']
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
data['moon_phase']['sunset']['minute'].to_i
|
233
|
-
)
|
234
|
-
end
|
235
|
-
|
236
|
-
sun = Data::Sun.new(
|
237
|
-
rise,
|
238
|
-
set
|
239
|
-
)
|
199
|
+
rise = Data::LocalTime.new(
|
200
|
+
data['moon_phase']['sunrise']['hour'].to_i,
|
201
|
+
data['moon_phase']['sunrise']['minute'].to_i
|
202
|
+
) if data['moon_phase']['sunrise']
|
203
|
+
set = Data::LocalTime.new(
|
204
|
+
data['moon_phase']['sunset']['hour'].to_i,
|
205
|
+
data['moon_phase']['sunset']['minute'].to_i
|
206
|
+
) if data['moon_phase']['sunset']
|
207
|
+
sun = Data::Sun.new(rise,set)
|
240
208
|
end
|
241
209
|
end
|
242
210
|
sun || Data::Sun.new
|
243
211
|
end
|
244
212
|
|
213
|
+
# override default _fetch behavior
|
214
|
+
# this service requires TWO seperate http requests (one for current
|
215
|
+
# and one for forecasted weather) ... combine the results
|
216
|
+
#
|
217
|
+
def self._fetch(query, metric=true)
|
218
|
+
result = []
|
219
|
+
result << _fetch_current(query)
|
220
|
+
result << _fetch_forecast(query)
|
221
|
+
result
|
222
|
+
end
|
223
|
+
|
245
224
|
# use HTTParty to get the current weather
|
246
|
-
|
225
|
+
#
|
226
|
+
def self._fetch_current(query)
|
247
227
|
return unless query
|
228
|
+
puts "fetch wunderground current: #{query.q}" if Barometer::debug?
|
248
229
|
self.get(
|
249
230
|
"http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml",
|
250
|
-
:query => {:query => query},
|
231
|
+
:query => {:query => query.q},
|
251
232
|
:format => :xml,
|
252
233
|
:timeout => Barometer.timeout
|
253
234
|
)['current_observation']
|
254
235
|
end
|
255
236
|
|
256
237
|
# use HTTParty to get the forecasted weather
|
257
|
-
|
238
|
+
#
|
239
|
+
def self._fetch_forecast(query)
|
258
240
|
return unless query
|
241
|
+
puts "fetch wunderground forecast: #{query.q}" if Barometer::debug?
|
259
242
|
self.get(
|
260
243
|
"http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml",
|
261
|
-
:query => {:query => query},
|
244
|
+
:query => {:query => query.q},
|
262
245
|
:format => :xml,
|
263
246
|
:timeout => Barometer.timeout
|
264
247
|
)['forecast']
|
265
248
|
end
|
266
249
|
|
250
|
+
# since we have two sets of data, override these calls to choose the
|
251
|
+
# right set of data
|
252
|
+
#
|
253
|
+
def self._current_result(data); data[0]; end
|
254
|
+
def self._forecast_result(data=nil); data[1]; end
|
255
|
+
def self._location_result(data=nil); data[0]; end
|
256
|
+
def self._station_result(data=nil); data[0]; end
|
257
|
+
def self._links_result(data=nil); data[0]; end
|
258
|
+
def self._sun_result(data=nil); data[1]; end
|
259
|
+
def self._timezone_result(data=nil); data[1]; end
|
260
|
+
|
267
261
|
end
|
268
262
|
end
|
@@ -45,103 +45,54 @@ module Barometer
|
|
45
45
|
#
|
46
46
|
class WeatherService::Yahoo < WeatherService
|
47
47
|
|
48
|
-
|
49
|
-
|
48
|
+
#########################################################################
|
49
|
+
# PRIVATE
|
50
|
+
# If class methods could be private, the remaining methods would be.
|
51
|
+
#
|
50
52
|
|
51
|
-
|
52
|
-
def self.
|
53
|
+
def self._source_name; :yahoo; end
|
54
|
+
def self._accepted_formats; [:zipcode, :weather_id]; end
|
55
|
+
|
56
|
+
def self._wet_icon_codes
|
53
57
|
codes = [1] + (3..18).to_a + [35] + (37..43).to_a + (45..47).to_a
|
54
58
|
codes.collect {|c| c.to_s}
|
55
59
|
end
|
56
|
-
def self.
|
60
|
+
def self._sunny_icon_codes
|
57
61
|
codes = (29..34).to_a + [36]
|
58
62
|
codes.collect {|c| c.to_s}
|
59
63
|
end
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
sun = nil
|
81
|
-
if measurement.current
|
82
|
-
sun = self.build_sun(result)
|
83
|
-
measurement.current.sun = sun
|
84
|
-
end
|
85
|
-
# use todays sun data for all future days
|
86
|
-
if measurement.forecast && sun
|
87
|
-
measurement.forecast.each do |forecast|
|
88
|
-
forecast.sun = sun
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
local_time = self.build_local_time(result)
|
93
|
-
if local_time
|
94
|
-
measurement.measured_at = local_time
|
95
|
-
measurement.current.current_at = local_time
|
64
|
+
|
65
|
+
def self._build_extra(measurement, result, metric=true)
|
66
|
+
#raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
67
|
+
#raise ArgumentError unless query.is_a?(Barometer::Query)
|
68
|
+
|
69
|
+
# use todays sun data for all future days
|
70
|
+
if measurement.forecast && measurement.current.sun
|
71
|
+
measurement.forecast.each do |forecast|
|
72
|
+
forecast.sun = measurement.current.sun
|
73
|
+
end
|
74
|
+
end
|
75
|
+
measurement
|
76
|
+
end
|
77
|
+
|
78
|
+
def self._build_timezone(data)
|
79
|
+
if data && data['item'] && data['item']['pubDate']
|
80
|
+
zone_match = data['item']['pubDate'].match(/ ([A-Z]*)$/)
|
81
|
+
Data::Zone.new(zone_match[1]) if zone_match
|
96
82
|
end
|
97
|
-
|
98
|
-
measurement
|
99
83
|
end
|
100
84
|
|
101
|
-
def self.
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
now_utc = Time.now.utc
|
106
|
-
|
107
|
-
# get published date
|
108
|
-
pub_date = data['item']['pubDate']
|
109
|
-
|
110
|
-
# get the TIME ZONE CODE
|
111
|
-
zone_match = pub_date.match(/ ([A-Z]*)$/) if pub_date
|
112
|
-
|
113
|
-
if zone_match
|
114
|
-
zone = zone_match[1]
|
115
|
-
|
116
|
-
# try converting pub_date to utc
|
117
|
-
# pub_date_utc = Data::Zone.code_to_utc(Time.parse(pub_date), zone) if zone
|
118
|
-
|
119
|
-
# how far back was this?
|
120
|
-
# data_age_in_seconds = now_utc - pub_date_utc
|
121
|
-
|
122
|
-
# is this older then 2 hours
|
123
|
-
# if (data_age_in_seconds < 0) || (data_age_in_seconds > (60 * 60 * 2))
|
124
|
-
# we may have converted the time wrong.
|
125
|
-
# if pub_date in the future, then?
|
126
|
-
# if pub_date too far back, then?
|
127
|
-
|
128
|
-
# for now do nothing ... don't set measured_time
|
129
|
-
# return nil
|
130
|
-
# else
|
131
|
-
# everything seems fine
|
132
|
-
# convert now to the local time
|
133
|
-
offset = Data::Zone.zone_to_offset(zone)
|
134
|
-
return Data::LocalTime.parse(now_utc + offset)
|
135
|
-
# end
|
85
|
+
def self._build_links(data)
|
86
|
+
links = {}
|
87
|
+
if data["title"] && data["link"]
|
88
|
+
links[data["title"]] = data["link"]
|
136
89
|
end
|
137
|
-
|
90
|
+
links
|
138
91
|
end
|
139
|
-
end
|
140
|
-
end
|
141
92
|
|
142
|
-
def self.
|
93
|
+
def self._build_current(data, metric=true)
|
143
94
|
raise ArgumentError unless data.is_a?(Hash)
|
144
|
-
current =
|
95
|
+
current = Measurement::Current.new(metric)
|
145
96
|
if data
|
146
97
|
if data['item'] && data['item']['yweather:condition']
|
147
98
|
condition_result = data['item']['yweather:condition']
|
@@ -171,15 +122,15 @@ end
|
|
171
122
|
current
|
172
123
|
end
|
173
124
|
|
174
|
-
def self.
|
125
|
+
def self._build_forecast(data, metric=true)
|
175
126
|
raise ArgumentError unless data.is_a?(Hash)
|
176
|
-
forecasts =
|
127
|
+
forecasts = Measurement::ForecastArray.new
|
177
128
|
|
178
129
|
if data && data['item'] && data['item']['yweather:forecast']
|
179
130
|
forecast_result = data['item']['yweather:forecast']
|
180
131
|
|
181
132
|
forecast_result.each do |forecast|
|
182
|
-
forecast_measurement =
|
133
|
+
forecast_measurement = Measurement::Forecast.new
|
183
134
|
forecast_measurement.icon = forecast['code']
|
184
135
|
forecast_measurement.date = Date.parse(forecast['date'])
|
185
136
|
forecast_measurement.condition = forecast['text']
|
@@ -193,7 +144,7 @@ end
|
|
193
144
|
forecasts
|
194
145
|
end
|
195
146
|
|
196
|
-
def self.
|
147
|
+
def self._build_location(data, geo=nil)
|
197
148
|
raise ArgumentError unless data.is_a?(Hash)
|
198
149
|
raise ArgumentError unless (geo.nil? || geo.is_a?(Data::Geo))
|
199
150
|
location = Data::Location.new
|
@@ -219,7 +170,7 @@ end
|
|
219
170
|
location
|
220
171
|
end
|
221
172
|
|
222
|
-
def self.
|
173
|
+
def self._build_sun(data)
|
223
174
|
raise ArgumentError unless data.is_a?(Hash)
|
224
175
|
sun = nil
|
225
176
|
if data && data['yweather:astronomy'] && data['item']
|
@@ -229,12 +180,14 @@ end
|
|
229
180
|
end
|
230
181
|
sun || Data::Sun.new
|
231
182
|
end
|
232
|
-
|
183
|
+
|
233
184
|
# use HTTParty to get the current weather
|
234
|
-
def self.
|
185
|
+
def self._fetch(query, metric=true)
|
186
|
+
return unless query
|
187
|
+
puts "fetch yahoo: #{query.q}" if Barometer::debug?
|
235
188
|
self.get(
|
236
189
|
"http://weather.yahooapis.com/forecastrss",
|
237
|
-
:query => {:p => query, :u => (metric ? 'c' : 'f')},
|
190
|
+
:query => {:p => query.q, :u => (metric ? 'c' : 'f')},
|
238
191
|
:format => :xml,
|
239
192
|
:timeout => Barometer.timeout
|
240
193
|
)['rss']['channel']
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# Web Service: Timezone
|
4
|
+
#
|
5
|
+
# uses geonames.org to obtain the full timezone for given coordinates
|
6
|
+
#
|
7
|
+
class WebService::Timezone < WebService
|
8
|
+
|
9
|
+
# get the full timezone for given coordinates
|
10
|
+
#
|
11
|
+
def self.fetch(latitude, longitude)
|
12
|
+
puts "timezone: #{latitude}, #{longitude}"
|
13
|
+
return nil unless latitude && longitude
|
14
|
+
_fetch_via_wunderground(latitude, longitude)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self._fetch_via_geonames(latitude, longitude)
|
18
|
+
response = self.get(
|
19
|
+
"http://ws.geonames.org/timezone",
|
20
|
+
:query => { :lat => latitude, :lng => longitude },
|
21
|
+
:format => :xml,
|
22
|
+
:timeout => Barometer.timeout
|
23
|
+
)['geonames']['timezone']
|
24
|
+
response ? Data::Zone.new(response['timezoneId']) : nil
|
25
|
+
end
|
26
|
+
|
27
|
+
def self._fetch_via_wunderground(latitude, longitude)
|
28
|
+
response = self.get(
|
29
|
+
"http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml",
|
30
|
+
:query => {:query => "#{latitude},#{longitude}"},
|
31
|
+
:format => :xml,
|
32
|
+
:timeout => Barometer.timeout
|
33
|
+
)['forecast']['simpleforecast']['forecastday'].first
|
34
|
+
response ? Data::Zone.new(response['date']['tz_long']) : nil
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
@@ -9,11 +9,13 @@ module Barometer
|
|
9
9
|
# get the weather_id for a given query
|
10
10
|
#
|
11
11
|
def self.fetch(query)
|
12
|
+
puts "fetch weather_id: #{query.q}" if Barometer::debug?
|
12
13
|
return nil unless query
|
13
14
|
raise ArgumentError unless _is_a_query?(query)
|
14
|
-
|
15
|
+
|
16
|
+
self.get(
|
15
17
|
"http://xoap.weather.com/search/search",
|
16
|
-
:query => { :where => query.q }, :format => :plain,
|
18
|
+
:query => { :where => _adjust_query(query.q) }, :format => :plain,
|
17
19
|
:timeout => Barometer.timeout
|
18
20
|
)
|
19
21
|
end
|
@@ -21,6 +23,7 @@ module Barometer
|
|
21
23
|
# get the location_date (geocode) for a given weather_id
|
22
24
|
#
|
23
25
|
def self.reverse(query)
|
26
|
+
puts "reverse weather_id: #{query.q}" if Barometer::debug?
|
24
27
|
return nil unless query
|
25
28
|
raise ArgumentError unless _is_a_query?(query)
|
26
29
|
self.get(
|
@@ -30,6 +33,18 @@ module Barometer
|
|
30
33
|
:timeout => Barometer.timeout
|
31
34
|
)['rss']['channel']["yweather:location"]
|
32
35
|
end
|
36
|
+
|
37
|
+
# filter out words that weather.com has trouble geo-locating
|
38
|
+
# mostly these are icao related
|
39
|
+
#
|
40
|
+
def self._adjust_query(query)
|
41
|
+
output = query.dup
|
42
|
+
words_to_remove = %w(international airport municipal)
|
43
|
+
words_to_remove.each do |word|
|
44
|
+
output.gsub!(/#{word}/i, "")
|
45
|
+
end
|
46
|
+
output
|
47
|
+
end
|
33
48
|
|
34
49
|
end
|
35
50
|
end
|
data/lib/barometer.rb
CHANGED
@@ -9,6 +9,12 @@ require 'barometer/formats'
|
|
9
9
|
|
10
10
|
module Barometer
|
11
11
|
|
12
|
+
@@debug_mode = false
|
13
|
+
def self.debug; @@debug_mode; end;
|
14
|
+
def self.debug=(value); @@debug_mode = value; end;
|
15
|
+
def self.debug!; @@debug_mode = true; end;
|
16
|
+
def self.debug?; @@debug_mode; end;
|
17
|
+
|
12
18
|
@@google_geocode_key = nil
|
13
19
|
def self.google_geocode_key; @@google_geocode_key; end;
|
14
20
|
def self.google_geocode_key=(key); @@google_geocode_key = key; end;
|
@@ -25,6 +31,11 @@ module Barometer
|
|
25
31
|
def self.force_geocode=(value); @@force_geocode = value; end;
|
26
32
|
def self.force_geocode!; @@force_geocode = true; end;
|
27
33
|
|
34
|
+
@@enhance_timezone = false
|
35
|
+
def self.enhance_timezone; @@enhance_timezone; end;
|
36
|
+
def self.enhance_timezone=(value); @@enhance_timezone = value; end;
|
37
|
+
def self.enhance_timezone!; @@enhance_timezone = true; end;
|
38
|
+
|
28
39
|
# adjust the timeout used when interactind with external web services
|
29
40
|
#
|
30
41
|
@@timeout = 15
|
data/lib/demometer/demometer.rb
CHANGED
@@ -32,6 +32,23 @@ class Demometer < Sinatra::Default
|
|
32
32
|
{ :weather_dot_com => { :keys => { :partner => partner_key, :license => license_key } } }
|
33
33
|
end
|
34
34
|
|
35
|
+
def config_weather_bug
|
36
|
+
if File.exists?(@@config_file)
|
37
|
+
keys = YAML.load_file(@@config_file)
|
38
|
+
if keys["weather_bug"] && keys["weather_bug"]["code"]
|
39
|
+
code = keys["weather_bug"]["code"].to_s
|
40
|
+
else
|
41
|
+
raise RunTimeError "no weatherbug.com keys"
|
42
|
+
exit
|
43
|
+
end
|
44
|
+
else
|
45
|
+
File.open(@@config_file, 'w') {|f| f << "\weather_bug:\n code: API_CODE" }
|
46
|
+
raise RunTimeError "no weatherbug.com keys"
|
47
|
+
exit
|
48
|
+
end
|
49
|
+
{ :weather_bug => { :keys => { :code => code } } }
|
50
|
+
end
|
51
|
+
|
35
52
|
helpers do
|
36
53
|
def data(title, value)
|
37
54
|
return if value.nil?
|
@@ -58,6 +75,13 @@ class Demometer < Sinatra::Default
|
|
58
75
|
Barometer::Base.config[1] << config_weather_dot_com
|
59
76
|
end
|
60
77
|
|
78
|
+
# setup weatherbug.com
|
79
|
+
if Barometer::Base.config && Barometer::Base.config[1] &&
|
80
|
+
Barometer::Base.config[1].include?(:weather_bug)
|
81
|
+
Barometer::Base.config[1].delete(:weather_bug)
|
82
|
+
Barometer::Base.config[1] << config_weather_bug
|
83
|
+
end
|
84
|
+
|
61
85
|
if params[:query] && !params[:query][:q].empty?
|
62
86
|
@barometer = Barometer.new(params[:query][:q])
|
63
87
|
@weather = @barometer.measure(metric)
|
@@ -72,5 +96,9 @@ class Demometer < Sinatra::Default
|
|
72
96
|
get '/readme.html' do
|
73
97
|
erb :readme
|
74
98
|
end
|
99
|
+
|
100
|
+
get '/about.html' do
|
101
|
+
erb :about
|
102
|
+
end
|
75
103
|
|
76
104
|
end
|