attack-barometer 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (64) hide show
  1. data/README.rdoc +51 -9
  2. data/VERSION.yml +1 -1
  3. data/bin/barometer +57 -7
  4. data/lib/barometer/base.rb +3 -0
  5. data/lib/barometer/data/sun.rb +10 -0
  6. data/lib/barometer/data/zone.rb +79 -188
  7. data/lib/barometer/data.rb +11 -6
  8. data/lib/barometer/formats/coordinates.rb +4 -1
  9. data/lib/barometer/formats/geocode.rb +9 -7
  10. data/lib/barometer/formats/icao.rb +2 -2
  11. data/lib/barometer/formats/weather_id.rb +2 -2
  12. data/lib/barometer/measurements/common.rb +113 -0
  13. data/lib/barometer/{data → measurements}/current.rb +17 -42
  14. data/lib/barometer/measurements/forecast.rb +62 -0
  15. data/lib/barometer/measurements/forecast_array.rb +72 -0
  16. data/lib/barometer/{data → measurements}/measurement.rb +57 -45
  17. data/lib/barometer/measurements/night.rb +27 -0
  18. data/lib/barometer/query.rb +55 -5
  19. data/lib/barometer/services.rb +3 -1
  20. data/lib/barometer/translations/zone_codes.yml +360 -0
  21. data/lib/barometer/weather.rb +5 -4
  22. data/lib/barometer/weather_services/google.rb +19 -35
  23. data/lib/barometer/weather_services/service.rb +113 -255
  24. data/lib/barometer/weather_services/weather_bug.rb +291 -2
  25. data/lib/barometer/weather_services/weather_dot_com.rb +45 -54
  26. data/lib/barometer/weather_services/wunderground.rb +83 -89
  27. data/lib/barometer/weather_services/yahoo.rb +44 -91
  28. data/lib/barometer/web_services/geocode.rb +1 -0
  29. data/lib/barometer/web_services/timezone.rb +40 -0
  30. data/lib/barometer/web_services/weather_id.rb +17 -2
  31. data/lib/barometer.rb +11 -0
  32. data/lib/demometer/demometer.rb +28 -0
  33. data/lib/demometer/public/css/master.css +259 -1
  34. data/lib/demometer/views/index.erb +2 -0
  35. data/lib/demometer/views/layout.erb +3 -2
  36. data/lib/demometer/views/measurement.erb +4 -1
  37. data/lib/demometer/views/readme.erb +116 -88
  38. data/spec/data/sun_spec.rb +53 -0
  39. data/spec/data/zone_spec.rb +330 -100
  40. data/spec/fixtures/formats/weather_id/ksfo.xml +1 -0
  41. data/spec/fixtures/services/weather_bug/90210_current.xml +1 -0
  42. data/spec/fixtures/services/weather_bug/90210_forecast.xml +1 -0
  43. data/spec/formats/weather_id_spec.rb +10 -5
  44. data/spec/measurements/common_spec.rb +352 -0
  45. data/spec/{data → measurements}/current_spec.rb +40 -103
  46. data/spec/measurements/forecast_array_spec.rb +165 -0
  47. data/spec/measurements/forecast_spec.rb +135 -0
  48. data/spec/{data → measurements}/measurement_spec.rb +86 -107
  49. data/spec/measurements/night_measurement_spec.rb +49 -0
  50. data/spec/query_spec.rb +12 -2
  51. data/spec/spec_helper.rb +28 -1
  52. data/spec/weather_services/google_spec.rb +27 -117
  53. data/spec/weather_services/services_spec.rb +49 -1024
  54. data/spec/weather_services/weather_bug_spec.rb +274 -0
  55. data/spec/weather_services/weather_dot_com_spec.rb +45 -125
  56. data/spec/weather_services/wunderground_spec.rb +42 -136
  57. data/spec/weather_services/yahoo_spec.rb +26 -116
  58. data/spec/weather_spec.rb +45 -45
  59. metadata +23 -11
  60. data/lib/barometer/data/forecast.rb +0 -84
  61. data/lib/barometer/data/night.rb +0 -69
  62. data/lib/barometer/extensions/graticule.rb +0 -51
  63. data/spec/data/forecast_spec.rb +0 -192
  64. data/spec/data/night_measurement_spec.rb +0 -136
@@ -23,11 +23,14 @@ module Barometer
23
23
  unless converts?(original_query)
