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,285 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Barometer
         
     | 
| 
      
 2 
     | 
    
         
            +
              #
         
     | 
| 
      
 3 
     | 
    
         
            +
              # = Weather Underground
         
     | 
| 
      
 4 
     | 
    
         
            +
              # www.wunderground.com
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              # - key required: NO
         
     | 
| 
      
 7 
     | 
    
         
            +
              # - registration required: NO
         
     | 
| 
      
 8 
     | 
    
         
            +
              # - supported countries: ALL
         
     | 
| 
      
 9 
     | 
    
         
            +
              #
         
     | 
| 
      
 10 
     | 
    
         
            +
              # === performs geo coding
         
     | 
| 
      
 11 
     | 
    
         
            +
              # - city: YES
         
     | 
| 
      
 12 
     | 
    
         
            +
              # - coordinates: YES
         
     | 
| 
      
 13 
     | 
    
         
            +
              # NOTE: provides geo data for location and weather station
         
     | 
| 
      
 14 
     | 
    
         
            +
              #
         
     | 
| 
      
 15 
     | 
    
         
            +
              # === time info
         
     | 
| 
      
 16 
     | 
    
         
            +
              # - sun rise/set: YES (today only)
         
     | 
| 
      
 17 
     | 
    
         
            +
              # - provides timezone: YES
         
     | 
| 
      
 18 
     | 
    
         
            +
              # - requires TZInfo: YES
         
     | 
| 
      
 19 
     | 
    
         
            +
              #
         
     | 
| 
      
 20 
     | 
    
         
            +
              # == resources
         
     | 
| 
      
 21 
     | 
    
         
            +
              # - API: http://wiki.wunderground.com/index.php/API_-_XML
         
     | 
| 
      
 22 
     | 
    
         
            +
              #
         
     | 
| 
      
 23 
     | 
    
         
            +
              # === Possible queries:
         
     | 
| 
      
 24 
     | 
    
         
            +
              # - http://api.wunderground.com/auto/wui/geo/GeoLookupXML/index.xml?query=94107
         
     | 
| 
      
 25 
     | 
    
         
            +
              # - http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml?query=KSFO
         
     | 
| 
      
 26 
     | 
    
         
            +
              # - http://api.wunderground.com/weatherstation/WXCurrentObXML.asp?ID=KCASANFR70
         
     | 
| 
      
 27 
     | 
    
         
            +
              # - http://api.wunderground.com/auto/wui/geo/AlertsXML/index.xml?query=86445
         
     | 
| 
      
 28 
     | 
    
         
            +
              # - http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml?query=Chicago,IL
         
     | 
| 
      
 29 
     | 
    
         
            +
              #
         
     | 
| 
      
 30 
     | 
    
         
            +
              # where query can be:
         
     | 
| 
      
 31 
     | 
    
         
            +
              # - zipcode (US or Canadian)
         
     | 
| 
      
 32 
     | 
    
         
            +
              # - city state; city, state
         
     | 
| 
      
 33 
     | 
    
         
            +
              # - city
         
     | 
| 
      
 34 
     | 
    
         
            +
              # - state
         
     | 
| 
      
 35 
     | 
    
         
            +
              # - country
         
     | 
| 
      
 36 
     | 
    
         
            +
              # - airport code (3-letter or 4-letter)
         
     | 
| 
      
 37 
     | 
    
         
            +
              # - lat,lon
         
     | 
| 
      
 38 
     | 
    
         
            +
              #
         
     | 
| 
      
 39 
     | 
    
         
            +
              class Wunderground < Service
         
     | 
| 
      
 40 
     | 
    
         
            +
                
         
     | 
| 
      
 41 
     | 
    
         
            +
                def self.accepted_formats
         
     | 
| 
      
 42 
     | 
    
         
            +
                  [:zipcode, :postalcode, :coordinates, :geocode]
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
                
         
     | 
| 
      
 45 
     | 
    
         
            +
                def self.source_name
         
     | 
| 
      
 46 
     | 
    
         
            +
                  :wunderground
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
                
         
     | 
| 
      
 49 
     | 
    
         
            +
                # these are the icon codes that indicate "wet", used by wet? function
         
     | 
| 
      
 50 
     | 
    
         
            +
                def self.wet_icon_codes
         
     | 
| 
      
 51 
     | 
    
         
            +
                  %w(flurries rain sleet snow tstorms nt_flurries nt_rain nt_sleet nt_snow nt_tstorms)
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
                def self.sunny_icon_codes
         
     | 
| 
      
 54 
     | 
    
         
            +
                  %w(clear mostlysunny partlysunny sunny partlycloudy)
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                def self._measure(measurement, query, metric=true)
         
     | 
| 
      
 58 
     | 
    
         
            +
                  raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
         
     | 
| 
      
 59 
     | 
    
         
            +
                  raise ArgumentError unless query.is_a?(Barometer::Query)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  measurement.source = self.source_name
         
     | 
| 
      
 61 
     | 
    
         
            +
                  
         
     | 
| 
      
 62 
     | 
    
         
            +
                  # get current measurement
         
     | 
| 
      
 63 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 64 
     | 
    
         
            +
                    current_result = self.get_current(query.preferred)
         
     | 
| 
      
 65 
     | 
    
         
            +
                    measurement.current = self.build_current(current_result, metric)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  rescue Timeout::Error => e
         
     | 
| 
      
 67 
     | 
    
         
            +
                    return measurement
         
     | 
| 
      
 68 
     | 
    
         
            +
                  end
         
     | 
| 
      
 69 
     | 
    
         
            +
                  
         
     | 
| 
      
 70 
     | 
    
         
            +
                  # get forecast measurement
         
     | 
| 
      
 71 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 72 
     | 
    
         
            +
                    forecast_result = self.get_forecast(query.preferred)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    measurement.forecast = self.build_forecast(forecast_result, metric)
         
     | 
| 
      
 74 
     | 
    
         
            +
                  rescue Timeout::Error => e
         
     | 
| 
      
 75 
     | 
    
         
            +
                    return measurement
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                  
         
     | 
| 
      
 78 
     | 
    
         
            +
                  measurement.location = self.build_location(current_result)
         
     | 
| 
      
 79 
     | 
    
         
            +
                  measurement.station = self.build_station(current_result)
         
     | 
| 
      
 80 
     | 
    
         
            +
                  measurement.timezone = self.build_timezone(forecast_result)
         
     | 
