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,15 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
# measurements and units
|
4
|
+
require 'data/measurement'
|
5
|
+
require 'data/current'
|
6
|
+
require 'data/forecast'
|
7
|
+
require 'data/zone'
|
8
|
+
require 'data/sun'
|
9
|
+
require 'data/geo'
|
10
|
+
require 'data/location'
|
11
|
+
require 'data/units'
|
12
|
+
require 'data/temperature'
|
13
|
+
require 'data/distance'
|
14
|
+
require 'data/speed'
|
15
|
+
require 'data/pressure'
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# Current Measurement
|
4
|
+
# a data class for current weather conditions
|
5
|
+
#
|
6
|
+
# This is basically a data holding class for the current weather
|
7
|
+
# conditions.
|
8
|
+
#
|
9
|
+
class CurrentMeasurement
|
10
|
+
|
11
|
+
attr_accessor :time, :local_time
|
12
|
+
attr_reader :humidity, :icon, :condition
|
13
|
+
attr_reader :temperature, :dew_point, :heat_index, :wind_chill
|
14
|
+
attr_reader :wind, :pressure, :visibility, :sun
|
15
|
+
|
16
|
+
def time=(time)
|
17
|
+
#raise ArgumentError unless time.is_a?(Time)
|
18
|
+
@time = time
|
19
|
+
end
|
20
|
+
|
21
|
+
def humidity=(humidity)
|
22
|
+
raise ArgumentError unless
|
23
|
+
(humidity.is_a?(Fixnum) || humidity.is_a?(Float))
|
24
|
+
@humidity = humidity
|
25
|
+
end
|
26
|
+
|
27
|
+
def icon=(icon)
|
28
|
+
raise ArgumentError unless icon.is_a?(String)
|
29
|
+
@icon = icon
|
30
|
+
end
|
31
|
+
|
32
|
+
def condition=(condition)
|
33
|
+
raise ArgumentError unless condition.is_a?(String)
|
34
|
+
@condition = condition
|
35
|
+
end
|
36
|
+
|
37
|
+
def temperature=(temperature)
|
38
|
+
raise ArgumentError unless temperature.is_a?(Barometer::Temperature)
|
39
|
+
@temperature = temperature
|
40
|
+
end
|
41
|
+
|
42
|
+
def dew_point=(dew_point)
|
43
|
+
raise ArgumentError unless dew_point.is_a?(Barometer::Temperature)
|
44
|
+
@dew_point = dew_point
|
45
|
+
end
|
46
|
+
|
47
|
+
def heat_index=(heat_index)
|
48
|
+
raise ArgumentError unless heat_index.is_a?(Barometer::Temperature)
|
49
|
+
@heat_index = heat_index
|
50
|
+
end
|
51
|
+
|
52
|
+
def wind_chill=(wind_chill)
|
53
|
+
raise ArgumentError unless wind_chill.is_a?(Barometer::Temperature)
|
54
|
+
@wind_chill = wind_chill
|
55
|
+
end
|
56
|
+
|
57
|
+
def wind=(wind)
|
58
|
+
raise ArgumentError unless wind.is_a?(Barometer::Speed)
|
59
|
+
@wind = wind
|
60
|
+
end
|
61
|
+
|
62
|
+
def pressure=(pressure)
|
63
|
+
raise ArgumentError unless pressure.is_a?(Barometer::Pressure)
|
64
|
+
@pressure = pressure
|
65
|
+
end
|
66
|
+
|
67
|
+
def visibility=(visibility)
|
68
|
+
raise ArgumentError unless visibility.is_a?(Barometer::Distance)
|
69
|
+
@visibility = visibility
|
70
|
+
end
|
71
|
+
|
72
|
+
def sun=(sun)
|
73
|
+
raise ArgumentError unless sun.is_a?(Barometer::Sun)
|
74
|
+
@sun = sun
|
75
|
+
end
|
76
|
+
|
77
|
+
#
|
78
|
+
# helpers
|
79
|
+
#
|
80
|
+
|
81
|
+
# creates "?" helpers for all attributes (which maps to nil?)
|
82
|
+
def method_missing(method,*args)
|
83
|
+
# if the method ends in ?, then strip it off and see if we
|
84
|
+
# respond to the method without the ?
|
85
|
+
if (call_method = method.to_s.chomp!("?")) && respond_to?(call_method)
|
86
|
+
return send(call_method).nil? ? false : true
|
87
|
+
else
|
88
|
+
super(method,*args)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# A simple Distance class
|
4
|
+
#
|
5
|
+
# Think of this like the Integer class. Enhancement
|
6
|
+
# is that you can create a number (in a certain unit), then
|
7
|
+
# get that number back already converted to another unit.
|
8
|
+
#
|
9
|
+
# All comparison operations will be done in metric
|
10
|
+
#
|
11
|
+
# NOTE: this currently only supports the scale of
|
12
|
+
# kilometers (km) and miles (m). There is currently
|
13
|
+
# no way to scale to smaller units (eg km -> m -> mm)
|
14
|
+
class Distance < Barometer::Units
|
15
|
+
|
16
|
+
METRIC_UNITS = "km"
|
17
|
+
IMPERIAL_UNITS = "m"
|
18
|
+
|
19
|
+
attr_accessor :kilometers, :miles
|
20
|
+
|
21
|
+
def initialize(metric=true)
|
22
|
+
@kilometers = nil
|
23
|
+
@miles = nil
|
24
|
+
super(metric)
|
25
|
+
end
|
26
|
+
|
27
|
+
def metric_default=(value); self.km = value; end
|
28
|
+
def imperial_default=(value); self.m = value; end
|
29
|
+
|
30
|
+
#
|
31
|
+
# CONVERTERS
|
32
|
+
#
|
33
|
+
|
34
|
+
def self.km_to_m(km)
|
35
|
+
return nil unless km && (km.is_a?(Integer) || km.is_a?(Float))
|
36
|
+
km.to_f * 0.622
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.m_to_km(m)
|
40
|
+
return nil unless m && (m.is_a?(Integer) || m.is_a?(Float))
|
41
|
+
m.to_f * 1.609
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# ACCESSORS
|
46
|
+
#
|
47
|
+
|
48
|
+
# store kilometers
|
49
|
+
def km=(km)
|
50
|
+
return if !km || !(km.is_a?(Integer) || km.is_a?(Float))
|
51
|
+
@kilometers = km.to_f
|
52
|
+
self.update_miles(km.to_f)
|
53
|
+
end
|
54
|
+
|
55
|
+
# store miles
|
56
|
+
def m=(m)
|
57
|
+
return if !m || !(m.is_a?(Integer) || m.is_a?(Float))
|
58
|
+
@miles = m.to_f
|
59
|
+
self.update_kilometers(m.to_f)
|
60
|
+
end
|
61
|
+
|
62
|
+
# return the stored kilometers or convert from miles
|
63
|
+
def km(as_integer=true)
|
64
|
+
km = (@kilometers || Distance.m_to_km(@miles))
|
65
|
+
km ? (as_integer ? km.to_i : (100*km).round/100.0) : nil
|
66
|
+
end
|
67
|
+
|
68
|
+
# return the stored miles or convert from kilometers
|
69
|
+
def m(as_integer=true)
|
70
|
+
m = (@miles || Distance.km_to_m(@kilometers))
|
71
|
+
m ? (as_integer ? m.to_i : (100*m).round/100.0) : nil
|
72
|
+
end
|
73
|
+
|
74
|
+
#
|
75
|
+
# OPERATORS
|
76
|
+
#
|
77
|
+
|
78
|
+
def <=>(other)
|
79
|
+
self.km <=> other.km
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# HELPERS
|
84
|
+
#
|
85
|
+
|
86
|
+
# will just return the value (no units)
|
87
|
+
def to_i(metric=nil)
|
88
|
+
(metric || (metric.nil? && self.metric?)) ? self.km : self.m
|
89
|
+
end
|
90
|
+
|
91
|
+
# will just return the value (no units) with more precision
|
92
|
+
def to_f(metric=nil)
|
93
|
+
(metric || (metric.nil? && self.metric?)) ? self.km(false) : self.m(false)
|
94
|
+
end
|
95
|
+
|
96
|
+
# will return the value with units
|
97
|
+
def to_s(metric=nil)
|
98
|
+
(metric || (metric.nil? && self.metric?)) ? "#{self.km} #{METRIC_UNITS}" : "#{self.m} #{IMPERIAL_UNITS}"
|
99
|
+
end
|
100
|
+
|
101
|
+
# will just return the units (no value)
|
102
|
+
def units(metric=nil)
|
103
|
+
(metric || (metric.nil? && self.metric?)) ? METRIC_UNITS : IMPERIAL_UNITS
|
104
|
+
end
|
105
|
+
|
106
|
+
# when we set miles, it is possible the a non-equivalent value of
|
107
|
+
# kilometers remains. if so, clear it.
|
108
|
+
def update_kilometers(m)
|
109
|
+
return unless @kilometers
|
110
|
+
difference = Distance.m_to_km(m.to_f) - @kilometers
|
111
|
+
# only clear kilometers if the stored kilometers is off be more then 1 unit
|
112
|
+
# then the conversion of miles
|
113
|
+
@kilometers = nil unless difference.abs <= 1.0
|
114
|
+
end
|
115
|
+
|
116
|
+
# when we set kilometers, it is possible the a non-equivalent value of
|
117
|
+
# miles remains. if so, clear it.
|
118
|
+
def update_miles(km)
|
119
|
+
return unless @miles
|
120
|
+
difference = Distance.km_to_m(km.to_f) - @miles
|
121
|
+
# only clear miles if the stored miles is off be more then 1 unit
|
122
|
+
# then the conversion of kilometers
|
123
|
+
@miles = nil unless difference.abs <= 1.0
|
124
|
+
end
|
125
|
+
|
126
|
+
def nil?
|
127
|
+
(@kilometers || @miles) ? false : true
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'date'
|
2
|
+
module Barometer
|
3
|
+
#
|
4
|
+
# Forecast Measurement
|
5
|
+
# a data class for forecasted weather conditions
|
6
|
+
#
|
7
|
+
# This is basically a data holding class for the forecasted weather
|
8
|
+
# conditions.
|
9
|
+
#
|
10
|
+
class ForecastMeasurement
|
11
|
+
|
12
|
+
attr_reader :date, :icon, :condition
|
13
|
+
attr_reader :low, :high, :pop, :sun
|
14
|
+
|
15
|
+
def date=(date)
|
16
|
+
raise ArgumentError unless date.is_a?(Date)
|
17
|
+
@date = date
|
18
|
+
end
|
19
|
+
|
20
|
+
def icon=(icon)
|
21
|
+
raise ArgumentError unless icon.is_a?(String)
|
22
|
+
@icon = icon
|
23
|
+
end
|
24
|
+
|
25
|
+
def condition=(condition)
|
26
|
+
raise ArgumentError unless condition.is_a?(String)
|
27
|
+
@condition = condition
|
28
|
+
end
|
29
|
+
|
30
|
+
def high=(high)
|
31
|
+
raise ArgumentError unless high.is_a?(Barometer::Temperature)
|
32
|
+
@high = high
|
33
|
+
end
|
34
|
+
|
35
|
+
def low=(low)
|
36
|
+
raise ArgumentError unless low.is_a?(Barometer::Temperature)
|
37
|
+
@low = low
|
38
|
+
end
|
39
|
+
|
40
|
+
def pop=(pop)
|
41
|
+
raise ArgumentError unless pop.is_a?(Fixnum)
|
42
|
+
@pop = pop
|
43
|
+
end
|
44
|
+
|
45
|
+
def sun=(sun)
|
46
|
+
raise ArgumentError unless sun.is_a?(Barometer::Sun)
|
47
|
+
@sun = sun
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# helpers
|
52
|
+
#
|
53
|
+
|
54
|
+
# creates "?" helpers for all attributes (which maps to nil?)
|
55
|
+
def method_missing(method,*args)
|
56
|
+
# if the method ends in ?, then strip it off and see if we
|
57
|
+
# respond to the method without the ?
|
58
|
+
if (call_method = method.to_s.chomp!("?")) && respond_to?(call_method)
|
59
|
+
return send(call_method).nil? ? false : true
|
60
|
+
else
|
61
|
+
super(method,*args)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# A simple Geo class
|
4
|
+
#
|
5
|
+
# Used to store location data from Graticule or HTTParty and convert
|
6
|
+
# into just the data needed for geocoding
|
7
|
+
#
|
8
|
+
class Geo
|
9
|
+
|
10
|
+
attr_accessor :latitude, :longitude
|
11
|
+
attr_accessor :locality, :region, :country, :country_code
|
12
|
+
|
13
|
+
#
|
14
|
+
# this will take a Location object (either generated by Graticule
|
15
|
+
# or HTTParty), and fill in the applicable data
|
16
|
+
#
|
17
|
+
def initialize(location=nil)
|
18
|
+
return unless location
|
19
|
+
|
20
|
+
has_graticule = false
|
21
|
+
begin
|
22
|
+
Graticule
|
23
|
+
has_graticule = true
|
24
|
+
rescue
|
25
|
+
# do nothing, Graticule not available
|
26
|
+
end
|
27
|
+
|
28
|
+
if has_graticule
|
29
|
+
raise ArgumentError unless
|
30
|
+
(location.is_a?(Graticule::Location) || location.is_a?(Hash))
|
31
|
+
else
|
32
|
+
raise ArgumentError unless location.is_a?(Hash)
|
33
|
+
end
|
34
|
+
|
35
|
+
if has_graticule && location.class == Graticule::Location
|
36
|
+
self.build_from_graticule(location)
|
37
|
+
elsif location.class == Hash
|
38
|
+
self.build_from_httparty(location)
|
39
|
+
end
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_from_graticule(location=nil)
|
44
|
+
return nil unless location
|
45
|
+
|
46
|
+
begin
|
47
|
+
require 'rubygems'
|
48
|
+
require 'graticule'
|
49
|
+
$:.unshift(File.dirname(__FILE__))
|
50
|
+
# load some changes to Graticule
|
51
|
+
# TODO: attempt to get changes into Graticule gem
|
52
|
+
require 'extensions/graticule'
|
53
|
+
end
|
54
|
+
|
55
|
+
raise ArgumentError unless location.is_a?(Graticule::Location)
|
56
|
+
|
57
|
+
@latitude = location.latitude
|
58
|
+
@longitude = location.longitude
|
59
|
+
@locality = location.locality
|
60
|
+
@region = location.region
|
61
|
+
@country = location.country
|
62
|
+
@country_code = location.country_code
|
63
|
+
end
|
64
|
+
|
65
|
+
def build_from_httparty(location=nil)
|
66
|
+
return nil unless location
|
67
|
+
raise ArgumentError unless location.is_a?(Hash)
|
68
|
+
|
69
|
+
placemark = location["Placemark"]
|
70
|
+
placemark = placemark.first if placemark.is_a?(Array)
|
71
|
+
|
72
|
+
if placemark && placemark["Point"] && placemark["Point"]["coordinates"]
|
73
|
+
@latitude = placemark["Point"]["coordinates"].split(',')[1].to_f
|
74
|
+
@longitude = placemark["Point"]["coordinates"].split(',')[0].to_f
|
75
|
+
end
|
76
|
+
if placemark && placemark["AddressDetails"] && placemark["AddressDetails"]["Country"]
|
77
|
+
if placemark["AddressDetails"]["Country"]["AdministrativeArea"]
|
78
|
+
if placemark["AddressDetails"]["Country"]["AdministrativeArea"]["SubAdministrativeArea"]
|
79
|
+
locality = placemark["AddressDetails"]["Country"]["AdministrativeArea"]["SubAdministrativeArea"]["Locality"]
|
80
|
+
else
|
81
|
+
locality = placemark["AddressDetails"]["Country"]["AdministrativeArea"]["Locality"]
|
82
|
+
end
|
83
|
+
if locality
|
84
|
+
@locality = locality["LocalityName"]
|
85
|
+
end
|
86
|
+
@region = placemark["AddressDetails"]["Country"]["AdministrativeArea"]["AdministrativeAreaName"]
|
87
|
+
end
|
88
|
+
@country = placemark["AddressDetails"]["Country"]["CountryName"]
|
89
|
+
@country_code = placemark["AddressDetails"]["Country"]["CountryNameCode"]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def coordinates
|
94
|
+
[@latitude, @longitude].join(',')
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# A simple Location class
|
4
|
+
#
|
5
|
+
# Used to store location information about the station that
|
6
|
+
# gave the measurement data for a weather query, or the location
|
7
|
+
# that was queried
|
8
|
+
#
|
9
|
+
class Location
|
10
|
+
|
11
|
+
attr_accessor :id, :name, :city
|
12
|
+
attr_accessor :state_name, :state_code, :country, :country_code, :zip_code
|
13
|
+
attr_accessor :latitude, :longitude
|
14
|
+
|
15
|
+
def coordinates
|
16
|
+
[@latitude, @longitude].join(',')
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module Barometer
|
2
|
+
#
|
3
|
+
# Measurement
|
4
|
+
# a class that holds the response from a weather service
|
5
|
+
#
|
6
|
+
# its main purpose is to hold all the data collected from a weather service
|
7
|
+
# as it is passed to the weather object
|
8
|
+
#
|
9
|
+
# this response includes
|
10
|
+
# - current weather data (using the CurrentMeasurement class)
|
11
|
+
# - forecasted weather data (an Array of instances of the ForecastMeasurement class)
|
12
|
+
# - time_zone information (for the location in question)
|
13
|
+
# - weather station information (for the station that gave collected the data)
|
14
|
+
#
|
15
|
+
class Measurement
|
16
|
+
|
17
|
+
# the weather service source
|
18
|
+
attr_reader :source
|
19
|
+
# current and forecasted data
|
20
|
+
attr_reader :current, :forecast
|
21
|
+
attr_reader :timezone, :station, :location
|
22
|
+
attr_reader :success, :time
|
23
|
+
attr_accessor :metric
|
24
|
+
|
25
|
+
def initialize(source=nil, metric=true)
|
26
|
+
@source = source
|
27
|
+
@metric = metric
|
28
|
+
@success = false
|
29
|
+
end
|
30
|
+
|
31
|
+
def success!
|
32
|
+
if current && current.temperature && !current.temperature.c.nil?
|
33
|
+
@success = true
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def stamp!; @time = Time.now.utc; end
|
38
|
+
def success?; @success; end
|
39
|
+
def metric?; @metric; end
|
40
|
+
def metric!; @metric=true; end
|
41
|
+
def imperial!; @metric=false; end
|
42
|
+
|
43
|
+
# this will tell us if the measurement is still current ... if it is still
|
44
|
+
# current this means that the CurrentMeasurement can still used as now
|
45
|
+
#
|
46
|
+
# what it also means is that if you took a measurement right now (time = now)
|
47
|
+
# and then asked if current?(time_in_future) that current? would be true for
|
48
|
+
# any time_in_future within 4 hours of now
|
49
|
+
#
|
50
|
+
# where is this useful? lets say you take the measurement now (time = now),
|
51
|
+
# and then you want to know if self.windy?(5_hours_in_future) ... we could
|
52
|
+
# not use the current data for this answser as the time 5_hours_in_future
|
53
|
+
# is not current
|
54
|
+
def current?(utc_time=Time.now.utc)
|
55
|
+
return false unless @time
|
56
|
+
raise ArgumentError unless utc_time.is_a?(Time)
|
57
|
+
hours_still_current = 4
|
58
|
+
difference = (@time - utc_time).to_i
|
59
|
+
difference = (difference*(-1)).to_i if difference < 0
|
60
|
+
difference <= (60*60*hours_still_current).to_i
|
61
|
+
end
|
62
|
+
|
63
|
+
#
|
64
|
+
# Returns a forecast for a day given by a Date, DateTime,
|
65
|
+
# Time, or a string that can be parsed to a date
|
66
|
+
#
|
67
|
+
# credit: http://github.com/jdpace/weatherman/
|
68
|
+
#
|
69
|
+
def for(date=nil)
|
70
|
+
date = @timezone.today unless date || !@timezone
|
71
|
+
date ||= Date.today
|
72
|
+
return nil unless (@forecast && @forecast.size > 0)
|
73
|
+
|
74
|
+
# Format date into a Date class
|
75
|
+
date = case date.class.name
|
76
|
+
when 'String'
|
77
|
+
Date.parse(date)
|
78
|
+
when 'Date'
|
79
|
+
date
|
80
|
+
when 'DateTime'
|
81
|
+
Date.new(date.year, date.month, date.day)
|
82
|
+
when 'Time'
|
83
|
+
Date.new(date.year, date.month, date.day)
|
84
|
+
end
|
85
|
+
|
86
|
+
day = nil
|
87
|
+
@forecast.each do |f|
|
88
|
+
day = f if date == f.date
|
89
|
+
end
|
90
|
+
return day
|
91
|
+
end
|
92
|
+
|
93
|
+
def source=(source)
|
94
|
+
raise ArgumentError unless source.is_a?(Symbol)
|
95
|
+
@source = source
|
96
|
+
end
|
97
|
+
|
98
|
+
def time=(time=Time.now.utc)
|
99
|
+
raise ArgumentError unless time.is_a?(Time)
|
100
|
+
@time = time
|
101
|
+
end
|
102
|
+
|
103
|
+
def current=(current)
|
104
|
+
raise ArgumentError unless current.is_a?(Barometer::CurrentMeasurement)
|
105
|
+
@current = current
|
106
|
+
self.stamp!
|
107
|
+
# self-determine success
|
108
|
+
self.success!
|
109
|
+
end
|
110
|
+
|
111
|
+
def forecast=(forecast)
|
112
|
+
raise ArgumentError unless forecast.is_a?(Array)
|
113
|
+
@forecast = forecast
|
114
|
+
end
|
115
|
+
|
116
|
+
def timezone=(timezone)
|
117
|
+
#raise ArgumentError unless timezone.is_a?(String)
|
118
|
+
raise ArgumentError unless timezone.is_a?(Barometer::Zone)
|
119
|
+
@timezone = timezone
|
120
|
+
end
|
121
|
+
|
122
|
+
def station=(station)
|
123
|
+
raise ArgumentError unless station.is_a?(Barometer::Location)
|
124
|
+
@station = station
|
125
|
+
end
|
126
|
+
|
127
|
+
def location=(location)
|
128
|
+
raise ArgumentError unless location.is_a?(Barometer::Location)
|
129
|
+
@location = location
|
130
|
+
end
|
131
|
+
|
132
|
+
#
|
133
|
+
# simple questions
|
134
|
+
# pass questions to the source
|
135
|
+
#
|
136
|
+
|
137
|
+
def windy?(threshold=10, utc_time=Time.now.utc)
|
138
|
+
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
139
|
+
raise ArgumentError unless utc_time.is_a?(Time)
|
140
|
+
Barometer::Service.source(@source).windy?(self, threshold, utc_time)
|
141
|
+
end
|
142
|
+
|
143
|
+
def wet?(threshold=50, utc_time=Time.now.utc)
|
144
|
+
raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
|
145
|
+
raise ArgumentError unless utc_time.is_a?(Time)
|
146
|
+
Barometer::Service.source(@source).wet?(self, threshold, utc_time)
|
147
|
+
end
|
148
|
+
|
149
|
+
def day?(utc_time=Time.now.utc)
|
150
|
+
raise ArgumentError unless utc_time.is_a?(Time)
|
151
|
+
Barometer::Service.source(@source).day?(self, utc_time)
|
152
|
+
end
|
153
|
+
|
154
|
+
def sunny?(utc_time=Time.now.utc)
|
155
|
+
raise ArgumentError unless utc_time.is_a?(Time)
|
156
|
+
return false if self.day?(utc_time) == false
|
157
|
+
Barometer::Service.source(@source).sunny?(self, utc_time)
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|