24
24
  return (original_query.format == format ? original_query.dup : nil)
25
25
  end
26
- converted_query = Barometer::Query.new
27
-
28
- converted_query = (original_query.format == :weather_id ?
29
- Query::Format::WeatherID.reverse(original_query) :
30
- geocode(original_query))
26
+
27
+ unless converted_query = original_query.get_conversion(format)
28
+ converted_query = Barometer::Query.new
29
+ converted_query = (original_query.format == :weather_id ?
30
+ Query::Format::WeatherID.reverse(original_query) :
31
+ geocode(original_query))
32
+ original_query.post_conversion(converted_query) if converted_query
33
+ end
31
34
  converted_query
32
35
  end
33
36
 
@@ -35,9 +38,8 @@ module Barometer
35
38
  #
36
39
  def self.geocode(original_query)
37
40
  raise ArgumentError unless is_a_query?(original_query)
41
+
38
42
  converted_query = Barometer::Query.new
39
-
40
- #converted_query.geo = _geocode(original_query)
41
43
  converted_query.geo = WebService::Geocode.fetch(original_query)
42
44
  if converted_query.geo
43
45
  converted_query.country_code = converted_query.geo.country_code
@@ -22,8 +22,8 @@ module Barometer
22
22
  #
23
23
  def self.regex; /^[A-Za-z]{3,4}$/; end
24
24
 
25
- # # in some cases the first letter can designate the country
26
- # #
25
+ # in some cases the first letter can designate the country
26
+ #
27
27
  def self.country_code(query=nil)
28
28
  return unless query && query.is_a?(String)
29
29
  $:.unshift(File.dirname(__FILE__))
@@ -17,7 +17,7 @@ module Barometer
17
17
  def self.format; :weather_id; end
18
18
  def self.regex; /(^[A-Za-z]{4}[0-9]{4}$)/; end
19
19
  def self.convertable_formats
20
- [:short_zipcode, :zipcode, :coordinates, :geocode]
20
+ [:short_zipcode, :zipcode, :coordinates, :icao, :geocode]
21
21
  end
22
22
 
23
23
  # the first two letters of the :weather_id is the country_code
@@ -31,10 +31,10 @@ module Barometer
31
31
  def self.to(original_query)
32
32
  raise ArgumentError unless is_a_query?(original_query)
33
33
  return nil unless converts?(original_query)
34
- converted_query = Barometer::Query.new
35
34
 
36
35
  # convert original query to :geocode, as that is the only
37
36
  # format we can convert directly from to weather_id
37
+ converted_query = Barometer::Query.new
38
38
  converted_query = Query::Format::Geocode.to(original_query)
39
39
  converted_query.q = _search(converted_query)
40
40
  converted_query.format = format