| 
      
 81 
     | 
    
         
            +
                  
         
     | 
| 
      
 82 
     | 
    
         
            +
                  # add sun data to current
         
     | 
| 
      
 83 
     | 
    
         
            +
                  sun = nil
         
     | 
| 
      
 84 
     | 
    
         
            +
                  if measurement.current
         
     | 
| 
      
 85 
     | 
    
         
            +
                     sun = self.build_sun(forecast_result, measurement.timezone)
         
     | 
| 
      
 86 
     | 
    
         
            +
                     measurement.current.sun = sun
         
     | 
| 
      
 87 
     | 
    
         
            +
                  end
         
     | 
| 
      
 88 
     | 
    
         
            +
                  # use todays sun data for all future days
         
     | 
| 
      
 89 
     | 
    
         
            +
                  if measurement.forecast && sun
         
     | 
| 
      
 90 
     | 
    
         
            +
                    start_date = Date.parse(measurement.current.time)
         
     | 
| 
      
 91 
     | 
    
         
            +
                    measurement.forecast.each do |forecast|
         
     | 
| 
      
 92 
     | 
    
         
            +
                      days_in_future = forecast.date - start_date
         
     | 
| 
      
 93 
     | 
    
         
            +
                      forecast.sun = Barometer::Sun.add_days!(sun,days_in_future.to_i)
         
     | 
| 
      
 94 
     | 
    
         
            +
                    end
         
     | 
| 
      
 95 
     | 
    
         
            +
                  end
         
     | 
| 
      
 96 
     | 
    
         
            +
                  
         
     | 
| 
      
 97 
     | 
    
         
            +
                  measurement
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                def self.build_current(data, metric=true)
         
     | 
| 
      
 101 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  
         
     | 
| 
      
 103 
     | 
    
         
            +
                  current = CurrentMeasurement.new
         
     | 
| 
      
 104 
     | 
    
         
            +
                  #current.time = Time.parse(current_result['observation_time_rfc822']) unless
         
     | 
| 
      
 105 
     | 
    
         
            +
                  #  current_result['observation_time_rfc822'].blank?
         
     | 
| 
      
 106 
     | 
    
         
            +
                  current.time = data['observation_time_rfc822']
         
     | 
| 
      
 107 
     | 
    
         
            +
                  current.local_time = data['observation_time']
         
     | 
| 
      
 108 
     | 
    
         
            +
                  current.humidity = data['relative_humidity'].to_i
         
     | 
| 
      
 109 
     | 
    
         
            +
                  current.icon = data['icon'] if data['icon']
         
     | 
| 
      
 110 
     | 
    
         
            +
                  
         
     | 
| 
      
 111 
     | 
    
         
            +
                  current.temperature = Temperature.new(metric)
         
     | 
| 
      
 112 
     | 
    
         
            +
                  current.temperature << [data['temp_c'], data['temp_f']]
         
     | 
| 
      
 113 
     | 
    
         
            +
                  
         
     | 
| 
      
 114 
     | 
    
         
            +
                  current.wind = Speed.new(metric)
         
     | 
| 
      
 115 
     | 
    
         
            +
                  current.wind.mph = data['wind_mph'].to_f
         
     | 
| 
      
 116 
     | 
    
         
            +
                  current.wind.degrees = data['wind_degrees'].to_i
         
     | 
| 
      
 117 
     | 
    
         
            +
                  current.wind.direction = data['wind_dir']
         
     | 
| 
      
 118 
     | 
    
         
            +
                  
         
     | 
| 
      
 119 
     | 
    
         
            +
                  current.pressure = Pressure.new(metric)
         
     | 
| 
      
 120 
     | 
    
         
            +
                  current.pressure << [data['pressure_mb'], data['pressure_in']]
         
     | 
| 
      
 121 
     | 
    
         
            +
                  
         
     | 
| 
      
 122 
     | 
    
         
            +
                  current.dew_point = Temperature.new(metric)
         
     | 
| 
      
 123 
     | 
    
         
            +
                  current.dew_point << [data['dewpoint_c'], data['dewpoint_f']]
         
     | 
| 
      
 124 
     | 
    
         
            +
                  
         
     | 
| 
      
 125 
     | 
    
         
            +
                  current.heat_index = Temperature.new(metric)
         
     | 
| 
      
 126 
     | 
    
         
            +
                  current.heat_index << [data['heat_index_c'], data['heat_index_f']]
         
     | 
| 
      
 127 
     | 
    
         
            +
                  
         
     | 
| 
      
 128 
     | 
    
         
            +
                  current.wind_chill = Temperature.new(metric)
         
     | 
| 
      
 129 
     | 
    
         
            +
                  current.wind_chill << [data['windchill_c'], data['windchill_f']]
         
     | 
| 
      
 130 
     | 
    
         
            +
                  
         
     | 
| 
      
 131 
     | 
    
         
            +
                  current.visibility = Distance.new(metric)
         
     | 
| 
      
 132 
     | 
    
         
            +
                  current.visibility << [data['visibility_km'], data['visibility_mi']]
         
     | 
| 
      
 133 
     | 
    
         
            +
                  
         
     | 
| 
      
 134 
     | 
    
         
            +
                  current
         
     | 
| 
      
 135 
     | 
    
         
            +
                end
         
     | 
| 
      
 136 
     | 
    
         
            +
                
         
     | 
| 
      
 137 
     | 
    
         
            +
                def self.build_forecast(data, metric=true)
         
     | 
| 
      
 138 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 139 
     | 
    
         
            +
                  forecasts = []
         
     | 
| 
      
 140 
     | 
    
         
            +
                  # go through each forecast and create an instance
         
     | 
| 
      
 141 
     | 
    
         
            +
                  if data && data['simpleforecast'] &&
         
     | 
| 
      
 142 
     | 
    
         
            +
                     data['simpleforecast']['forecastday']
         
     | 
| 
      
 143 
     | 
    
         
            +
                     
         
     | 
| 
      
 144 
     | 
    
         
            +
                    data['simpleforecast']['forecastday'].each do |forecast|
         
     | 
| 
      
 145 
     | 
    
         
            +
                      forecast_measurement = ForecastMeasurement.new
         
     | 
| 
      
 146 
     | 
    
         
            +
                      forecast_measurement.icon = forecast['icon']
         
     | 
| 
      
 147 
     | 
    
         
            +
                      forecast_measurement.date = Date.parse(forecast['date']['pretty'])
         
     | 
