barometer 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. data/README.rdoc +51 -9
  2. data/VERSION.yml +2 -2
  3. data/bin/barometer +57 -7
  4. data/lib/barometer.rb +11 -0
  5. data/lib/barometer/base.rb +3 -0
  6. data/lib/barometer/data.rb +11 -6
  7. data/lib/barometer/data/sun.rb +10 -0
  8. data/lib/barometer/data/zone.rb +79 -188
  9. data/lib/barometer/formats/coordinates.rb +4 -1
  10. data/lib/barometer/formats/geocode.rb +9 -7
  11. data/lib/barometer/formats/icao.rb +2 -2
  12. data/lib/barometer/formats/weather_id.rb +2 -2
  13. data/lib/barometer/measurements/common.rb +113 -0
  14. data/lib/barometer/{data → measurements}/current.rb +17 -42
  15. data/lib/barometer/measurements/forecast.rb +62 -0
  16. data/lib/barometer/measurements/forecast_array.rb +72 -0
  17. data/lib/barometer/{data → measurements}/measurement.rb +57 -45
  18. data/lib/barometer/measurements/night.rb +27 -0
  19. data/lib/barometer/query.rb +55 -5
  20. data/lib/barometer/services.rb +3 -1
  21. data/lib/barometer/translations/icao_country_codes.yml +274 -1
  22. data/lib/barometer/translations/weather_country_codes.yml +189 -6
  23. data/lib/barometer/translations/zone_codes.yml +360 -0
  24. data/lib/barometer/weather.rb +5 -4
  25. data/lib/barometer/weather_services/google.rb +19 -35
  26. data/lib/barometer/weather_services/service.rb +113 -255
  27. data/lib/barometer/weather_services/weather_bug.rb +291 -2
  28. data/lib/barometer/weather_services/weather_dot_com.rb +45 -54
  29. data/lib/barometer/weather_services/wunderground.rb +83 -89
  30. data/lib/barometer/weather_services/yahoo.rb +44 -91
  31. data/lib/barometer/web_services/geocode.rb +1 -0
  32. data/lib/barometer/web_services/timezone.rb +40 -0
  33. data/lib/barometer/web_services/weather_id.rb +17 -2
  34. data/lib/demometer/demometer.rb +28 -0
  35. data/lib/demometer/public/css/master.css +259 -1
  36. data/lib/demometer/public/css/print.css +94 -0
  37. data/lib/demometer/public/css/syntax.css +64 -0
  38. data/lib/demometer/public/images/link-out.gif +0 -0
  39. data/lib/demometer/views/about.erb +10 -0
  40. data/lib/demometer/views/index.erb +2 -0
  41. data/lib/demometer/views/layout.erb +3 -2
  42. data/lib/demometer/views/measurement.erb +4 -1
  43. data/lib/demometer/views/readme.erb +116 -88
  44. data/spec/data/sun_spec.rb +53 -0
  45. data/spec/data/zone_spec.rb +330 -100
  46. data/spec/fixtures/formats/weather_id/ksfo.xml +1 -0
  47. data/spec/fixtures/services/weather_bug/90210_current.xml +1 -0
  48. data/spec/fixtures/services/weather_bug/90210_forecast.xml +1 -0
  49. data/spec/formats/weather_id_spec.rb +10 -5
  50. data/spec/measurements/common_spec.rb +352 -0
  51. data/spec/{data → measurements}/current_spec.rb +40 -103
  52. data/spec/measurements/forecast_array_spec.rb +165 -0
  53. data/spec/measurements/forecast_spec.rb +135 -0
  54. data/spec/{data → measurements}/measurement_spec.rb +86 -107
  55. data/spec/measurements/night_measurement_spec.rb +49 -0
  56. data/spec/query_spec.rb +12 -2
  57. data/spec/spec_helper.rb +28 -1
  58. data/spec/weather_services/google_spec.rb +27 -117
  59. data/spec/weather_services/services_spec.rb +49 -1024
  60. data/spec/weather_services/weather_bug_spec.rb +274 -0
  61. data/spec/weather_services/weather_dot_com_spec.rb +45 -125
  62. data/spec/weather_services/wunderground_spec.rb +42 -136
  63. data/spec/weather_services/yahoo_spec.rb +26 -116
  64. data/spec/weather_spec.rb +45 -45
  65. metadata +27 -11
  66. data/lib/barometer/data/forecast.rb +0 -84
  67. data/lib/barometer/data/night.rb +0 -69
  68. data/lib/barometer/extensions/graticule.rb +0 -51
  69. data/spec/data/forecast_spec.rb +0 -192
  70. data/spec/data/night_measurement_spec.rb +0 -136
@@ -26,7 +26,10 @@ module Barometer
26
26
  #
27
27
  pre_query = nil
28
28
  if original_query.format == :weather_id
29
- pre_query = Query::Format::WeatherID.reverse(original_query)
29
+ unless pre_query = original_query.get_conversion(Query::Format::Geocode.format)
30
+ pre_query = Query::Format::WeatherID.reverse(original_query)
31
+ original_query.post_conversion(pre_query)
32
+ end
30
33
  end
31
34
 
32
35
  # convert & adjust
@@ -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