@@ -0,0 +1,113 @@
1
+ module Barometer
2
+ #
3
+ # Common Measurement
4
+ #
5
+ # Code common to both Current and Forecast Measurements
6
+ #
7
+ class Measurement::Common
8
+
9
+ attr_reader :humidity, :icon, :condition
10
+ attr_reader :wind, :sun
11
+ attr_accessor :metric
12
+
13
+ def initialize(metric=true)
14
+ @metric = metric
15
+ end
16
+
17
+ def metric?; metric; end
18
+
19
+ # accessors (with input checking)
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 wind=(wind)
38
+ raise ArgumentError unless wind.is_a?(Data::Speed)
39
+ @wind = wind
40
+ end
41
+
42
+ def sun=(sun)
43
+ raise ArgumentError unless (sun.is_a?(Data::Sun) || sun.nil?)
44
+ @sun = sun
45
+ end
46
+
47
+ #
48
+ # helpers
49
+ #
50
+
51
+ # creates "?" helpers for all attributes (which maps to nil?)
52
+ #
53
+ def method_missing(method,*args)
54
+ # if the method ends in ?, then strip it off and see if we
55
+ # respond to the method without the ?
56
+ if (call_method = method.to_s.chomp!("?")) && respond_to?(call_method)
57
+ return send(call_method).nil? ? false : true
58
+ else
59
+ super(method,*args)
60
+ end
61
+ end
62
+
63
+ #
64
+ # answer simple questions
65
+ #
66
+
67
+ def windy?(threshold=10)
68
+ raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
69
+ return nil unless wind?
70
+ wind.to_f(metric?) >= threshold.to_f
71
+ end
72
+
73
+ def day?(time)
74
+ return nil unless time && sun?
75
+ sun.after_rise?(time) && sun.before_set?(time)
76
+ end
77
+
78
+ def wet?(wet_icons=nil, humidity_threshold=99)
79
+ result = nil
80
+ result ||= _wet_by_icon?(wet_icons) if icon?
81
+ result ||= _wet_by_humidity?(humidity_threshold) if humidity?
82
+ result
83
+ end
84
+
85
+ def sunny?(time, sunny_icons=nil)
86
+ return nil unless time
87
+ is_day = day?(time)
88
+ return nil if is_day.nil?
89
+ is_day && _sunny_by_icon?(sunny_icons)
90
+ end
91
+
92
+ private
93
+
94
+ def _wet_by_humidity?(threshold=99)
95
+ raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
96
+ return nil unless humidity?
97
+ humidity.to_f >= threshold.to_f
98
+ end
99
+
100
+ def _wet_by_icon?(wet_icons=nil)
101
+ raise ArgumentError unless (wet_icons.nil? || wet_icons.is_a?(Array))
102
+ return nil unless (icon? && wet_icons)
103
+ wet_icons.include?(icon.to_s.downcase)
104
+ end
105
+
106
+ def _sunny_by_icon?(sunny_icons=nil)
107
+ raise ArgumentError unless (sunny_icons.nil? || sunny_icons.is_a?(Array))
108
+ return nil unless (icon? && sunny_icons)
109
+ sunny_icons.include?(icon.to_s.downcase)
110
+ end
111
+
112
+ end
113
+ end
@@ -6,31 +6,14 @@ module Barometer
6
6
  # This is basically a data holding class for the current weather
7
7
  # conditions.
8
8
  #
9
- class Data::CurrentMeasurement
9
+ class Measurement::Current < Measurement::Common
10
10
 
11
11
  attr_reader :current_at, :updated_at
12
- attr_reader :humidity, :icon, :condition
13
12
  attr_reader :temperature, :dew_point, :heat_index, :wind_chill
14
- attr_reader :wind, :pressure, :visibility, :sun
13
+ attr_reader :pressure, :visibility
15
14
 
16
15
  # accessors (with input checking)
17
16
  #
18
- def humidity=(humidity)
19
- raise ArgumentError unless
20
- (humidity.is_a?(Fixnum) || humidity.is_a?(Float))
21
- @humidity = humidity
22
- end
23
-
24
- def icon=(icon)
25
- raise ArgumentError unless icon.is_a?(String)
26
- @icon = icon
27
- end
28
-
29
- def condition=(condition)
30
- raise ArgumentError unless condition.is_a?(String)
31
- @condition = condition
32
- end
33
-
34
17
  def temperature=(temperature)
35
18
  raise ArgumentError unless temperature.is_a?(Data::Temperature)
36
19
  @temperature = temperature
@@ -51,11 +34,6 @@ module Barometer
51
34
  @wind_chill = wind_chill
52
35
  end
53
36
 
54
- def wind=(wind)
55
- raise ArgumentError unless wind.is_a?(Data::Speed)
56
- @wind = wind
57
- end
58
-
59
37
  def pressure=(pressure)
60
38
  raise ArgumentError unless pressure.is_a?(Data::Pressure)
61
39
  @pressure = pressure
@@ -66,35 +44,32 @@ module Barometer
66
44
  @visibility = visibility
67
45
  end
68
46
 
69
- def sun=(sun)
70
- raise ArgumentError unless sun.is_a?(Data::Sun)
71
- @sun = sun
72
- end
73
-
74
47
  def current_at=(current_at)
75
48
  raise ArgumentError unless (current_at.is_a?(Data::LocalTime) || current_at.is_a?(Data::LocalDateTime))
76
49
  @current_at = current_at
77
50
  end
78
51
 
79
52
  def updated_at=(updated_at)
80
- raise ArgumentError unless (updated_at.is_a?(Data::LocalTime) || updated_at.is_a?(Data::LocalDateTime))
81
- @updated_at = updated_at
53
+ raise ArgumentError unless (updated_at.is_a?(Data::LocalTime) || updated_at.is_a?(Data::LocalDateTime))
54
+ @updated_at = updated_at
82
55
  end