| 
      
 148 
     | 
    
         
            +
                      forecast_measurement.pop = forecast['pop'].to_i
         
     | 
| 
      
 149 
     | 
    
         
            +
                      
         
     | 
| 
      
 150 
     | 
    
         
            +
                      forecast_measurement.high = Temperature.new(metric)
         
     | 
| 
      
 151 
     | 
    
         
            +
                      forecast_measurement.high << [forecast['high']['celsius'],forecast['high']['fahrenheit']]
         
     | 
| 
      
 152 
     | 
    
         
            +
                      
         
     | 
| 
      
 153 
     | 
    
         
            +
                      forecast_measurement.low = Temperature.new(metric)
         
     | 
| 
      
 154 
     | 
    
         
            +
                      forecast_measurement.low << [forecast['low']['celsius'],forecast['low']['fahrenheit']]
         
     | 
| 
      
 155 
     | 
    
         
            +
                      
         
     | 
| 
      
 156 
     | 
    
         
            +
                      forecasts << forecast_measurement
         
     | 
| 
      
 157 
     | 
    
         
            +
                    end
         
     | 
| 
      
 158 
     | 
    
         
            +
                  end
         
     | 
| 
      
 159 
     | 
    
         
            +
                  forecasts
         
     | 
| 
      
 160 
     | 
    
         
            +
                end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                def self.build_location(data)
         
     | 
| 
      
 163 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 164 
     | 
    
         
            +
                  location = Location.new
         
     | 
| 
      
 165 
     | 
    
         
            +
                  if data['display_location']
         
     | 
| 
      
 166 
     | 
    
         
            +
                    location.name = data['display_location']['full']
         
     | 
| 
      
 167 
     | 
    
         
            +
                    location.city = data['display_location']['city']
         
     | 
| 
      
 168 
     | 
    
         
            +
                    location.state_name = data['display_location']['state_name']
         
     | 
| 
      
 169 
     | 
    
         
            +
                    location.state_code = data['display_location']['state']
         
     | 
| 
      
 170 
     | 
    
         
            +
                    location.country_code = data['display_location']['country']
         
     | 
| 
      
 171 
     | 
    
         
            +
                    location.zip_code = data['display_location']['zip']
         
     | 
| 
      
 172 
     | 
    
         
            +
                    location.latitude = data['display_location']['latitude']
         
     | 
| 
      
 173 
     | 
    
         
            +
                    location.longitude = data['display_location']['longitude']
         
     | 
| 
      
 174 
     | 
    
         
            +
                  end
         
     | 
| 
      
 175 
     | 
    
         
            +
                  location
         
     | 
| 
      
 176 
     | 
    
         
            +
                end
         
     | 
| 
      
 177 
     | 
    
         
            +
                
         
     | 
| 
      
 178 
     | 
    
         
            +
                def self.build_station(data)
         
     | 
| 
      
 179 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 180 
     | 
    
         
            +
                  station = Location.new
         
     | 
| 
      
 181 
     | 
    
         
            +
                  station.id = data['station_id']
         
     | 
| 
      
 182 
     | 
    
         
            +
                  if data['observation_location']
         
     | 
| 
      
 183 
     | 
    
         
            +
                    station.name = data['observation_location']['full']
         
     | 
| 
      
 184 
     | 
    
         
            +
                    station.city = data['observation_location']['city']
         
     | 
| 
      
 185 
     | 
    
         
            +
                    station.state_name = data['observation_location']['state_name']
         
     | 
| 
      
 186 
     | 
    
         
            +
                    station.state_code = data['observation_location']['state']
         
     | 
| 
      
 187 
     | 
    
         
            +
                    station.country_code = data['observation_location']['country']
         
     | 
| 
      
 188 
     | 
    
         
            +
                    station.zip_code = data['observation_location']['zip']
         
     | 
| 
      
 189 
     | 
    
         
            +
                    station.latitude = data['observation_location']['latitude']
         
     | 
| 
      
 190 
     | 
    
         
            +
                    station.longitude = data['observation_location']['longitude']
         
     | 
| 
      
 191 
     | 
    
         
            +
                  end
         
     | 
| 
      
 192 
     | 
    
         
            +
                  station
         
     | 
| 
      
 193 
     | 
    
         
            +
                end
         
     | 
| 
      
 194 
     | 
    
         
            +
                
         
     | 
| 
      
 195 
     | 
    
         
            +
                # <forecastday>
         
     | 
| 
      
 196 
     | 
    
         
            +
                #       <date>
         
     | 
| 
      
 197 
     | 
    
         
            +
                #         <pretty_short>9:00 PM CST</pretty_short>
         
     | 
| 
      
 198 
     | 
    
         
            +
                #         <pretty>9:00 PM CST on January 15, 2008</pretty>
         
     | 
| 
      
 199 
     | 
    
         
            +
                #         <isdst>0</isdst>
         
     | 
| 
      
 200 
     | 
    
         
            +
                #         <tz_short>CST</tz_short>
         
     | 
| 
      
 201 
     | 
    
         
            +
                #         <tz_long>America/Chicago</tz_long>
         
     | 
| 
      
 202 
     | 
    
         
            +
                #       </date>
         
     | 
| 
      
 203 
     | 
    
         
            +
                #     </forecastday>
         
     | 
| 
      
 204 
     | 
    
         
            +
                def self.build_timezone(data)
         
     | 
| 
      
 205 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 206 
     | 
    
         
            +
                  timezone = nil
         
     | 
| 
      
 207 
     | 
    
         
            +
                  if data && data['simpleforecast'] &&
         
     | 
| 
      
 208 
     | 
    
         
            +
                     data['simpleforecast']['forecastday'] &&
         
     | 
| 
      
 209 
     | 
    
         
            +
                     data['simpleforecast']['forecastday'].first &&
         
     | 
| 
      
 210 
     | 
    
         
            +
                     data['simpleforecast']['forecastday'].first['date']
         
     | 
| 
      
 211 
     | 
    
         
            +
                    timezone = Barometer::Zone.new(
         
     | 
| 
      
 212 
     | 
    
         
            +
                      data['simpleforecast']['forecastday'].first['date']['tz_long']
         
     | 
| 
      
 213 
     | 
    
         
            +
                    )
         
     | 
| 
      
 214 
     | 
    
         
            +
                  end
         
     | 
