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.
Files changed (108) hide show
  1. data/README.rdoc +78 -70
  2. data/VERSION.yml +2 -2
  3. data/bin/barometer +100 -37
  4. data/lib/barometer.rb +12 -8
  5. data/lib/barometer/base.rb +48 -20
  6. data/lib/barometer/data.rb +5 -1
  7. data/lib/barometer/data/current.rb +23 -15
  8. data/lib/barometer/data/distance.rb +15 -5
  9. data/lib/barometer/data/forecast.rb +23 -5
  10. data/lib/barometer/data/geo.rb +16 -54
  11. data/lib/barometer/data/local_datetime.rb +137 -0
  12. data/lib/barometer/data/local_time.rb +134 -0
  13. data/lib/barometer/data/location.rb +6 -1
  14. data/lib/barometer/data/measurement.rb +71 -42
  15. data/lib/barometer/data/night.rb +69 -0
  16. data/lib/barometer/data/pressure.rb +15 -5
  17. data/lib/barometer/data/speed.rb +16 -5
  18. data/lib/barometer/data/sun.rb +8 -20
  19. data/lib/barometer/data/temperature.rb +22 -9
  20. data/lib/barometer/data/units.rb +10 -19
  21. data/lib/barometer/data/zone.rb +135 -9
  22. data/lib/barometer/formats.rb +12 -0
  23. data/lib/barometer/formats/coordinates.rb +42 -0
  24. data/lib/barometer/formats/format.rb +46 -0
  25. data/lib/barometer/formats/geocode.rb +51 -0
  26. data/lib/barometer/formats/icao.rb +37 -0
  27. data/lib/barometer/formats/postalcode.rb +22 -0
  28. data/lib/barometer/formats/short_zipcode.rb +17 -0
  29. data/lib/barometer/formats/weather_id.rb +107 -0
  30. data/lib/barometer/formats/zipcode.rb +31 -0
  31. data/lib/barometer/query.rb +61 -232
  32. data/lib/barometer/services.rb +14 -4
  33. data/lib/barometer/translations/icao_country_codes.yml +9 -0
  34. data/lib/barometer/translations/weather_country_codes.yml +17 -0
  35. data/lib/barometer/weather.rb +51 -30
  36. data/lib/barometer/{services → weather_services}/google.rb +23 -26
  37. data/lib/barometer/weather_services/noaa.rb +6 -0
  38. data/lib/barometer/{services → weather_services}/service.rb +101 -92
  39. data/lib/barometer/weather_services/weather_bug.rb +6 -0
  40. data/lib/barometer/weather_services/weather_dot_com.rb +261 -0
  41. data/lib/barometer/{services → weather_services}/wunderground.rb +58 -76
  42. data/lib/barometer/{services → weather_services}/yahoo.rb +91 -121
  43. data/lib/barometer/web_services/geocode.rb +33 -0
  44. data/lib/barometer/web_services/weather_id.rb +37 -0
  45. data/lib/barometer/web_services/web_service.rb +32 -0
  46. data/lib/demometer/demometer.rb +31 -4
  47. data/lib/demometer/views/forecast.erb +20 -0
  48. data/lib/demometer/views/index.erb +10 -3
  49. data/lib/demometer/views/measurement.erb +8 -3
  50. data/lib/demometer/views/readme.erb +63 -24
  51. data/spec/barometer_spec.rb +18 -36
  52. data/spec/{data_current_spec.rb → data/current_spec.rb} +73 -49
  53. data/spec/{data_distance_spec.rb → data/distance_spec.rb} +30 -30
  54. data/spec/{data_forecast_spec.rb → data/forecast_spec.rb} +57 -15
  55. data/spec/data/geo_spec.rb +91 -0
  56. data/spec/data/local_datetime_spec.rb +269 -0
  57. data/spec/data/local_time_spec.rb +239 -0
  58. data/spec/{data_location_spec.rb → data/location_spec.rb} +12 -1
  59. data/spec/{data_measurement_spec.rb → data/measurement_spec.rb} +135 -66
  60. data/spec/data/night_measurement_spec.rb +136 -0
  61. data/spec/{data_pressure_spec.rb → data/pressure_spec.rb} +29 -29
  62. data/spec/{data_speed_spec.rb → data/speed_spec.rb} +30 -30
  63. data/spec/data/sun_spec.rb +49 -0
  64. data/spec/{data_temperature_spec.rb → data/temperature_spec.rb} +44 -44
  65. data/spec/{units_spec.rb → data/units_spec.rb} +6 -6
  66. data/spec/{data_zone_spec.rb → data/zone_spec.rb} +15 -15
  67. data/spec/fixtures/formats/weather_id/90210.xml +1 -0
  68. data/spec/fixtures/formats/weather_id/atlanta.xml +1 -0
  69. data/spec/fixtures/formats/weather_id/from_USGA0028.xml +1 -0
  70. data/spec/fixtures/formats/weather_id/new_york.xml +1 -0
  71. data/spec/fixtures/{geocode_40_73.xml → geocode/40_73.xml} +0 -0
  72. data/spec/fixtures/{geocode_90210.xml → geocode/90210.xml} +0 -0
  73. data/spec/fixtures/{geocode_T5B4M9.xml → geocode/T5B4M9.xml} +0 -0
  74. data/spec/fixtures/geocode/atlanta.xml +1 -0
  75. data/spec/fixtures/{geocode_calgary_ab.xml → geocode/calgary_ab.xml} +0 -0
  76. data/spec/fixtures/{geocode_ksfo.xml → geocode/ksfo.xml} +0 -0
  77. data/spec/fixtures/{geocode_newyork_ny.xml → geocode/newyork_ny.xml} +0 -0
  78. data/spec/fixtures/{google_calgary_ab.xml → services/google/calgary_ab.xml} +0 -0
  79. data/spec/fixtures/services/weather_dot_com/90210.xml +1 -0
  80. data/spec/fixtures/{current_calgary_ab.xml → services/wunderground/current_calgary_ab.xml} +0 -0
  81. data/spec/fixtures/{forecast_calgary_ab.xml → services/wunderground/forecast_calgary_ab.xml} +0 -0
  82. data/spec/fixtures/{yahoo_90210.xml → services/yahoo/90210.xml} +0 -0
  83. data/spec/formats/coordinates_spec.rb +158 -0
  84. data/spec/formats/format_spec.rb +73 -0
  85. data/spec/formats/geocode_spec.rb +179 -0
  86. data/spec/formats/icao_spec.rb +61 -0
  87. data/spec/formats/postalcode_spec.rb +59 -0
  88. data/spec/formats/short_zipcode_spec.rb +53 -0
  89. data/spec/formats/weather_id_spec.rb +191 -0
  90. data/spec/formats/zipcode_spec.rb +111 -0
  91. data/spec/query_spec.rb +261 -288
  92. data/spec/spec_helper.rb +128 -4
  93. data/spec/{service_google_spec.rb → weather_services/google_spec.rb} +46 -46
  94. data/spec/weather_services/services_spec.rb +1118 -0
  95. data/spec/weather_services/weather_dot_com_spec.rb +327 -0
  96. data/spec/weather_services/wunderground_spec.rb +332 -0
  97. data/spec/{service_yahoo_spec.rb → weather_services/yahoo_spec.rb} +65 -81
  98. data/spec/weather_spec.rb +73 -61
  99. data/spec/web_services/geocode_spec.rb +45 -0
  100. data/spec/web_services/web_services_spec.rb +26 -0
  101. metadata +88 -36
  102. data/lib/barometer/services/noaa.rb +0 -6
  103. data/lib/barometer/services/weather_bug.rb +0 -6
  104. data/lib/barometer/services/weather_dot_com.rb +0 -6
  105. data/spec/data_geo_spec.rb +0 -94
  106. data/spec/data_sun_spec.rb +0 -76
  107. data/spec/service_wunderground_spec.rb +0 -330
  108. data/spec/services_spec.rb +0 -1106
@@ -0,0 +1,6 @@
1
+ module Barometer
2
+
3
+ class WeatherService::WeatherBug < WeatherService
4
+ end
5
+
6
+ end
@@ -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
- class Wunderground < Service
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?(Barometer::Measurement)
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.preferred)
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.preferred)
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
- # add sun data to current
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
- days_in_future = forecast.date - start_date
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
- #current.time = Time.parse(current_result['observation_time_rfc822']) unless
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 = Barometer::Zone.new(
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?(Barometer::Zone)
222
-
219
+ raise ArgumentError unless timezone.is_a?(Data::Zone)
223
220
  sun = nil
224
221
  if data
225
- time = nil
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 = Time.local(
242
- time.year, time.month, time.day,
243
- data['moon_phase']['sunrise']['hour'],
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 = Time.local(
249
- time.year, time.month, time.day,
250
- data['moon_phase']['sunset']['hour'],
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
- timezone.tz.local_to_utc(rise),
257
- timezone.tz.local_to_utc(set)
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
- Barometer::Wunderground.get(
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
- Barometer::Wunderground.get(
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,