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,146 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# = Google Weather
|
4
|
+
# www.google.com
|
5
|
+
# NOTE: Google does not have an official API
|
6
|
+
#
|
7
|
+
# - key required: NO
|
8
|
+
# - registration required: NO
|
9
|
+
# - supported countries: ALL
|
10
|
+
#
|
11
|
+
# === performs geo coding
|
12
|
+
# - city: YES (except postalcode query)
|
13
|
+
# - coordinates: NO
|
14
|
+
#
|
15
|
+
# === time info
|
16
|
+
# - sun rise/set: NO
|
17
|
+
# - provides timezone: NO
|
18
|
+
# - requires TZInfo: NO
|
19
|
+
#
|
20
|
+
# == resources
|
21
|
+
# - API: http://unknown
|
22
|
+
#
|
23
|
+
# === Possible queries:
|
24
|
+
# -
|
25
|
+
#
|
26
|
+
# where query can be:
|
27
|
+
# - zipcode (US or Canadian)
|
28
|
+
# - city state; city, state
|
29
|
+
# - city
|
30
|
+
# - state
|
31
|
+
# - country
|
32
|
+
#
|
33
|
+
class Google < Service
|
34
|
+
|
35
|
+
def self.accepted_formats
|
36
|
+
[:zipcode, :postalcode, :geocode]
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.source_name
|
40
|
+
:google
|
41
|
+
end
|
42
|
+
|
43
|
+
def self._measure(measurement, query, metric=true)
|
44
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
45
|
+
raise ArgumentError unless query.is_a?(Barometer::Query)
|
46
|
+
measurement.source = self.source_name
|
47
|
+
|
48
|
+
begin
|
49
|
+
result = self.get_all(query.preferred, metric)
|
50
|
+
rescue Timeout::Error => e
|
51
|
+
return measurement
|
52
|
+
end
|
53
|
+
|
54
|
+
measurement.current = self.build_current(result, metric)
|
55
|
+
measurement.forecast = self.build_forecast(result, metric)
|
56
|
+
measurement.location = self.build_location(query.geo)
|
57
|
+
measurement
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.build_current(data, metric=true)
|
61
|
+
raise ArgumentError unless data.is_a?(Hash)
|
62
|
+
current = CurrentMeasurement.new
|
63
|
+
|
64
|
+
if data && data['forecast_information'] &&
|
65
|
+
data['forecast_information']['current_date_time']
|
66
|
+
current.time = data['forecast_information']['current_date_time']['data']
|
67
|
+
end
|
68
|
+
|
69
|
+
if data['current_conditions']
|
70
|
+
data = data['current_conditions']
|
71
|
+
current.icon = data['icon']['data'] if data['icon']
|
72
|
+
current.condition = data['condition']['data'] if data['condition']
|
73
|
+
|
74
|
+
humidity_match = data['humidity']['data'].match(/[\d]+/)
|
75
|
+
current.humidity = humidity_match[0].to_i if humidity_match
|
76
|
+
|
77
|
+
current.temperature = Temperature.new(metric)
|
78
|
+
current.temperature << [data['temp_c']['data'], data['temp_f']['data']]
|
79
|
+
|
80
|
+
current.wind = Speed.new(metric)
|
81
|
+
begin
|
82
|
+
current.wind << data['wind_condition']['data'].match(/[\d]+/)[0]
|
83
|
+
current.wind.direction = data['wind_condition']['data'].match(/Wind:.*?([\w]+).*?at/)[1]
|
84
|
+
rescue
|
85
|
+
end
|
86
|
+
end
|
87
|
+
current
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.build_forecast(data, metric=true)
|
91
|
+
raise ArgumentError unless data.is_a?(Hash)
|
92
|
+
|
93
|
+
forecasts = []
|
94
|
+
return forecasts unless data && data['forecast_information'] &&
|
95
|
+
data['forecast_information']['forecast_date']
|
96
|
+
start_date = Date.parse(data['forecast_information']['forecast_date']['data'])
|
97
|
+
data = data['forecast_conditions'] if data['forecast_conditions']
|
98
|
+
|
99
|
+
# go through each forecast and create an instance
|
100
|
+
d = 0
|
101
|
+
data.each do |forecast|
|
102
|
+
forecast_measurement = ForecastMeasurement.new
|
103
|
+
forecast_measurement.icon = forecast['icon']['data'] if forecast['icon']
|
104
|
+
forecast_measurement.condition = forecast['condition']['data'] if forecast['condition']
|
105
|
+
|
106
|
+
if (start_date + d).strftime("%a").downcase == forecast['day_of_week']['data'].downcase
|
107
|
+
forecast_measurement.date = start_date + d
|
108
|
+
end
|
109
|
+
|
110
|
+
forecast_measurement.high = Temperature.new(metric)
|
111
|
+
forecast_measurement.high << forecast['high']['data']
|
112
|
+
forecast_measurement.low = Temperature.new(metric)
|
113
|
+
forecast_measurement.low << forecast['low']['data']
|
114
|
+
|
115
|
+
forecasts << forecast_measurement
|
116
|
+
d += 1
|
117
|
+
end
|
118
|
+
forecasts
|
119
|
+
end
|
120
|
+
|
121
|
+
def self.build_location(geo=nil)
|
122
|
+
raise ArgumentError unless (geo.nil? || geo.is_a?(Barometer::Geo))
|
123
|
+
location = Location.new
|
124
|
+
if geo
|
125
|
+
location.city = geo.locality
|
126
|
+
location.state_code = geo.region
|
127
|
+
location.country = geo.country
|
128
|
+
location.country_code = geo.country_code
|
129
|
+
location.latitude = geo.latitude
|
130
|
+
location.longitude = geo.longitude
|
131
|
+
end
|
132
|
+
location
|
133
|
+
end
|
134
|
+
|
135
|
+
# use HTTParty to get the current weather
|
136
|
+
def self.get_all(query, metric=true)
|
137
|
+
Barometer::Google.get(
|
138
|
+
"http://google.com/ig/api",
|
139
|
+
:query => {:weather => query, :hl => (metric ? "en-GB" : "en-US")},
|
140
|
+
:format => :xml,
|
141
|
+
:timeout => Barometer.timeout
|
142
|
+
)['xml_api_reply']['weather']
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'httparty'
|
3
|
+
|
4
|
+
$:.unshift(File.dirname(__FILE__))
|
5
|
+
# load some changes to Httparty
|
6
|
+
require 'extensions/httparty'
|
7
|
+
|
8
|
+
module Barometer
|
9
|
+
#
|
10
|
+
# Service Class
|
11
|
+
#
|
12
|
+
# This is a base class for creating alternate weather api-consuming
|
13
|
+
# drivers. Each driver inherits from this class.
|
14
|
+
#
|
15
|
+
# Basically, all a service is required to do is take a query
|
16
|
+
# (ie "Paris") and return a complete Barometer::Measurement instance.
|
17
|
+
#
|
18
|
+
class Service
|
19
|
+
|
20
|
+
# all service drivers will use the HTTParty gem
|
21
|
+
include HTTParty
|
22
|
+
|
23
|
+
# Retrieves the weather source Service object
|
24
|
+
def self.source(source_name)
|
25
|
+
raise ArgumentError unless (source_name.is_a?(String) || source_name.is_a?(Symbol))
|
26
|
+
source_name = source_name.to_s.split("_").collect{ |s| s.capitalize }.join('')
|
27
|
+
raise ArgumentError unless Barometer.const_defined?(source_name)
|
28
|
+
raise ArgumentError unless Barometer.const_get(source_name).superclass == Barometer::Service
|
29
|
+
Barometer.const_get(source_name)
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# get current weather and future (forecasted) weather
|
34
|
+
#
|
35
|
+
def self.measure(query, metric=true)
|
36
|
+
raise ArgumentError unless query.is_a?(Barometer::Query)
|
37
|
+
|
38
|
+
measurement = Barometer::Measurement.new(self.source_name, metric)
|
39
|
+
if self.meets_requirements?(query)
|
40
|
+
query.convert!(self.accepted_formats)
|
41
|
+
measurement = self._measure(measurement, query, metric) if query.preferred
|
42
|
+
end
|
43
|
+
measurement
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.meets_requirements?(query=nil)
|
47
|
+
self.supports_country?(query) && (!self.requires_keys? || self.has_keys?)
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# NOTE: The following methods MUST be re-defined by each driver.
|
52
|
+
#
|
53
|
+
|
54
|
+
# STUB: define this method to indicate what query formats are accepted
|
55
|
+
def self.accepted_formats
|
56
|
+
raise NotImplementedError
|
57
|
+
end
|
58
|
+
|
59
|
+
# STUB: define this method to measure the current & future weather
|
60
|
+
def self._measure(measurement=nil, query=nil, metric=true)
|
61
|
+
raise NotImplementedError
|
62
|
+
end
|
63
|
+
|
64
|
+
# STUB: define this method to actually retireve the source_name
|
65
|
+
def self.source_name
|
66
|
+
raise NotImplementedError
|
67
|
+
end
|
68
|
+
|
69
|
+
# STUB: define this method to check for the existance of API keys,
|
70
|
+
# this method is NOT needed if requires_keys? returns false
|
71
|
+
def self.has_keys?
|
72
|
+
raise NotImplementedError
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# NOTE: The following methods can be re-defined by each driver. [OPTIONAL]
|
77
|
+
#
|
78
|
+
|
79
|
+
# DEFAULT: override this if you need to determine if the country is specified
|
80
|
+
def self.supports_country?(query=nil)
|
81
|
+
true
|
82
|
+
end
|
83
|
+
|
84
|
+
# DEFAULT: override this if you need to determine if API keys are required
|
85
|
+
def self.requires_keys?
|
86
|
+
false
|
87
|
+
end
|
88
|
+
|
89
|
+
#
|
90
|
+
# answer simple questions
|
91
|
+
#
|
92
|
+
|
93
|
+
#
|
94
|
+
# WINDY?
|
95
|
+
#
|
96
|
+
def self.windy?(measurement, threshold=10, utc_time=nil)
|
97
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
98
|
+
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
99
|
+
raise ArgumentError unless (utc_time.is_a?(Time) || utc_time.nil?)
|
100
|
+
|
101
|
+
measurement.current?(utc_time) ?
|
102
|
+
self.currently_windy?(measurement, threshold) :
|
103
|
+
self.forecasted_windy?(measurement, threshold, utc_time)
|
104
|
+
end
|
105
|
+
|
106
|
+
# cookie cutter answer, a driver can override this if they answer it differently
|
107
|
+
# if a service doesn't support obtaining the wind value, it will be ignored
|
108
|
+
def self.currently_windy?(measurement, threshold=10)
|
109
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
110
|
+
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
111
|
+
return nil if (!measurement.current || !measurement.current.wind?)
|
112
|
+
measurement.metric? ?
|
113
|
+
measurement.current.wind.kph.to_f >= threshold.to_f :
|
114
|
+
measurement.current.wind.mph.to_f >= threshold.to_f
|
115
|
+
end
|
116
|
+
|
117
|
+
# no driver can currently answer this question, so it doesn't have any code
|
118
|
+
def self.forecasted_windy?(measurement, threshold, utc_time); nil; end
|
119
|
+
|
120
|
+
#
|
121
|
+
# WET?
|
122
|
+
#
|
123
|
+
def self.wet?(measurement, threshold=50, utc_time=nil)
|
124
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
125
|
+
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
126
|
+
raise ArgumentError unless (utc_time.is_a?(Time) || utc_time.nil?)
|
127
|
+
measurement.current?(utc_time) ?
|
128
|
+
self.currently_wet?(measurement, threshold) :
|
129
|
+
self.forecasted_wet?(measurement, threshold, utc_time)
|
130
|
+
end
|
131
|
+
|
132
|
+
# cookie cutter answer
|
133
|
+
def self.currently_wet?(measurement, threshold=50)
|
134
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
135
|
+
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
136
|
+
return nil unless measurement.current
|
137
|
+
self.currently_wet_by_icon?(measurement.current) ||
|
138
|
+
self.currently_wet_by_dewpoint?(measurement) ||
|
139
|
+
self.currently_wet_by_humidity?(measurement.current) ||
|
140
|
+
self.currently_wet_by_pop?(measurement, threshold)
|
141
|
+
end
|
142
|
+
|
143
|
+
# cookie cutter answer
|
144
|
+
def self.currently_wet_by_dewpoint?(measurement)
|
145
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
146
|
+
return nil if (!measurement.current || !measurement.current.temperature? ||
|
147
|
+
!measurement.current.dew_point?)
|
148
|
+
measurement.metric? ?
|
149
|
+
measurement.current.temperature.c.to_f <= measurement.current.dew_point.c.to_f :
|
150
|
+
measurement.current.temperature.f.to_f <= measurement.current.dew_point.f.to_f
|
151
|
+
end
|
152
|
+
|
153
|
+
# cookie cutter answer
|
154
|
+
def self.currently_wet_by_humidity?(current_measurement)
|
155
|
+
raise ArgumentError unless current_measurement.is_a?(Barometer::CurrentMeasurement)
|
156
|
+
return nil unless current_measurement.humidity?
|
157
|
+
current_measurement.humidity.to_i >= 99
|
158
|
+
end
|
159
|
+
|
160
|
+
# cookie cutter answer
|
161
|
+
def self.currently_wet_by_pop?(measurement, threshold=50)
|
162
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
163
|
+
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
164
|
+
return nil unless measurement.forecast
|
165
|
+
# get todays forecast
|
166
|
+
forecast_measurement = measurement.for
|
167
|
+
return nil unless forecast_measurement
|
168
|
+
forecast_measurement.pop.to_f >= threshold.to_f
|
169
|
+
end
|
170
|
+
|
171
|
+
# cookie cutter answer
|
172
|
+
def self.forecasted_wet?(measurement, threshold=50, utc_time=nil)
|
173
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
174
|
+
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
175
|
+
raise ArgumentError unless (utc_time.is_a?(Time) || utc_time.nil?)
|
176
|
+
return nil unless measurement.forecast
|
177
|
+
forecast_measurement = measurement.for(utc_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?(Barometer::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?(Barometer::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?(Barometer::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
|
+
|
212
|
+
#
|
213
|
+
# DAY?
|
214
|
+
#
|
215
|
+
def self.day?(measurement, utc_time=nil)
|
216
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
217
|
+
raise ArgumentError unless (utc_time.is_a?(Time) || utc_time.nil?)
|
218
|
+
|
219
|
+
measurement.current?(utc_time) ?
|
220
|
+
self.currently_day?(measurement) :
|
221
|
+
self.forecasted_day?(measurement, utc_time)
|
222
|
+
end
|
223
|
+
|
224
|
+
def self.currently_day?(measurement)
|
225
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
226
|
+
return nil unless measurement.current && measurement.current.sun
|
227
|
+
self.currently_after_sunrise?(measurement.current) &&
|
228
|
+
self.currently_before_sunset?(measurement.current)
|
229
|
+
end
|
230
|
+
|
231
|
+
def self.currently_after_sunrise?(current_measurement)
|
232
|
+
raise ArgumentError unless current_measurement.is_a?(Barometer::CurrentMeasurement)
|
233
|
+
return nil unless current_measurement.sun && current_measurement.sun.rise
|
234
|
+
Time.now.utc >= current_measurement.sun.rise
|
235
|
+
end
|
236
|
+
|
237
|
+
def self.currently_before_sunset?(current_measurement)
|
238
|
+
raise ArgumentError unless current_measurement.is_a?(Barometer::CurrentMeasurement)
|
239
|
+
return nil unless current_measurement.sun && current_measurement.sun.set
|
240
|
+
Time.now.utc <= current_measurement.sun.set
|
241
|
+
end
|
242
|
+
|
243
|
+
def self.forecasted_day?(measurement, utc_time=nil)
|
244
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
245
|
+
raise ArgumentError unless (utc_time.is_a?(Time) || utc_time.nil?)
|
246
|
+
return nil unless measurement.forecast
|
247
|
+
forecast_measurement = measurement.for(utc_time)
|
248
|
+
return nil unless forecast_measurement
|
249
|
+
self.forecasted_after_sunrise?(forecast_measurement, utc_time) &&
|
250
|
+
self.forecasted_before_sunset?(forecast_measurement, utc_time)
|
251
|
+
end
|
252
|
+
|
253
|
+
def self.forecasted_after_sunrise?(forecast_measurement, utc_time)
|
254
|
+
raise ArgumentError unless forecast_measurement.is_a?(Barometer::ForecastMeasurement)
|
255
|
+
raise ArgumentError unless utc_time.is_a?(Time)
|
256
|
+
return nil unless forecast_measurement.sun && forecast_measurement.sun.rise
|
257
|
+
utc_time >= forecast_measurement.sun.rise
|
258
|
+
end
|
259
|
+
|
260
|
+
def self.forecasted_before_sunset?(forecast_measurement, utc_time)
|
261
|
+
raise ArgumentError unless forecast_measurement.is_a?(Barometer::ForecastMeasurement)
|
262
|
+
raise ArgumentError unless utc_time.is_a?(Time)
|
263
|
+
return nil unless forecast_measurement.sun && forecast_measurement.sun.set
|
264
|
+
utc_time <= forecast_measurement.sun.set
|
265
|
+
end
|
266
|
+
|
267
|
+
#
|
268
|
+
# SUNNY?
|
269
|
+
#
|
270
|
+
def self.sunny?(measurement, utc_time=nil)
|
271
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
272
|
+
raise ArgumentError unless (utc_time.is_a?(Time) || utc_time.nil?)
|
273
|
+
measurement.current?(utc_time) ?
|
274
|
+
self.currently_sunny?(measurement) :
|
275
|
+
self.forecasted_sunny?(measurement, utc_time)
|
276
|
+
end
|
277
|
+
|
278
|
+
# cookie cutter answer
|
279
|
+
def self.currently_sunny?(measurement)
|
280
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
281
|
+
return nil unless measurement.current
|
282
|
+
return false if self.currently_day?(measurement) == false
|
283
|
+
self.currently_sunny_by_icon?(measurement.current)
|
284
|
+
end
|
285
|
+
|
286
|
+
# cookie cutter answer
|
287
|
+
def self.forecasted_sunny?(measurement, utc_time=nil)
|
288
|
+
raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
|
289
|
+
raise ArgumentError unless (utc_time.is_a?(Time) || utc_time.nil?)
|
290
|
+
return nil unless measurement.forecast
|
291
|
+
return false if self.forecasted_day?(measurement, utc_time) == false
|
292
|
+
forecast_measurement = measurement.for(utc_time)
|
293
|
+
return nil unless forecast_measurement
|
294
|
+
self.forecasted_sunny_by_icon?(forecast_measurement)
|
295
|
+
end
|
296
|
+
|
297
|
+
def self.currently_sunny_by_icon?(current_measurement)
|
298
|
+
raise ArgumentError unless current_measurement.is_a?(Barometer::CurrentMeasurement)
|
299
|
+
return nil unless self.sunny_icon_codes
|
300
|
+
return nil unless current_measurement.icon?
|
301
|
+
current_measurement.icon.is_a?(String) ?
|
302
|
+
self.sunny_icon_codes.include?(current_measurement.icon.to_s.downcase) :
|
303
|
+
self.sunny_icon_codes.include?(current_measurement.icon)
|
304
|
+
end
|
305
|
+
|
306
|
+
def self.forecasted_sunny_by_icon?(forecast_measurement)
|
307
|
+
raise ArgumentError unless forecast_measurement.is_a?(Barometer::ForecastMeasurement)
|
308
|
+
return nil unless self.sunny_icon_codes
|
309
|
+
return nil unless forecast_measurement.icon?
|
310
|
+
forecast_measurement.icon.is_a?(String) ?
|
311
|
+
self.sunny_icon_codes.include?(forecast_measurement.icon.to_s.downcase) :
|
312
|
+
self.sunny_icon_codes.include?(forecast_measurement.icon)
|
313
|
+
end
|
314
|
+
|
315
|
+
# this returns an array of codes that indicate "sunny"
|
316
|
+
def self.sunny_icon_codes; nil; end
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
# def key_name
|
323
|
+
# # what variables holds the api key?
|
324
|
+
# end
|