| 
      
 215 
     | 
    
         
            +
                  timezone
         
     | 
| 
      
 216 
     | 
    
         
            +
                end
         
     | 
| 
      
 217 
     | 
    
         
            +
                
         
     | 
| 
      
 218 
     | 
    
         
            +
                def self.build_sun(data, timezone)
         
     | 
| 
      
 219 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 220 
     | 
    
         
            +
                  raise ArgumentError unless timezone.is_a?(Barometer::Zone)
         
     | 
| 
      
 221 
     | 
    
         
            +
                  
         
     | 
| 
      
 222 
     | 
    
         
            +
                  sun = nil
         
     | 
| 
      
 223 
     | 
    
         
            +
                  if data
         
     | 
| 
      
 224 
     | 
    
         
            +
                    time = nil
         
     | 
| 
      
 225 
     | 
    
         
            +
                    if data['simpleforecast'] &&
         
     | 
| 
      
 226 
     | 
    
         
            +
                       data['simpleforecast']['forecastday'] &&
         
     | 
| 
      
 227 
     | 
    
         
            +
                       data['simpleforecast']['forecastday'].first &&
         
     | 
| 
      
 228 
     | 
    
         
            +
                       data['simpleforecast']['forecastday'].first['date']
         
     | 
| 
      
 229 
     | 
    
         
            +
                      
         
     | 
| 
      
 230 
     | 
    
         
            +
                      # construct current date
         
     | 
| 
      
 231 
     | 
    
         
            +
                      date_data = data['simpleforecast']['forecastday'].first['date']
         
     | 
| 
      
 232 
     | 
    
         
            +
                      time = Time.local(
         
     | 
| 
      
 233 
     | 
    
         
            +
                        date_data['year'], date_data['month'], date_data['day'],
         
     | 
| 
      
 234 
     | 
    
         
            +
                        date_data['hour'], date_data['min'], date_data['sec']
         
     | 
| 
      
 235 
     | 
    
         
            +
                      )
         
     | 
| 
      
 236 
     | 
    
         
            +
                    end
         
     | 
| 
      
 237 
     | 
    
         
            +
                    if time && data['moon_phase']
         
     | 
| 
      
 238 
     | 
    
         
            +
                      # get the sun rise and set times (ie "6:32 am")
         
     | 
| 
      
 239 
     | 
    
         
            +
                      if data['moon_phase']['sunrise']
         
     | 
| 
      
 240 
     | 
    
         
            +
                        rise = Time.local(
         
     | 
| 
      
 241 
     | 
    
         
            +
                          time.year, time.month, time.day,
         
     | 
| 
      
 242 
     | 
    
         
            +
                          data['moon_phase']['sunrise']['hour'],
         
     | 
| 
      
 243 
     | 
    
         
            +
                          data['moon_phase']['sunrise']['minute']
         
     | 
| 
      
 244 
     | 
    
         
            +
                        )
         
     | 
| 
      
 245 
     | 
    
         
            +
                      end
         
     | 
| 
      
 246 
     | 
    
         
            +
                      if data['moon_phase']['sunset']
         
     | 
| 
      
 247 
     | 
    
         
            +
                        set = Time.local(
         
     | 
| 
      
 248 
     | 
    
         
            +
                          time.year, time.month, time.day,
         
     | 
| 
      
 249 
     | 
    
         
            +
                          data['moon_phase']['sunset']['hour'],
         
     | 
| 
      
 250 
     | 
    
         
            +
                          data['moon_phase']['sunset']['minute']
         
     | 
| 
      
 251 
     | 
    
         
            +
                        )
         
     | 
| 
      
 252 
     | 
    
         
            +
                      end
         
     | 
| 
      
 253 
     | 
    
         
            +
                    
         
     | 
| 
      
 254 
     | 
    
         
            +
                      sun = Sun.new(
         
     | 
| 
      
 255 
     | 
    
         
            +
                        timezone.tz.local_to_utc(rise),
         
     | 
| 
      
 256 
     | 
    
         
            +
                        timezone.tz.local_to_utc(set)
         
     | 
| 
      
 257 
     | 
    
         
            +
                      )
         
     | 
| 
      
 258 
     | 
    
         
            +
                    end
         
     | 
| 
      
 259 
     | 
    
         
            +
                  end
         
     | 
| 
      
 260 
     | 
    
         
            +
                  
         
     | 
| 
      
 261 
     | 
    
         
            +
                  sun || Sun.new
         
     | 
| 
      
 262 
     | 
    
         
            +
                end
         
     | 
| 
      
 263 
     | 
    
         
            +
                
         
     | 
| 
      
 264 
     | 
    
         
            +
                # use HTTParty to get the current weather
         
     | 
| 
      
 265 
     | 
    
         
            +
                def self.get_current(query)
         
     | 
| 
      
 266 
     | 
    
         
            +
                  Barometer::Wunderground.get(
         
     | 
| 
      
 267 
     | 
    
         
            +
                   "http://api.wunderground.com/auto/wui/geo/WXCurrentObXML/index.xml",
         
     | 
| 
      
 268 
     | 
    
         
            +
                   :query => {:query => query},
         
     | 
| 
      
 269 
     | 
    
         
            +
                   :format => :xml,
         
     | 
| 
      
 270 
     | 
    
         
            +
                   :timeout => Barometer.timeout
         
     | 
| 
      
 271 
     | 
    
         
            +
                   )['current_observation']
         
     | 
| 
      
 272 
     | 
    
         
            +
                end
         
     | 
| 
      
 273 
     | 
    
         
            +
                
         
     | 
| 
      
 274 
     | 
    
         
            +
                # use HTTParty to get the forecasted weather
         
     | 
| 
      
 275 
     | 
    
         
            +
                def self.get_forecast(query)
         
     | 
| 
      
 276 
     | 
    
         
            +
                  Barometer::Wunderground.get(
         
     | 
| 
      
 277 
     | 
    
         
            +
                    "http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml",
         
     | 
| 
      
 278 
     | 
    
         
            +
                    :query => {:query => query},
         
     | 
| 
      
 279 
     | 
    
         
            +
                    :format => :xml,
         
     | 
| 
      
 280 
     | 
    
         
            +
                    :timeout => Barometer.timeout
         
     | 
| 
      
 281 
     | 
    
         
            +
                  )['forecast']
         
     | 
| 
      
 282 
     | 
    
         
            +
                end
         
     | 