83
56
 
84
57
  #
85
- # helpers
58
+ # answer simple questions
86
59
  #
87
60
 
88
- # creates "?" helpers for all attributes (which maps to nil?)
89
- #
90
- def method_missing(method,*args)
91
- # if the method ends in ?, then strip it off and see if we
92
- # respond to the method without the ?
93
- if (call_method = method.to_s.chomp!("?")) && respond_to?(call_method)
94
- return send(call_method).nil? ? false : true
95
- else
96
- super(method,*args)
97
- end
61
+ def wet?(wet_icons=nil, humidity_threshold=99)
62
+ result = nil
63
+ result ||= super(wet_icons, humidity_threshold) if (icon? || humidity?)
64
+ result ||= _wet_by_dewpoint? if (dew_point? && temperature?)
65
+ result
66
+ end
67
+
68
+ private
69
+
70
+ def _wet_by_dewpoint?
71
+ return nil unless dew_point? && temperature?
72
+ temperature.to_f(metric?) <= dew_point.to_f(metric?)
98
73
  end
99
74
 
100
75
  end
@@ -0,0 +1,62 @@
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 Measurement::Forecast < Measurement::Common
11
+
12
+ attr_reader :date
13
+ attr_reader :low, :high, :pop, :night
14
+
15
+ # accessors (with input checking)
16
+ #
17
+ def date=(date)
18
+ raise ArgumentError unless date.is_a?(Date)
19
+ @date = date
20
+ end
21
+
22
+ def high=(high)
23
+ raise ArgumentError unless high.is_a?(Data::Temperature)
24
+ @high = high
25
+ end
26
+
27
+ def low=(low)
28
+ raise ArgumentError unless low.is_a?(Data::Temperature)
29
+ @low = low
30
+ end
31
+
32
+ def pop=(pop)
33
+ raise ArgumentError unless pop.is_a?(Fixnum)
34
+ @pop = pop
35
+ end
36
+
37
+ def night=(night)
38
+ raise ArgumentError unless night.is_a?(Measurement::ForecastNight)
39
+ @night = night
40
+ end
41
+
42
+ #
43
+ # answer simple questions
44
+ #
45
+
46
+ def wet?(wet_icons=nil, pop_threshold=50, humidity_threshold=99)
47
+ result = nil
48
+ result ||= _wet_by_pop?(pop_threshold) if pop?
49
+ result ||= super(wet_icons, humidity_threshold) if (icon? || humidity?)
50
+ result
51
+ end
52
+
53
+ private
54
+
55
+ def _wet_by_pop?(threshold=50)
56
+ raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
57
+ return nil unless pop?
58
+ pop.to_f >= threshold.to_f
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,72 @@
1
+ require 'date'
2
+ module Barometer
3
+ #
4
+ # Forecast Array
5
+ # an array that holds multiple forecasts
6
+ #
7
+ class Measurement::ForecastArray < Array
8
+
9
+ def <<(forecast)
10
+ raise ArgumentError unless forecast.is_a?(Measurement::Forecast)
11
+ super(forecast)
12
+ end
13
+
14
+ def [](index)
15
+ index.is_a?(Fixnum) ? super(index) : self.for(index)
16
+ end
17
+
18
+ #
19
+ # Returns a forecast for a day given by a Date, DateTime,
20
+ # Time, or a string that can be parsed to a date
21
+ #
22
+ # credit: http://github.com/jdpace/weatherman/
23
+ #
24
+ def for(date)
25
+
26
+ return nil unless self.size > 0
27
+
28
+ # Format date into a Date class
29
+ date = case date.class.name
30
+ when 'Date'
31
+ date
32
+ when 'Data::LocalDateTime'
33
+ date.to_d
34
+ when 'String'
35
+ Date.parse(date)
36
+ when 'Time'
37
+ Date.new(date.year, date.month, date.day)
38
+ when 'DateTime'
39
+ Date.new(date.year, date.month, date.day)
40
+ end
41
+
42
+ day = nil
43
+ self.each do |f|
44
+ day = f if date == f.date
45
+ end
46
+ return day
47
+ end
48
+
49
+ #
50
+ # answer simple questions
51
+ #
52
+
53
+ def windy?(datetime, threshold=10)
54
+ (forecast = self[datetime]) ? forecast.windy?(threshold) : nil
55
+ end
56
+
57
+ def day?(datetime)
58
+ local_time = Data::LocalTime.parse(datetime)
59
+ (forecast = self[datetime]) ? forecast.day?(local_time) : nil
60
+ end
61
+
62
+ def sunny?(datetime, sunny_icons=nil)
63
+ local_time = Data::LocalTime.parse(datetime)
64
+ (forecast = self[datetime]) ? forecast.sunny?(local_time, sunny_icons) : nil
65
+ end
66
+
67
+ def wet?(datetime, wet_icons=nil, pop_threshold=50, humidity_threshold=99)
68
+ (forecast = self[datetime]) ? forecast.wet?(wet_icons,pop_threshold,humidity_threshold) : nil
69
+ end
70
+
71
+ end
72
+ end
@@ -12,7 +12,7 @@ module Barometer
12
12
  # - time_zone information (for the location in question)
