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
@@ -10,10 +10,11 @@ module Barometer
|
|
10
10
|
# Service Class
|
11
11
|
#
|
12
12
|
# This is a base class for creating alternate weather api-consuming
|
13
|
-
# drivers. Each driver inherits from this class.
|
13
|
+
# drivers. Each driver inherits from this class. This class creates
|
14
|
+
# some default behaviours, but they can easily be over-ridden.
|
14
15
|
#
|
15
16
|
# Basically, all a service is required to do is take a query
|
16
|
-
# (ie "Paris") and return a complete
|
17
|
+
# (ie "Paris") and return a complete Barometer::Measurement instance.
|
17
18
|
#
|
18
19
|
class WeatherService
|
19
20
|
# all service drivers will use the HTTParty gem
|
@@ -34,300 +35,157 @@ module Barometer
|
|
34
35
|
def self.measure(query, metric=true)
|
35
36
|
raise ArgumentError unless query.is_a?(Barometer::Query)
|
36
37
|
|
37
|
-
measurement =
|
38
|
-
|
39
|
-
|
38
|
+
measurement = Barometer::Measurement.new(self._source_name, metric)
|
39
|
+
measurement.start_at = Time.now.utc
|
40
|
+
if self._meets_requirements?(query)
|
41
|
+
converted_query = query.convert!(self._accepted_formats)
|
40
42
|
if converted_query
|
43
|
+
measurement.source = self._source_name
|
41
44
|
measurement.query = converted_query.q
|
42
45
|
measurement.format = converted_query.format
|
43
46
|
measurement = self._measure(measurement, converted_query, metric)
|
44
47
|
end
|
45
48
|
end
|
49
|
+
measurement.end_at = Time.now.utc
|
46
50
|
measurement
|
47
51
|
end
|
48
52
|
|
49
|
-
|
50
|
-
|
51
|
-
|
53
|
+
#########################################################################
|
54
|
+
# PRIVATE
|
55
|
+
# If class methods could be private, the remaining methods would be.
|
56
|
+
#
|
52
57
|
|
53
58
|
#
|
54
|
-
#
|
59
|
+
# REQUIRED
|
60
|
+
# re-defining these methods will be required
|
55
61
|
#
|
56
62
|
|
57
|
-
|
58
|
-
def self.
|
59
|
-
|
60
|
-
|
61
|
-
def self.
|
63
|
+
def self._source_name; raise NotImplementedError; end
|
64
|
+
def self._accepted_formats; raise NotImplementedError; end
|
65
|
+
def self._fetch(query=nil, metric=true); nil; end
|
66
|
+
def self._build_current(result=nil, metric=true); nil; end
|
67
|
+
def self._build_forecast(result=nil, metric=true); nil; end
|
62
68
|
|
63
|
-
#
|
64
|
-
|
65
|
-
|
69
|
+
#
|
70
|
+
# PROBABLE
|
71
|
+
# re-defining these methods is probable though not a must
|
72
|
+
#
|
73
|
+
|
74
|
+
# data processing stubs
|
75
|
+
#
|
76
|
+
def self._build_location(result=nil, geo=nil); nil; end
|
77
|
+
def self._build_station(result=nil); Data::Location.new; end
|
78
|
+
def self._build_links(result=nil); {}; end
|
79
|
+
def self._build_sun(result=nil); Data::Sun.new; end
|
80
|
+
def self._build_timezone(result=nil); nil; end
|
81
|
+
def self._build_extra(measurement=nil, result=nil, metric=true); measurement; end
|
82
|
+
def self._build_local_time(measurement)
|
83
|
+
(measurement && measurement.timezone) ? Data::LocalTime.parse(measurement.timezone.now) : nil
|
66
84
|
end
|
67
|
-
|
85
|
+
|
86
|
+
# given the result set, return the full_timezone or local time ...
|
87
|
+
# if not available return nil
|
88
|
+
def self._parse_full_timezone(result=nil); nil; end
|
89
|
+
def self._parse_local_time(result=nil); nil; end
|
90
|
+
|
91
|
+
# this returns an array of codes that indicate "wet"
|
92
|
+
def self._wet_icon_codes; nil; end
|
93
|
+
# this returns an array of codes that indicate "sunny"
|
94
|
+
def self._sunny_icon_codes; nil; end
|
95
|
+
|
68
96
|
#
|
69
|
-
#
|
97
|
+
# OPTIONAL
|
98
|
+
# re-defining these methods will be optional
|
70
99
|
#
|
71
100
|
|
72
101
|
# STUB: define this method to check for the existance of API keys,
|
73
102
|
# this method is NOT needed if requires_keys? returns false
|
74
|
-
def self.
|
103
|
+
def self._has_keys?; raise NotImplementedError; end
|
75
104
|
|
76
105
|
# STUB: define this method to check for the existance of API keys,
|
77
106
|
# this method is NOT needed if requires_keys? returns false
|
78
|
-
def self.
|
107
|
+
def self._keys=(keys=nil); nil; end
|
79
108
|
|
80
109
|
# DEFAULT: override this if you need to determine if the country is specified
|
81
|
-
def self.
|
110
|
+
def self._supports_country?(query=nil); true; end
|
82
111
|
|
83
112
|
# DEFAULT: override this if you need to determine if API keys are required
|
84
|
-
def self.
|
113
|
+
def self._requires_keys?; false; end
|
85
114
|
|
115
|
+
# data accessors
|
116
|
+
# (see the wunderground driver for an example of overriding these)
|
86
117
|
#
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
def self.
|
94
|
-
|
95
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
96
|
-
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
97
|
-
raise ArgumentError unless (local_time.is_a?(Data::LocalDateTime) || local_time.nil?)
|
98
|
-
|
99
|
-
measurement.current?(local_time) ?
|
100
|
-
self.currently_windy?(measurement, threshold) :
|
101
|
-
self.forecasted_windy?(measurement, threshold, local_time)
|
102
|
-
end
|
103
|
-
|
104
|
-
# cookie cutter answer, a driver can override this if they answer it differently
|
105
|
-
# if a service doesn't support obtaining the wind value, it will be ignored
|
106
|
-
def self.currently_windy?(measurement, threshold=10)
|
107
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
108
|
-
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
109
|
-
return nil if (!measurement.current || !measurement.current.wind?)
|
110
|
-
measurement.metric? ?
|
111
|
-
measurement.current.wind.kph.to_f >= threshold.to_f :
|
112
|
-
measurement.current.wind.mph.to_f >= threshold.to_f
|
113
|
-
end
|
118
|
+
def self._current_result(data=nil); data; end
|
119
|
+
def self._forecast_result(data=nil); data; end
|
120
|
+
def self._location_result(data=nil); data; end
|
121
|
+
def self._station_result(data=nil); data; end
|
122
|
+
def self._links_result(data=nil); data; end
|
123
|
+
def self._sun_result(data=nil); data; end
|
124
|
+
def self._timezone_result(data=nil); data; end
|
125
|
+
def self._time_result(data=nil); data; end
|
114
126
|
|
115
|
-
# no driver can currently answer this question, so it doesn't have any code
|
116
|
-
def self.forecasted_windy?(measurement, threshold, time_string); nil; end
|
117
|
-
|
118
127
|
#
|
119
|
-
#
|
128
|
+
# COMPLETE
|
129
|
+
# re-defining these methods should not be needed, as the behavior
|
130
|
+
# can be adjusted using methods above
|
120
131
|
#
|
121
|
-
def self.wet?(measurement, threshold=50, time_string=nil)
|
122
|
-
local_time = Data::LocalDateTime.parse(time_string) if time_string
|
123
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
124
|
-
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
125
|
-
raise ArgumentError unless (local_time.is_a?(Data::LocalDateTime) || local_time.nil?)
|
126
|
-
measurement.current?(local_time) ?
|
127
|
-
self.currently_wet?(measurement, threshold) :
|
128
|
-
self.forecasted_wet?(measurement, threshold, local_time)
|
129
|
-
end
|
130
|
-
|
131
|
-
# cookie cutter answer
|
132
|
-
def self.currently_wet?(measurement, threshold=50)
|
133
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
134
|
-
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
135
|
-
return nil unless measurement.current
|
136
|
-
self.currently_wet_by_icon?(measurement.current) ||
|
137
|
-
self.currently_wet_by_dewpoint?(measurement) ||
|
138
|
-
self.currently_wet_by_humidity?(measurement.current) ||
|
139
|
-
self.currently_wet_by_pop?(measurement, threshold)
|
140
|
-
end
|
141
|
-
|
142
|
-
# cookie cutter answer
|
143
|
-
def self.currently_wet_by_dewpoint?(measurement)
|
144
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
145
|
-
return nil if (!measurement.current || !measurement.current.temperature? ||
|
146
|
-
!measurement.current.dew_point?)
|
147
|
-
measurement.metric? ?
|
148
|
-
measurement.current.temperature.c.to_f <= measurement.current.dew_point.c.to_f :
|
149
|
-
measurement.current.temperature.f.to_f <= measurement.current.dew_point.f.to_f
|
150
|
-
end
|
151
|
-
|
152
|
-
# cookie cutter answer
|
153
|
-
def self.currently_wet_by_humidity?(current_measurement)
|
154
|
-
raise ArgumentError unless current_measurement.is_a?(Data::CurrentMeasurement)
|
155
|
-
return nil unless current_measurement.humidity?
|
156
|
-
current_measurement.humidity.to_i >= 99
|
157
|
-
end
|
158
|
-
|
159
|
-
# cookie cutter answer
|
160
|
-
def self.currently_wet_by_pop?(measurement, threshold=50)
|
161
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
162
|
-
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
163
|
-
return nil unless measurement.forecast
|
164
|
-
# get todays forecast
|
165
|
-
forecast_measurement = measurement.for
|
166
|
-
return nil unless forecast_measurement
|
167
|
-
forecast_measurement.pop.to_f >= threshold.to_f
|
168
|
-
end
|
169
|
-
|
170
|
-
# cookie cutter answer
|
171
|
-
def self.forecasted_wet?(measurement, threshold=50, time_string=nil)
|
172
|
-
local_time = Data::LocalDateTime.parse(time_string) if time_string
|
173
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
174
|
-
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
175
|
-
raise ArgumentError unless (local_time.is_a?(Data::LocalDateTime) || local_time.nil?)
|
176
|
-
return nil unless measurement.forecast
|
177
|
-
forecast_measurement = measurement.for(local_time)
|
178
|
-
return nil unless forecast_measurement
|
179
|
-
self.forecasted_wet_by_icon?(forecast_measurement) ||
|
180
|
-
self.forecasted_wet_by_pop?(forecast_measurement, threshold)
|
181
|
-
end
|
182
|
-
|
183
|
-
# cookie cutter answer
|
184
|
-
def self.forecasted_wet_by_pop?(forecast_measurement, threshold=50)
|
185
|
-
raise ArgumentError unless forecast_measurement.is_a?(Data::ForecastMeasurement)
|
186
|
-
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
187
|
-
return nil unless forecast_measurement.pop?
|
188
|
-
forecast_measurement.pop.to_f >= threshold.to_f
|
189
|
-
end
|
190
|
-
|
191
|
-
def self.currently_wet_by_icon?(current_measurement)
|
192
|
-
raise ArgumentError unless current_measurement.is_a?(Data::CurrentMeasurement)
|
193
|
-
return nil unless self.wet_icon_codes
|
194
|
-
return nil unless current_measurement.icon?
|
195
|
-
current_measurement.icon.is_a?(String) ?
|
196
|
-
self.wet_icon_codes.include?(current_measurement.icon.to_s.downcase) :
|
197
|
-
self.wet_icon_codes.include?(current_measurement.icon)
|
198
|
-
end
|
199
|
-
|
200
|
-
def self.forecasted_wet_by_icon?(forecast_measurement)
|
201
|
-
raise ArgumentError unless forecast_measurement.is_a?(Data::ForecastMeasurement)
|
202
|
-
return nil unless self.wet_icon_codes
|
203
|
-
return nil unless forecast_measurement.icon?
|
204
|
-
forecast_measurement.icon.is_a?(String) ?
|
205
|
-
self.wet_icon_codes.include?(forecast_measurement.icon.to_s.downcase) :
|
206
|
-
self.wet_icon_codes.include?(forecast_measurement.icon)
|
207
|
-
end
|
208
|
-
|
209
|
-
# this returns an array of codes that indicate "wet"
|
210
|
-
def self.wet_icon_codes; nil; end
|
211
132
|
|
133
|
+
# this is the generic measuring and data processing for each weather service
|
134
|
+
# driver. this method should be re-defined if the driver in question
|
135
|
+
# doesn't fit into "generic" (ie wunderground)
|
212
136
|
#
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
def self.currently_before_sunset?(current_measurement)
|
241
|
-
raise ArgumentError unless current_measurement.is_a?(Data::CurrentMeasurement)
|
242
|
-
return nil unless current_measurement.current_at &&
|
243
|
-
current_measurement.sun && current_measurement.sun.set
|
244
|
-
#Time.now.utc <= current_measurement.sun.set
|
245
|
-
current_measurement.current_at <= current_measurement.sun.set
|
246
|
-
end
|
247
|
-
|
248
|
-
def self.forecasted_day?(measurement, time_string=nil)
|
249
|
-
local_datetime = Data::LocalDateTime.parse(time_string) if time_string
|
250
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
251
|
-
raise ArgumentError unless (local_datetime.is_a?(Data::LocalDateTime) || local_datetime.nil?)
|
252
|
-
return nil unless measurement.forecast
|
253
|
-
forecast_measurement = measurement.for(local_datetime)
|
254
|
-
return nil unless forecast_measurement
|
255
|
-
self.forecasted_after_sunrise?(forecast_measurement, local_datetime) &&
|
256
|
-
self.forecasted_before_sunset?(forecast_measurement, local_datetime)
|
257
|
-
end
|
258
|
-
|
259
|
-
def self.forecasted_after_sunrise?(forecast_measurement, time_string)
|
260
|
-
local_datetime = Data::LocalDateTime.parse(time_string) if time_string
|
261
|
-
raise ArgumentError unless forecast_measurement.is_a?(Data::ForecastMeasurement)
|
262
|
-
raise ArgumentError unless (local_datetime.is_a?(Data::LocalDateTime) || local_datetime.nil?)
|
263
|
-
return nil unless forecast_measurement.sun && forecast_measurement.sun.rise
|
264
|
-
local_datetime >= forecast_measurement.sun.rise
|
265
|
-
end
|
266
|
-
|
267
|
-
def self.forecasted_before_sunset?(forecast_measurement, time_string)
|
268
|
-
local_datetime = Data::LocalDateTime.parse(time_string) if time_string
|
269
|
-
raise ArgumentError unless forecast_measurement.is_a?(Data::ForecastMeasurement)
|
270
|
-
raise ArgumentError unless (local_datetime.is_a?(Data::LocalDateTime) || local_datetime.nil?)
|
271
|
-
return nil unless forecast_measurement.sun && forecast_measurement.sun.set
|
272
|
-
local_datetime <= forecast_measurement.sun.set
|
137
|
+
def self._measure(measurement, query, metric=true)
|
138
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
139
|
+
raise ArgumentError unless query.is_a?(Barometer::Query)
|
140
|
+
|
141
|
+
begin
|
142
|
+
result = _fetch(query, metric)
|
143
|
+
rescue Timeout::Error => e
|
144
|
+
return measurement
|
145
|
+
end
|
146
|
+
|
147
|
+
if result
|
148
|
+
measurement.current = _build_current(_current_result(result), metric)
|
149
|
+
measurement.forecast = _build_forecast(_forecast_result(result), metric)
|
150
|
+
measurement.location = _build_location(_location_result(result), query.geo)
|
151
|
+
measurement.station = _build_station(_station_result(result))
|
152
|
+
measurement.links = _build_links(_links_result(result))
|
153
|
+
measurement.current.sun = _build_sun(_sun_result(result)) if measurement.current
|
154
|
+
measurement.timezone = _timezone(_timezone_result(result), query, measurement.location)
|
155
|
+
if local_time = _local_time(_time_result(result), measurement)
|
156
|
+
measurement.measured_at = local_time
|
157
|
+
measurement.current.current_at = local_time
|
158
|
+
end
|
159
|
+
measurement = _build_extra(measurement, result, metric)
|
160
|
+
end
|
161
|
+
|
162
|
+
measurement
|
273
163
|
end
|
274
164
|
|
165
|
+
# either get the timezone based on coords, or build it from the data
|
275
166
|
#
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
# cookie cutter answer
|
288
|
-
def self.currently_sunny?(measurement)
|
289
|
-
raise ArgumentError unless measurement.is_a?(Data::Measurement)
|
290
|
-
return nil unless measurement.current
|
291
|
-
return false if self.currently_day?(measurement) == false
|
292
|
-
self.currently_sunny_by_icon?(measurement.current)
|
167
|
+
def self._timezone(result=nil, query=nil, location=nil)
|
168
|
+
if full_timezone = _parse_full_timezone(result)
|
169
|
+
full_timezone
|
170
|
+
elsif query && query.timezone
|
171
|
+
query.timezone
|
172
|
+
elsif Barometer.enhance_timezone && location &&
|
173
|
+
location.latitude && location.longitude
|
174
|
+
WebService::Timezone.fetch(location.latitude, location.longitude)
|
175
|
+
else
|
176
|
+
_build_timezone(result)
|
177
|
+
end
|
293
178
|
end
|
294
179
|
|
295
|
-
#
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
raise ArgumentError unless (local_time.is_a?(Data::LocalDateTime) || local_time.nil?)
|
300
|
-
return nil unless measurement.forecast
|
301
|
-
return false if self.forecasted_day?(measurement, local_time) == false
|
302
|
-
forecast_measurement = measurement.for(local_time)
|
303
|
-
return nil unless forecast_measurement
|
304
|
-
self.forecasted_sunny_by_icon?(forecast_measurement)
|
305
|
-
end
|
306
|
-
|
307
|
-
def self.currently_sunny_by_icon?(current_measurement)
|
308
|
-
raise ArgumentError unless current_measurement.is_a?(Data::CurrentMeasurement)
|
309
|
-
return nil unless self.sunny_icon_codes
|
310
|
-
return nil unless current_measurement.icon?
|
311
|
-
current_measurement.icon.is_a?(String) ?
|
312
|
-
self.sunny_icon_codes.include?(current_measurement.icon.to_s.downcase) :
|
313
|
-
self.sunny_icon_codes.include?(current_measurement.icon)
|
180
|
+
# return the current local time (as Data::LocalTime)
|
181
|
+
#
|
182
|
+
def self._local_time(result, measurement=nil)
|
183
|
+
_parse_local_time(result) || _build_local_time(measurement)
|
314
184
|
end
|
315
185
|
|
316
|
-
def self.
|
317
|
-
|
318
|
-
return nil unless self.sunny_icon_codes
|
319
|
-
return nil unless forecast_measurement.icon?
|
320
|
-
forecast_measurement.icon.is_a?(String) ?
|
321
|
-
self.sunny_icon_codes.include?(forecast_measurement.icon.to_s.downcase) :
|
322
|
-
self.sunny_icon_codes.include?(forecast_measurement.icon)
|
186
|
+
def self._meets_requirements?(query=nil)
|
187
|
+
self._supports_country?(query) && (!self._requires_keys? || self._has_keys?)
|
323
188
|
end
|
324
|
-
|
325
|
-
# this returns an array of codes that indicate "sunny"
|
326
|
-
def self.sunny_icon_codes; nil; end
|
327
189
|
|
328
190
|
end
|
329
|
-
end
|
330
|
-
|
331
|
-
# def key_name
|
332
|
-
# # what variables holds the api key?
|
333
|
-
# end
|
191
|
+
end
|