| 
      
 283 
     | 
    
         
            +
                
         
     | 
| 
      
 284 
     | 
    
         
            +
              end
         
     | 
| 
      
 285 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,274 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Barometer
         
     | 
| 
      
 2 
     | 
    
         
            +
              #
         
     | 
| 
      
 3 
     | 
    
         
            +
              # = Yahoo Weather
         
     | 
| 
      
 4 
     | 
    
         
            +
              # www.yahoo.com
         
     | 
| 
      
 5 
     | 
    
         
            +
              #
         
     | 
| 
      
 6 
     | 
    
         
            +
              # - key required: NO
         
     | 
| 
      
 7 
     | 
    
         
            +
              # - registration required: NO
         
     | 
| 
      
 8 
     | 
    
         
            +
              # - supported countries: US (by zipcode), International (by Yahoo Location ID)
         
     | 
| 
      
 9 
     | 
    
         
            +
              #
         
     | 
| 
      
 10 
     | 
    
         
            +
              # === performs geo coding
         
     | 
| 
      
 11 
     | 
    
         
            +
              # - city: YES
         
     | 
| 
      
 12 
     | 
    
         
            +
              # - coordinates: YES
         
     | 
| 
      
 13 
     | 
    
         
            +
              #
         
     | 
| 
      
 14 
     | 
    
         
            +
              # === time info
         
     | 
| 
      
 15 
     | 
    
         
            +
              # - sun rise/set: YES (today only)
         
     | 
| 
      
 16 
     | 
    
         
            +
              # - provides timezone: PARTIAL (just short code)
         
     | 
| 
      
 17 
     | 
    
         
            +
              # - requires TZInfo: NO
         
     | 
| 
      
 18 
     | 
    
         
            +
              # NOTE: since this only supports US, the short code can be used
         
     | 
| 
      
 19 
     | 
    
         
            +
              #       to convert times (until yahoo location id support is added)
         
     | 
| 
      
 20 
     | 
    
         
            +
              #
         
     | 
| 
      
 21 
     | 
    
         
            +
              # == resources
         
     | 
| 
      
 22 
     | 
    
         
            +
              # - API: http://developer.yahoo.com/weather/
         
     | 
| 
      
 23 
     | 
    
         
            +
              #
         
     | 
| 
      
 24 
     | 
    
         
            +
              # === Possible queries:
         
     | 
| 
      
 25 
     | 
    
         
            +
              # - http://weather.yahooapis.com/forecastrss?p=94089
         
     | 
| 
      
 26 
     | 
    
         
            +
              # - http://weather.yahooapis.com/forecastrss?p=USCA1116
         
     | 
| 
      
 27 
     | 
    
         
            +
              # - http://weather.yahooapis.com/forecastrss?p=FRXX0076&u=c
         
     | 
| 
      
 28 
     | 
    
         
            +
              #
         
     | 
| 
      
 29 
     | 
    
         
            +
              # where query can be:
         
     | 
| 
      
 30 
     | 
    
         
            +
              # - zipcode (US)
         
     | 
| 
      
 31 
     | 
    
         
            +
              # - Yahoo Location ID (International) - not currently supported
         
     | 
| 
      
 32 
     | 
    
         
            +
              #
         
     | 
| 
      
 33 
     | 
    
         
            +
              # == notes
         
     | 
| 
      
 34 
     | 
    
         
            +
              # - the Yahoo Location ID is a propreitary number (possibly shared with weather.com)
         
     | 
| 
      
 35 
     | 
    
         
            +
              #   so this driver currently does not provide a way to get/use this number,
         
     | 
| 
      
 36 
     | 
    
         
            +
              #   therefore International support is currently missing
         
     | 
| 
      
 37 
     | 
    
         
            +
              #
         
     | 
| 
      
 38 
     | 
    
         
            +
              class Yahoo < Service
         
     | 
| 
      
 39 
     | 
    
         
            +
                
         
     | 
| 
      
 40 
     | 
    
         
            +
                def self.accepted_formats
         
     | 
| 
      
 41 
     | 
    
         
            +
                  [:zipcode]
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
                
         
     | 
| 
      
 44 
     | 
    
         
            +
                def self.source_name
         
     | 
| 
      
 45 
     | 
    
         
            +
                  :yahoo
         
     | 
| 
      
 46 
     | 
    
         
            +
                end
         
     | 
| 
      
 47 
     | 
    
         
            +
                
         
     | 
| 
      
 48 
     | 
    
         
            +
                # these are the icon codes that indicate "wet", used by wet? function
         
     | 
| 
      
 49 
     | 
    
         
            +
                def self.wet_icon_codes
         
     | 
| 
      
 50 
     | 
    
         
            +
                  codes = [1] + (3..18).to_a + [35] + (37..43).to_a + (45..47).to_a
         
     | 
| 
      
 51 
     | 
    
         
            +
                  codes.collect {|c| c.to_s}
         
     | 
| 
      
 52 
     | 
    
         
            +
                end
         
     | 
| 
      
 53 
     | 
    
         
            +
                def self.sunny_icon_codes
         
     | 
| 
      
 54 
     | 
    
         
            +
                  codes = (29..34).to_a + [36]
         
     | 
| 
      
 55 
     | 
    
         
            +
                  codes.collect {|c| c.to_s}
         
     | 
| 
      
 56 
     | 
    
         
            +
                end
         
     | 
| 
      
 57 
     | 
    
         
            +
                
         
     | 
| 
      
 58 
     | 
    
         
            +
                # override, only currently supports US
         
     | 
| 
      
 59 
     | 
    
         
            +
                def self.supports_country?(query=nil)
         
     | 
| 
      
 60 
     | 
    
         
            +
                  query && query.country_code && query.country_code.downcase == "us"
         
     | 
| 
      
 61 
     | 
    
         
            +
                end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                def self._measure(measurement, query, metric=true)
         
     | 
| 
      
 64 
     | 
    
         
            +
                  raise ArgumentError unless measurement.is_a?(Barometer::Measurement)
         
     | 
| 
      
 65 
     | 
    
         
            +
                  raise ArgumentError unless query.is_a?(Barometer::Query)
         
     | 
| 
      
 66 
     | 
    
         
            +
                  measurement.source = self.source_name
         
     | 
| 
      
 67 
     | 
    
         
            +
                  
         
     | 