13
13
  # - weather station information (for the station that gave collected the data)
14
14
  #
15
- class Data::Measurement
15
+ class Measurement
16
16
 
17
17
  attr_reader :source, :weight
18
18
  attr_reader :measured_at, :utc_time_stamp
@@ -20,6 +20,7 @@ module Barometer
20
20
  attr_reader :timezone, :station, :location, :links
21
21
  attr_reader :success
22
22
  attr_accessor :metric, :query, :format
23
+ attr_accessor :start_at, :end_at
23
24
 
24
25
  def initialize(source=nil, metric=true)
25
26
  @source = source
@@ -39,6 +40,7 @@ module Barometer
39
40
  def metric?; @metric; end
40
41
  def metric!; @metric=true; end
41
42
  def imperial!; @metric=false; end
43
+ def now; timezone ? timezone.now : nil; end
42
44
 
43
45
  #
44
46
  # this will tell us if the measurement is still current ... if it is still
@@ -58,7 +60,7 @@ module Barometer
58
60
  self.current.current_at : self.measured_at)
59
61
 
60
62
  local_time = (local_time.nil? ? current_at : Data::LocalTime.parse(local_time))
61
- return false unless local_time
63
+ return true unless local_time
62
64
  raise ArgumentError unless local_time.is_a?(Data::LocalTime)
63
65
 
64
66
  hours_still_current = 4
@@ -70,32 +72,12 @@ module Barometer
70
72
  # Returns a forecast for a day given by a Date, DateTime,
71
73
  # Time, or a string that can be parsed to a date
72
74
  #
73
- # credit: http://github.com/jdpace/weatherman/
74
- #
75
75
  def for(date=nil)
76
76
  date = @timezone.today unless date || !@timezone
77
77
  date ||= Date.today
78
78
  return nil unless (@forecast && @forecast.size > 0)
79
79
 
80
- # Format date into a Date class
81
- date = case date.class.name
82
- when 'Date'
83
- date
84
- when 'Data::LocalDateTime'
85
- date.to_d
86
- when 'String'
87
- Date.parse(date)
88
- when 'Time'
89
- Date.new(date.year, date.month, date.day)
90
- when 'DateTime'
91
- Date.new(date.year, date.month, date.day)
92
- end
93
-
94
- day = nil
95
- @forecast.each do |f|
96
- day = f if date == f.date
97
- end
98
- return day
80
+ @forecast.for(date)
99
81
  end
100
82
 
101
83
  #
@@ -113,18 +95,19 @@ module Barometer
113
95
  end
114
96
 
115
97
  def current=(current)
116
- raise ArgumentError unless current.is_a?(Data::CurrentMeasurement)
98
+ raise ArgumentError unless current.is_a?(Measurement::Current)
117
99
  @current = current
118
100
  self.stamp!
119
101
  self.success!
120
102
  end
121
103
 
122
104
  def forecast=(forecast)
123
- raise ArgumentError unless forecast.is_a?(Array)
105
+ raise ArgumentError unless forecast.is_a?(Measurement::ForecastArray)
124
106
  @forecast = forecast
125
107
  end
126
108
 
127
109
  def timezone=(timezone)
110
+ return unless timezone
128
111
  raise ArgumentError unless timezone.is_a?(Data::Zone)
129
112
  @timezone = timezone
130
113
  end
@@ -156,34 +139,63 @@ module Barometer
156
139
 
157
140
  #
158
141
  # simple questions
159
- # pass questions to the source
160
142
  #