| 
      
 68 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 69 
     | 
    
         
            +
                    result = self.get_all(query.preferred, metric)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  rescue Timeout::Error => e
         
     | 
| 
      
 71 
     | 
    
         
            +
                    return measurement
         
     | 
| 
      
 72 
     | 
    
         
            +
                  end
         
     | 
| 
      
 73 
     | 
    
         
            +
                  
         
     | 
| 
      
 74 
     | 
    
         
            +
                  measurement.current = self.build_current(result, metric)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  measurement.forecast = self.build_forecast(result, metric)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  measurement.location = self.build_location(result, query.geo)
         
     | 
| 
      
 77 
     | 
    
         
            +
                  
         
     | 
| 
      
 78 
     | 
    
         
            +
                  # add to current
         
     | 
| 
      
 79 
     | 
    
         
            +
                  sun = nil
         
     | 
| 
      
 80 
     | 
    
         
            +
                  if measurement.current
         
     | 
| 
      
 81 
     | 
    
         
            +
                    sun = self.build_sun(result)
         
     | 
| 
      
 82 
     | 
    
         
            +
                    measurement.current.sun = sun
         
     | 
| 
      
 83 
     | 
    
         
            +
                  end
         
     | 
| 
      
 84 
     | 
    
         
            +
                  # use todays sun data for all future days
         
     | 
| 
      
 85 
     | 
    
         
            +
                  if measurement.forecast && sun
         
     | 
| 
      
 86 
     | 
    
         
            +
                    start_date = Date.parse(measurement.current.local_time)
         
     | 
| 
      
 87 
     | 
    
         
            +
                    measurement.forecast.each do |forecast|
         
     | 
| 
      
 88 
     | 
    
         
            +
                      days_in_future = forecast.date - start_date
         
     | 
| 
      
 89 
     | 
    
         
            +
                      forecast.sun = Barometer::Sun.add_days!(sun,days_in_future.to_i)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
                  end
         
     | 
| 
      
 92 
     | 
    
         
            +
                  
         
     | 
| 
      
 93 
     | 
    
         
            +
                  measurement
         
     | 
| 
      
 94 
     | 
    
         
            +
                end
         
     | 
| 
      
 95 
     | 
    
         
            +
                
         
     | 
| 
      
 96 
     | 
    
         
            +
                def self.build_current(data, metric=true)
         
     | 
| 
      
 97 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 98 
     | 
    
         
            +
                  current = CurrentMeasurement.new
         
     | 
| 
      
 99 
     | 
    
         
            +
                  if data
         
     | 
| 
      
 100 
     | 
    
         
            +
                    if data['item'] && data['item']['yweather:condition']
         
     | 
| 
      
 101 
     | 
    
         
            +
                      condition_result = data['item']['yweather:condition']
         
     | 
| 
      
 102 
     | 
    
         
            +
                      current.local_time = condition_result['date']
         
     | 
| 
      
 103 
     | 
    
         
            +
                      current.icon = condition_result['code']
         
     | 
| 
      
 104 
     | 
    
         
            +
                      current.condition = condition_result['text']
         
     | 
| 
      
 105 
     | 
    
         
            +
                      current.temperature = Temperature.new(metric)
         
     | 
| 
      
 106 
     | 
    
         
            +
                      current.temperature << condition_result['temp']
         
     | 
| 
      
 107 
     | 
    
         
            +
                    end
         
     | 
| 
      
 108 
     | 
    
         
            +
                    if data['yweather:atmosphere']
         
     | 
| 
      
 109 
     | 
    
         
            +
                      atmosphere_result = data['yweather:atmosphere']
         
     | 
| 
      
 110 
     | 
    
         
            +
                      current.humidity = atmosphere_result['humidity'].to_i
         
     | 
| 
      
 111 
     | 
    
         
            +
                      current.pressure = Pressure.new(metric)
         
     | 
| 
      
 112 
     | 
    
         
            +
                      current.pressure << atmosphere_result['pressure']
         
     | 
| 
      
 113 
     | 
    
         
            +
                      current.visibility = Distance.new(metric)
         
     | 
| 
      
 114 
     | 
    
         
            +
                      current.visibility << atmosphere_result['visibility']
         
     | 
| 
      
 115 
     | 
    
         
            +
                    end
         
     | 
| 
      
 116 
     | 
    
         
            +
                    if data['yweather:wind']
         
     | 
| 
      
 117 
     | 
    
         
            +
                      wind_result = data['yweather:wind']
         
     | 
| 
      
 118 
     | 
    
         
            +
                      current.wind = Speed.new(metric)
         
     | 
| 
      
 119 
     | 
    
         
            +
                      current.wind << wind_result['speed']
         
     | 
| 
      
 120 
     | 
    
         
            +
                      current.wind.degrees = wind_result['degrees'].to_f
         
     | 
| 
      
 121 
     | 
    
         
            +
                      current.wind_chill = Temperature.new(metric)
         
     | 
| 
      
 122 
     | 
    
         
            +
                      current.wind_chill << wind_result['chill']
         
     | 
| 
      
 123 
     | 
    
         
            +
                    end
         
     | 
| 
      
 124 
     | 
    
         
            +
                  end
         
     | 
| 
      
 125 
     | 
    
         
            +
                  current
         
     | 
| 
      
 126 
     | 
    
         
            +
                end
         
     | 
| 
      
 127 
     | 
    
         
            +
                
         
     | 
| 
      
 128 
     | 
    
         
            +
                def self.build_forecast(data, metric=true)
         
     | 
| 
      
 129 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 130 
     | 
    
         
            +
                  forecasts = []
         
     | 
| 
      
 131 
     | 
    
         
            +
                  
         
     | 
| 
      
 132 
     | 
    
         
            +
                  if data && data['item'] && data['item']['yweather:forecast']
         
     | 
| 
      
 133 
     | 
    
         
            +
                     forecast_result = data['item']['yweather:forecast']
         
     | 
| 
      
 134 
     | 
    
         
            +
                     
         
     | 
| 
      
 135 
     | 
    
         
            +
                    forecast_result.each do |forecast|
         
     | 
| 
      
 136 
     | 
    
         
            +
                      forecast_measurement = ForecastMeasurement.new
         
     | 
| 
      
 137 
     | 
    
         
            +
                      forecast_measurement.icon = forecast['code']
         
     | 
| 
      
 138 
     | 
    
         
            +
                      forecast_measurement.date = Date.parse(forecast['date'])
         
     | 
| 
      
 139 
     | 
    
         
            +
                      forecast_measurement.condition = forecast['text']
         
     | 
| 
      
 140 
     | 
    
         
            +
                      forecast_measurement.high = Temperature.new(metric)
         
     | 
| 
      
 141 
     | 
    
         
            +
                      forecast_measurement.high << forecast['high'].to_f
         
     | 
| 
      
 142 
     | 
    
         
            +
                      forecast_measurement.low = Temperature.new(metric)
         
     | 
| 
      
 143 
     | 
    
         
            +
                      forecast_measurement.low << forecast['low'].to_f
         
     | 
| 
      
 144 
     | 
    
         
            +
                      forecasts << forecast_measurement
         
     | 
| 
      
 145 
     | 
    
         
            +
                    end
         
     | 
| 
      
 146 
     | 
    
         
            +
                  end
         
     | 
| 
      
 147 
     | 
    
         
            +
                  forecasts
         
     | 
| 
      
 148 
     | 
    
         
            +
                end
         
     | 
| 
      
 149 
     | 
    
         
            +
                
         
     | 
| 
      
 150 
     | 
    
         
            +
                def self.build_location(data, geo=nil)
         
     | 
| 
      
 151 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 152 
     | 
    
         
            +
                  raise ArgumentError unless (geo.nil? || geo.is_a?(Barometer::Geo))
         
     | 
| 
      
 153 
     | 
    
         
            +
                  location = Location.new
         
     | 
| 
      
 154 
     | 
    
         
            +
                  # use the geocoded data if available, otherwise get data from result
         
     | 
| 
      
 155 
     | 
    
         
            +
                  if geo
         
     | 
| 
      
 156 
     | 
    
         
            +
                    location.city = geo.locality
         
     | 
| 
      
 157 
     | 
    
         
            +
                    location.state_code = geo.region
         
     | 
| 
      
 158 
     | 
    
         
            +
                    location.country = geo.country
         
     | 
| 
      
 159 
     | 
    
         
            +
                    location.country_code = geo.country_code
         
     | 
| 
      
 160 
     | 
    
         
            +
                    location.latitude = geo.latitude
         
     | 
| 
      
 161 
     | 
    
         
            +
                    location.longitude = geo.longitude
         
     | 
| 
      
 162 
     | 
    
         
            +
                  else
         
     | 
| 
      
 163 
     | 
    
         
            +
                    if data && data['yweather:location']
         
     | 
| 
      
 164 
     | 
    
         
            +
                      location.city = data['yweather:location']['city']
         
     | 
| 
      
 165 
     | 
    
         
            +
                      location.state_code = data['yweather:location']['region']
         
     | 
| 
      
 166 
     | 
    
         
            +
                      location.country_code = data['yweather:location']['country']
         
     | 
| 
      
 167 
     | 
    
         
            +
                      if data['item']
         
     | 
| 
      
 168 
     | 
    
         
            +
                        location.latitude = data['item']['geo:lat']
         
     | 
| 
      
 169 
     | 
    
         
            +
                        location.longitude = data['item']['geo:long']
         
     | 
| 
      
 170 
     | 
    
         
            +
                      end
         
     | 
| 
      
 171 
     | 
    
         
            +
                    end
         
     | 
| 
      
 172 
     | 
    
         
            +
                  end
         
     | 
| 
      
 173 
     | 
    
         
            +
                  location
         
     | 
| 
      
 174 
     | 
    
         
            +
                end
         
     | 
| 
      
 175 
     | 
    
         
            +
                
         
     | 
| 
      
 176 
     | 
    
         
            +
                def self.build_sun(data)
         
     | 
| 
      
 177 
     | 
    
         
            +
                  raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 178 
     | 
    
         
            +
                  sun = nil
         
     | 
| 
      
 179 
     | 
    
         
            +
                  if data && data['yweather:astronomy'] && data['item']
         
     | 
| 
      
 180 
     | 
    
         
            +
                    # get the TIME ZONE CODE
         
     | 
| 
      
 181 
     | 
    
         
            +
                    zone_match = data['item']['pubDate'].match(/ ([A-Z]*)$/)
         
     | 
| 
      
 182 
     | 
    
         
            +
                    zone = zone_match[1] if zone_match
         
     | 
| 
      
 183 
     | 
    
         
            +
                    # get the sun rise and set
         
     | 
| 
      
 184 
     | 
    
         
            +
                    rise = Barometer::Zone.merge(
         
     | 
| 
      
 185 
     | 
    
         
            +
                      data['yweather:astronomy']['sunrise'],
         
     | 
| 
      
 186 
     | 
    
         
            +
                      data['item']['pubDate'],
         
     | 
| 
      
 187 
     | 
    
         
            +
                      zone
         
     | 
| 
      
 188 
     | 
    
         
            +
                    )
         
     | 
| 
      
 189 
     | 
    
         
            +
                    set = Barometer::Zone.merge(
         
     | 
| 
      
 190 
     | 
    
         
            +
                      data['yweather:astronomy']['sunset'],
         
     | 
| 
      
 191 
     | 
    
         
            +
                      data['item']['pubDate'],
         
     | 
| 
      
 192 
     | 
    
         
            +
                      zone
         
     | 
| 
      
 193 
     | 
    
         
            +
                    )
         
     | 
| 
      
 194 
     | 
    
         
            +
                    sun = Sun.new(rise, set)
         
     | 
| 
      
 195 
     | 
    
         
            +
                  end
         
     | 
| 
      
 196 
     | 
    
         
            +
                  sun || Sun.new
         
     | 
| 
      
 197 
     | 
    
         
            +
                end
         
     | 
| 
      
 198 
     | 
    
         
            +
             
     | 
| 
      
 199 
     | 
    
         
            +
                # def self.build_timezone(data)
         
     | 
| 
      
 200 
     | 
    
         
            +
                #   raise ArgumentError unless data.is_a?(Hash)
         
     | 
| 
      
 201 
     | 
    
         
            +
                #   
         
     | 
| 
      
 202 
     | 
    
         
            +
                #   timezone = nil
         
     | 
| 
      
 203 
     | 
    
         
            +
                #   if data && data['simpleforecast'] &&
         
     | 
| 
      
 204 
     | 
    
         
            +
                #      data['simpleforecast']['forecastday'] &&
         
     | 
| 
      
 205 
     | 
    
         
            +
                #      data['simpleforecast']['forecastday'].first &&
         
     | 