161
143
 
162
- def windy?(threshold=10, time_string=nil)
163
- local_datetime = Data::LocalDateTime.parse(time_string) if time_string
164
- raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
165
- raise ArgumentError unless (local_datetime.is_a?(Data::LocalDateTime) || local_datetime.nil?)
166
- Barometer::WeatherService.source(@source).windy?(self, threshold, local_datetime)
167
- end
168
-
169
- def wet?(threshold=50, time_string=nil)
170
- local_datetime = Data::LocalDateTime.parse(time_string) if time_string
171
- raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
172
- raise ArgumentError unless (local_datetime.is_a?(Data::LocalDateTime) || local_datetime.nil?)
173
- Barometer::WeatherService.source(@source).wet?(self, threshold, local_datetime)
144
+ def windy?(time_string=nil, threshold=10)
145
+ time_string ||= (measured_at || now)
146
+ local_time = Data::LocalTime.parse(time_string)
147
+
148
+ if current?(local_time)
149
+ return nil unless current
150
+ current.windy?(threshold)
151
+ else
152
+ return nil unless forecast && (future = forecast[local_time])
153
+ future.windy?(threshold)
154
+ end
174
155
  end
175
156
 
176
157
  def day?(time_string=nil)
177
- local_datetime = Data::LocalDateTime.parse(time_string) if time_string
178
- raise ArgumentError unless (local_datetime.is_a?(Data::LocalDateTime) || local_datetime.nil?)
179
- Barometer::WeatherService.source(@source).day?(self, local_datetime)
158
+ time_string ||= (measured_at || now)
159
+ local_time = Data::LocalTime.parse(time_string)
160
+
161
+ if current?(local_time)
162
+ return nil unless current
163
+ current.day?(local_time)
164
+ else
165
+ return nil unless forecast && (future = forecast[local_time])
166
+ future.day?(local_time)
167
+ end
180
168
  end
181
169
 
182
170
  def sunny?(time_string=nil)
183
- local_datetime = Data::LocalDateTime.parse(time_string) if time_string
184
- raise ArgumentError unless (local_datetime.is_a?(Data::LocalDateTime) || local_datetime.nil?)
185
- return false if self.day?(local_datetime) == false
186
- Barometer::WeatherService.source(@source).sunny?(self, local_datetime)
171
+ time_string ||= (measured_at || now)
172
+ local_time = Data::LocalTime.parse(time_string)
173
+ sunny_icons = Barometer::WeatherService.source(@source)._sunny_icon_codes
174
+
175
+ is_day = day?(local_time)
176
+ return is_day unless is_day
177
+
178
+ if current?(local_time)
179
+ return nil unless current
180
+ current.sunny?(local_time, sunny_icons)
181
+ else
182
+ return nil unless forecast && (future = forecast[local_time])
183
+ future.sunny?(local_time, sunny_icons)
184
+ end
185
+ end
186
+
187
+ def wet?(time_string=nil, pop_threshold=50, humidity_threshold=99)
188
+ time_string ||= (measured_at || now)
189
+ local_time = Data::LocalTime.parse(time_string)
190
+ wet_icons = Barometer::WeatherService.source(@source)._wet_icon_codes
191
+
192
+ if current?(local_time)
193
+ return nil unless current
194
+ current.wet?(wet_icons, humidity_threshold)
195
+ else
196
+ return nil unless forecast && (future = forecast[local_time])
197
+ future.wet?(wet_icons, pop_threshold, humidity_threshold)
198
+ end
187
199
  end
188
200
 
189
201
  end
@@ -0,0 +1,27 @@
1
+ require 'date'
2
+ module Barometer
3
+ #
4
+ # Night Measurement
5
+ # a data class for forecasted night weather conditions
6
+ #
7
+ # This is basically a data holding class for the forecasted night
8
+ # weather conditions.
9
+ #
10
+ class Measurement::ForecastNight < Measurement::Common
11
+
12
+ attr_reader :date, :pop
13
+
14
+ # accessors (with input checking)
15
+ #
16
+ def date=(date)
17
+ raise ArgumentError unless date.is_a?(Date)
18
+ @date = date
19
+ end
20
+
21
+ def pop=(pop)
22
+ raise ArgumentError unless pop.is_a?(Fixnum)
23
+ @pop = pop
24
+ end
25
+
26
+ end
27
+ end