| 
      
 206 
     | 
    
         
            +
                #      data['simpleforecast']['forecastday'].first['date']
         
     | 
| 
      
 207 
     | 
    
         
            +
                #     timezone = Barometer::Zone.new(Time.now.utc,data['simpleforecast']['forecastday'].first['date']['tz_long'])
         
     | 
| 
      
 208 
     | 
    
         
            +
                #   end
         
     | 
| 
      
 209 
     | 
    
         
            +
                #   timezone
         
     | 
| 
      
 210 
     | 
    
         
            +
                # end
         
     | 
| 
      
 211 
     | 
    
         
            +
                
         
     | 
| 
      
 212 
     | 
    
         
            +
                # use HTTParty to get the current weather
         
     | 
| 
      
 213 
     | 
    
         
            +
                def self.get_all(query, metric=true)
         
     | 
| 
      
 214 
     | 
    
         
            +
                  Barometer::Yahoo.get(
         
     | 
| 
      
 215 
     | 
    
         
            +
                    "http://weather.yahooapis.com/forecastrss",
         
     | 
| 
      
 216 
     | 
    
         
            +
                    :query => {:p => query, :u => (metric ? 'c' : 'f')},
         
     | 
| 
      
 217 
     | 
    
         
            +
                    :format => :xml,
         
     | 
| 
      
 218 
     | 
    
         
            +
                    :timeout => Barometer.timeout
         
     | 
| 
      
 219 
     | 
    
         
            +
                  )['rss']['channel']
         
     | 
| 
      
 220 
     | 
    
         
            +
                end
         
     | 
| 
      
 221 
     | 
    
         
            +
                
         
     | 
| 
      
 222 
     | 
    
         
            +
              end
         
     | 
| 
      
 223 
     | 
    
         
            +
            end
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
            # Condition Codes
         
     | 
| 
      
 226 
     | 
    
         
            +
            # 0   tornado
         
     | 
| 
      
 227 
     | 
    
         
            +
            # 1   tropical storm
         
     | 
| 
      
 228 
     | 
    
         
            +
            # 2   hurricane
         
     | 
| 
      
 229 
     | 
    
         
            +
            # 3   severe thunderstorms
         
     | 
| 
      
 230 
     | 
    
         
            +
            # 4   thunderstorms
         
     | 
| 
      
 231 
     | 
    
         
            +
            # 5   mixed rain and snow
         
     | 
| 
      
 232 
     | 
    
         
            +
            # 6   mixed rain and sleet
         
     | 
| 
      
 233 
     | 
    
         
            +
            # 7   mixed snow and sleet
         
     | 
| 
      
 234 
     | 
    
         
            +
            # 8   freezing drizzle
         
     | 
| 
      
 235 
     | 
    
         
            +
            # 9   drizzle
         
     | 
| 
      
 236 
     | 
    
         
            +
            # 10  freezing rain
         
     | 
| 
      
 237 
     | 
    
         
            +
            # 11  showers
         
     | 
| 
      
 238 
     | 
    
         
            +
            # 12  showers
         
     | 
| 
      
 239 
     | 
    
         
            +
            # 13  snow flurries
         
     | 
| 
      
 240 
     | 
    
         
            +
            # 14  light snow showers
         
     | 
| 
      
 241 
     | 
    
         
            +
            # 15  blowing snow
         
     | 
| 
      
 242 
     | 
    
         
            +
            # 16  snow
         
     | 
| 
      
 243 
     | 
    
         
            +
            # 17  hail
         
     | 
| 
      
 244 
     | 
    
         
            +
            # 18  sleet
         
     | 
| 
      
 245 
     | 
    
         
            +
            # 19  dust
         
     | 
| 
      
 246 
     | 
    
         
            +
            # 20  foggy
         
     | 
| 
      
 247 
     | 
    
         
            +
            # 21  haze
         
     | 
| 
      
 248 
     | 
    
         
            +
            # 22  smoky
         
     | 
| 
      
 249 
     | 
    
         
            +
            # 23  blustery
         
     | 
| 
      
 250 
     | 
    
         
            +
            # 24  windy
         
     | 
| 
      
 251 
     | 
    
         
            +
            # 25  cold
         
     | 
| 
      
 252 
     | 
    
         
            +
            # 26  cloudy
         
     | 
| 
      
 253 
     | 
    
         
            +
            # 27  mostly cloudy (night)
         
     | 
| 
      
 254 
     | 
    
         
            +
            # 28  mostly cloudy (day)
         
     | 
| 
      
 255 
     | 
    
         
            +
            # 29  partly cloudy (night)
         
     | 
| 
      
 256 
     | 
    
         
            +
            # 30  partly cloudy (day)
         
     | 
| 
      
 257 
     | 
    
         
            +
            # 31  clear (night)
         
     | 
| 
      
 258 
     | 
    
         
            +
            # 32  sunny
         
     | 
| 
      
 259 
     | 
    
         
            +
            # 33  fair (night)
         
     | 
| 
      
 260 
     | 
    
         
            +
            # 34  fair (day)
         
     | 
| 
      
 261 
     | 
    
         
            +
            # 35  mixed rain and hail
         
     | 
| 
      
 262 
     | 
    
         
            +
            # 36  hot
         
     | 
| 
      
 263 
     | 
    
         
            +
            # 37  isolated thunderstorms
         
     | 
| 
      
 264 
     | 
    
         
            +
            # 38  scattered thunderstorms
         
     | 
| 
      
 265 
     | 
    
         
            +
            # 39  scattered thunderstorms
         
     | 
| 
      
 266 
     | 
    
         
            +
            # 40  scattered showers
         
     | 
| 
      
 267 
     | 
    
         
            +
            # 41  heavy snow
         
     | 
| 
      
 268 
     | 
    
         
            +
            # 42  scattered snow showers
         
     | 
| 
      
 269 
     | 
    
         
            +
            # 43  heavy snow
         
     | 
| 
      
 270 
     | 
    
         
            +
            # 44  partly cloudy
         
     | 
| 
      
 271 
     | 
    
         
            +
            # 45  thundershowers
         
     | 
| 
      
 272 
     | 
    
         
            +
            # 46  snow showers
         
     | 
| 
      
 273 
     | 
    
         
            +
            # 47  isolated thundershowers
         
     | 
| 
      
 274 
     | 
    
         
            +
            # 3200  not available
         
     |