barometer 0.6.1 → 0.6.2

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 (42) hide show
  1. data/README.rdoc +1 -1
  2. data/VERSION.yml +1 -1
  3. data/bin/barometer +4 -12
  4. data/lib/barometer/data.rb +2 -5
  5. data/lib/barometer/data/local_datetime.rb +2 -2
  6. data/lib/barometer/measurements/measurement.rb +6 -6
  7. data/lib/barometer/measurements/result.rb +207 -0
  8. data/lib/barometer/measurements/{forecast_array.rb → result_array.rb} +16 -13
  9. data/lib/barometer/translations/weather_country_codes.yml +3 -3
  10. data/lib/barometer/weather_services/google.rb +3 -3
  11. data/lib/barometer/weather_services/weather_bug.rb +3 -3
  12. data/lib/barometer/weather_services/weather_dot_com.rb +65 -38
  13. data/lib/barometer/weather_services/wunderground.rb +3 -3
  14. data/lib/barometer/weather_services/yahoo.rb +3 -3
  15. data/lib/demometer/demometer.rb +2 -2
  16. data/lib/demometer/public/css/master.css +4 -75
  17. data/lib/demometer/public/css/print.css +1 -2
  18. data/lib/demometer/public/css/syntax.css +1 -2
  19. data/lib/demometer/views/about.erb +1 -1
  20. data/lib/demometer/views/contributing.erb +4 -4
  21. data/lib/demometer/views/index.erb +8 -9
  22. data/lib/demometer/views/layout.erb +1 -2
  23. data/spec/measurements/measurement_spec.rb +29 -53
  24. data/spec/measurements/{forecast_array_spec.rb → result_array_spec.rb} +8 -8
  25. data/spec/measurements/result_spec.rb +660 -0
  26. data/spec/spec_helper.rb +1 -0
  27. data/spec/weather_services/google_spec.rb +4 -4
  28. data/spec/weather_services/services_spec.rb +1 -1
  29. data/spec/weather_services/weather_bug_spec.rb +3 -3
  30. data/spec/weather_services/weather_dot_com_spec.rb +19 -22
  31. data/spec/weather_services/wunderground_spec.rb +2 -2
  32. data/spec/weather_services/yahoo_spec.rb +2 -2
  33. data/spec/weather_spec.rb +14 -39
  34. metadata +6 -12
  35. data/lib/barometer/measurements/common.rb +0 -113
  36. data/lib/barometer/measurements/current.rb +0 -76
  37. data/lib/barometer/measurements/forecast.rb +0 -62
  38. data/lib/barometer/measurements/night.rb +0 -27
  39. data/spec/measurements/common_spec.rb +0 -352
  40. data/spec/measurements/current_spec.rb +0 -186
  41. data/spec/measurements/forecast_spec.rb +0 -135
  42. data/spec/measurements/night_measurement_spec.rb +0 -49
data/README.rdoc CHANGED
@@ -15,7 +15,7 @@ this.
15
15
 
16
16
  == version
17
17
 
18
- Version 0.6.0 is the current release of this gem.
18
+ Version 0.6.2 is the current release of this gem.
19
19
  The gem is available from github (attack-barometer) or rubyforge (barometer).
20
20
  It is fully functional (for five weather service APIs).
21
21
 
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 1
2
+ :patch: 2
3
3
  :major: 0
4
4
  :minor: 6
data/bin/barometer CHANGED
@@ -66,7 +66,7 @@ require 'yaml'
66
66
 
67
67
  # file where API keys are stored
68
68
  KEY_FILE = File.expand_path(File.join('~', '.barometer'))
69
- BAROMETER_VERSION = '0.6.0'
69
+ BAROMETER_VERSION = '0.6.2'
70
70
 
71
71
  class App
72
72
 
@@ -403,22 +403,14 @@ def pretty_forecast(f)
403
403
  return unless f
404
404
  section("FOR: #{f.date}", 3) do
405
405
  pretty_hash({
406
- "Date" => f.date, "Icon" => f.icon,
406
+ "Valid From" => f.valid_start_date.to_s(true),
407
+ "Valid Until" => f.valid_end_date.to_s(true),
408
+ "Icon" => f.icon, "Description" => f.description,
407
409
  "Condition" => f.condition, "High" => f.high,
408
410
  "Low" => f.low, "POP" => f.pop, "Humidity" => f.humidity })
409
411
  pretty_hash({ "Wind" => f.wind, "Wind Direction" => f.wind.direction,
410
412
  "Wind Degrees" => f.wind.degrees }) if f.wind
411
413
  pretty_hash({ "Sun Rise" => f.sun.rise, "Sun Set" => f.sun.set }) if f.sun
412
- if f.night
413
- puts
414
- title("NIGHT", 4)
415
- pretty_hash({
416
- "Date" => f.night.date, "Icon" => f.night.icon,
417
- "Condition" => f.night.condition, "POP" => f.night.pop,
418
- "Humidity" => f.night.humidity })
419
- pretty_hash({ "Wind" => f.night.wind, "Wind Direction" => f.night.wind.direction,
420
- "Wind Degrees" => f.night.wind.degrees }) if f.night.wind
421
- end
422
414
  end
423
415
  end
424
416
 
@@ -17,8 +17,5 @@ require 'data/local_datetime'
17
17
  # measurements
18
18
  #
19
19
  require 'measurements/measurement'
20
- require 'measurements/common'
21
- require 'measurements/current'
22
- require 'measurements/forecast_array'
23
- require 'measurements/forecast'
24
- require 'measurements/night'
20
+ require 'measurements/result'
21
+ require 'measurements/result_array'
@@ -101,8 +101,8 @@ module Barometer
101
101
  end
102
102
  raise ArgumentError unless the_other.is_a?(Data::LocalDateTime) || the_other.is_a?(Data::LocalTime)
103
103
 
104
- if (other.is_a?(String) || other.is_a?(Time) || other.is_a?(DateTime)) &&
105
- the_other.is_a?(Data::LocalDateTime)
104
+ if ((other.is_a?(String) || other.is_a?(Time) || other.is_a?(DateTime)) &&
105
+ the_other.is_a?(Data::LocalDateTime)) || other.is_a?(Data::LocalDateTime)
106
106
  # we are counting days + seconds
107
107
  if (_total_days <=> the_other._total_days) == 0
108
108
  return total_seconds <=> the_other.total_seconds
@@ -3,8 +3,8 @@ module Barometer
3
3
  # Measurement
4
4
  # a class that holds the response from a weather service
5
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
6
+ # its main purpose is to hold all the data collected from a single weather
7
+ # service as it is passed to the weather object
8
8
  #
9
9
  # this response includes
10
10
  # - current weather data (using the CurrentMeasurement class)
@@ -31,8 +31,8 @@ module Barometer
31
31
  end
32
32
 
33
33
  def success!
34
- current && current.temperature &&
35
- !current.temperature.c.nil? && @success = true
34
+ current && current.temperature &&
35
+ !current.temperature.c.nil? && @success = true
36
36
  end
37
37
 
38
38
  def stamp!; @utc_time_stamp = Time.now.utc; end
@@ -95,14 +95,14 @@ module Barometer
95
95
  end
96
96
 
97
97
  def current=(current)
98
- raise ArgumentError unless current.is_a?(Measurement::Current)
98
+ raise ArgumentError unless current.is_a?(Measurement::Result)
99
99
  @current = current
100
100
  self.stamp!
101
101
  self.success!
102
102
  end
103
103
 
104
104
  def forecast=(forecast)
105
- raise ArgumentError unless forecast.is_a?(Measurement::ForecastArray)
105
+ raise ArgumentError unless forecast.is_a?(Measurement::ResultArray)
106
106
  @forecast = forecast
107
107
  end
108
108
 
@@ -0,0 +1,207 @@
1
+ module Barometer
2
+ #
3
+ # Result Measurement
4
+ # a data class for resulting weather conditions
5
+ #
6
+ # This is basically a data holding class for the resulting weather
7
+ # conditions.
8
+ #
9
+ class Measurement::Result
10
+
11
+ attr_reader :current_at, :updated_at
12
+ attr_reader :valid_start_date, :valid_end_date, :date
13
+ attr_reader :humidity, :icon, :condition
14
+ attr_reader :temperature, :dew_point, :heat_index, :wind_chill
15
+ attr_reader :low, :high, :pop
16
+ attr_reader :wind, :sun, :pressure, :visibility
17
+ attr_accessor :metric, :description
18
+
19
+ def initialize(metric=true); @metric = metric; end
20
+
21
+ # accessors (with input checking)
22
+ #
23
+ def temperature=(temperature)
24
+ raise ArgumentError unless temperature.is_a?(Data::Temperature)
25
+ @temperature = temperature
26
+ end
27
+
28
+ def dew_point=(dew_point)
29
+ raise ArgumentError unless dew_point.is_a?(Data::Temperature)
30
+ @dew_point = dew_point
31
+ end
32
+
33
+ def heat_index=(heat_index)
34
+ raise ArgumentError unless heat_index.is_a?(Data::Temperature)
35
+ @heat_index = heat_index
36
+ end
37
+
38
+ def wind_chill=(wind_chill)
39
+ raise ArgumentError unless wind_chill.is_a?(Data::Temperature)
40
+ @wind_chill = wind_chill
41
+ end
42
+
43
+ def pressure=(pressure)
44
+ raise ArgumentError unless pressure.is_a?(Data::Pressure)
45
+ @pressure = pressure
46
+ end
47
+
48
+ def visibility=(visibility)
49
+ raise ArgumentError unless visibility.is_a?(Data::Distance)
50
+ @visibility = visibility
51
+ end
52
+
53
+ def current_at=(current_at)
54
+ raise ArgumentError unless (current_at.is_a?(Data::LocalTime) || current_at.is_a?(Data::LocalDateTime))
55
+ @current_at = current_at
56
+ end
57
+
58
+ def updated_at=(updated_at)
59
+ raise ArgumentError unless (updated_at.is_a?(Data::LocalTime) || updated_at.is_a?(Data::LocalDateTime))
60
+ @updated_at = updated_at
61
+ end
62
+
63
+ def date=(date)
64
+ raise ArgumentError unless date.is_a?(Date)
65
+ @date = date
66
+ @valid_start_date = Data::LocalDateTime.new(date.year,date.month,date.day,0,0,0)
67
+ @valid_end_date = Data::LocalDateTime.new(date.year,date.month,date.day,23,59,59)
68
+ end
69
+
70
+ def valid_start_date=(date)
71
+ raise ArgumentError unless date.is_a?(Data::LocalDateTime)
72
+ @valid_start_date = date
73
+ end
74
+
75
+ def valid_end_date=(date)
76
+ raise ArgumentError unless date.is_a?(Data::LocalDateTime)
77
+ @valid_end_date = date
78
+ end
79
+
80
+ def high=(high)
81
+ raise ArgumentError unless high.is_a?(Data::Temperature)
82
+ @high = high
83
+ end
84
+
85
+ def low=(low)
86
+ raise ArgumentError unless low.is_a?(Data::Temperature)
87
+ @low = low
88
+ end
89
+
90
+ def pop=(pop)
91
+ raise ArgumentError unless pop.is_a?(Fixnum)
92
+ @pop = pop
93
+ end
94
+
95
+ def humidity=(humidity)
96
+ raise ArgumentError unless
97
+ (humidity.is_a?(Fixnum) || humidity.is_a?(Float))
98
+ @humidity = humidity
99
+ end
100
+
101
+ def icon=(icon)
102
+ raise ArgumentError unless icon.is_a?(String)
103
+ @icon = icon
104
+ end
105
+
106
+ def condition=(condition)
107
+ raise ArgumentError unless condition.is_a?(String)
108
+ @condition = condition
109
+ end
110
+
111
+ def wind=(wind)
112
+ raise ArgumentError unless wind.is_a?(Data::Speed)
113
+ @wind = wind
114
+ end
115
+
116
+ def sun=(sun)
117
+ raise ArgumentError unless (sun.is_a?(Data::Sun) || sun.nil?)
118
+ @sun = sun
119
+ end
120
+
121
+ #
122
+ # answer simple questions
123
+ #
124
+
125
+ def windy?(threshold=10)
126
+ raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
127
+ return nil unless wind?
128
+ wind.to_f(metric?) >= threshold.to_f
129
+ end
130
+
131
+ def day?(time)
132
+ return nil unless time && sun?
133
+ sun.after_rise?(time) && sun.before_set?(time)
134
+ end
135
+
136
+ def sunny?(time, sunny_icons=nil)
137
+ return nil unless time
138
+ is_day = day?(time)
139
+ return nil if is_day.nil?
140
+ is_day && _sunny_by_icon?(sunny_icons)
141
+ end
142
+
143
+ def wet?(wet_icons=nil, pop_threshold=50, humidity_threshold=99)
144
+ result = nil
145
+ result ||= _wet_by_pop?(pop_threshold) if pop?
146
+ result ||= _wet_by_icon?(wet_icons) if icon?
147
+ result ||= _wet_by_humidity?(humidity_threshold) if humidity?
148
+ result ||= _wet_by_dewpoint? if (dew_point? && temperature?)
149
+ result
150
+ end
151
+
152
+ #
153
+ # helpers
154
+ #
155
+
156
+ def metric?; metric; end
157
+
158
+ def for_datetime?(datetime)
159
+ raise ArgumentError unless datetime.is_a?(Data::LocalDateTime)
160
+ datetime >= @valid_start_date && datetime <= @valid_end_date
161
+ end
162
+
163
+ # creates "?" helpers for all attributes (which maps to nil?)
164
+ #
165
+ def method_missing(method,*args)
166
+ # if the method ends in ?, then strip it off and see if we
167
+ # respond to the method without the ?
168
+ if (call_method = method.to_s.chomp!("?")) && respond_to?(call_method)
169
+ return send(call_method).nil? ? false : true
170
+ else
171
+ super(method,*args)
172
+ end
173
+ end
174
+
175
+ private
176
+
177
+ def _wet_by_dewpoint?
178
+ return nil unless dew_point? && temperature?
179
+ temperature.to_f(metric?) <= dew_point.to_f(metric?)
180
+ end
181
+
182
+ def _wet_by_pop?(threshold=50)
183
+ raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
184
+ return nil unless pop?
185
+ pop.to_f >= threshold.to_f
186
+ end
187
+
188
+ def _wet_by_humidity?(threshold=99)
189
+ raise ArgumentError unless (threshold.is_a?(Fixnum) || threshold.is_a?(Float))
190
+ return nil unless humidity?
191
+ humidity.to_f >= threshold.to_f
192
+ end
193
+
194
+ def _wet_by_icon?(wet_icons=nil)
195
+ raise ArgumentError unless (wet_icons.nil? || wet_icons.is_a?(Array))
196
+ return nil unless (icon? && wet_icons)
197
+ wet_icons.include?(icon.to_s.downcase)
198
+ end
199
+
200
+ def _sunny_by_icon?(sunny_icons=nil)
201
+ raise ArgumentError unless (sunny_icons.nil? || sunny_icons.is_a?(Array))
202
+ return nil unless (icon? && sunny_icons)
203
+ sunny_icons.include?(icon.to_s.downcase)
204
+ end
205
+
206
+ end
207
+ end
@@ -1,13 +1,15 @@
1
1
  require 'date'
2
2
  module Barometer
3
3
  #
4
- # Forecast Array
5
- # an array that holds multiple forecasts
4
+ # Result Array
6
5
  #
7
- class Measurement::ForecastArray < Array
6
+ # an array that holds multiple results,
7
+ # with methods for insertion and searching
8
+ #
9
+ class Measurement::ResultArray < Array
8
10
 
9
11
  def <<(forecast)
10
- raise ArgumentError unless forecast.is_a?(Measurement::Forecast)
12
+ raise ArgumentError unless forecast.is_a?(Measurement::Result)
11
13
  super(forecast)
12
14
  end
13
15
 
@@ -17,31 +19,32 @@ module Barometer
17
19
 
18
20
  #
19
21
  # Returns a forecast for a day given by a Date, DateTime,
20
- # Time, or a string that can be parsed to a date
22
+ # Time, or a string that can be parsed to a Data::LocalDateTime
21
23
  #
22
24
  # credit: http://github.com/jdpace/weatherman/
23
25
  #
24
- def for(date)
26
+ def for(datetime)
25
27
 
26
28
  return nil unless self.size > 0
27
29
 
28
30
  # Format date into a Date class
29
- date = case date.class.name
31
+ datetime = case datetime.class.name
30
32
  when 'Date'
31
- date
33
+ # if just given a date, assume a time that will be mid-day
34
+ Data::LocalDateTime.new(datetime.year,datetime.month,datetime.day,12,0,0)
32
35
  when 'Data::LocalDateTime'
33
- date.to_d
36
+ datetime
34
37
  when 'String'
35
- Date.parse(date)
38
+ Data::LocalDateTime.parse(datetime)
36
39
  when 'Time'
37
- Date.new(date.year, date.month, date.day)
40
+ Data::LocalDateTime.parse(datetime)
38
41
  when 'DateTime'
39
- Date.new(date.year, date.month, date.day)
42
+ Data::LocalDateTime.parse(datetime)
40
43
  end
41
44
 
42
45
  day = nil
43
46
  self.each do |f|
44
- day = f if date == f.date
47
+ day = f if f.for_datetime?(datetime)
45
48
  end
46
49
  return day
47
50
  end
@@ -102,7 +102,7 @@ MG : MN
102
102
 
103
103
  WA : NA
104
104
  NT : AN
105
- NU: NI
105
+ NU : NI
106
106
  NG : NE
107
107
  NI : NG
108
108
 
@@ -127,7 +127,7 @@ LO : SK
127
127
  BP : SB
128
128
  SF : ZA
129
129
  SP : ES
130
- CE: LK
130
+ CE : LK
131
131
  SU : SD
132
132
  NS : SR
133
133
  WZ : SZ
@@ -147,7 +147,7 @@ UP : UA
147
147
  UK : GB
148
148
 
149
149
  NH : VU
150
- VM: VN
150
+ VM : VN
151
151
 
152
152
  WI : EH
153
153
 
@@ -52,7 +52,7 @@ module Barometer
52
52
 
53
53
  def self._build_current(data, metric=true)
54
54
  raise ArgumentError unless data.is_a?(Hash)
55
- current = Measurement::Current.new
55
+ current = Measurement::Result.new
56
56
 
57
57
  if data['current_conditions']
58
58
  data = data['current_conditions']
@@ -81,7 +81,7 @@ module Barometer
81
81
  def self._build_forecast(data, metric=true)
82
82
  raise ArgumentError unless data.is_a?(Hash)
83
83
 
84
- forecasts = Measurement::ForecastArray.new
84
+ forecasts = Measurement::ResultArray.new
85
85
  return forecasts unless data && data['forecast_information'] &&
86
86
  data['forecast_information']['forecast_date']
87
87
  start_date = Date.parse(data['forecast_information']['forecast_date']['data'])
@@ -90,7 +90,7 @@ module Barometer
90
90
  # go through each forecast and create an instance
91
91
  d = 0
92
92
  data.each do |forecast|
93
- forecast_measurement = Measurement::Forecast.new
93
+ forecast_measurement = Measurement::Result.new
94
94
  if forecast['icon']
95
95
  icon_match = forecast['icon']['data'].match(/.*\/([A-Za-z_]*)\.png/)
96
96
  forecast_measurement.icon = icon_match[1] if icon_match
@@ -97,7 +97,7 @@ module Barometer
97
97
  def self._build_current(data, metric=true)
98
98
  raise ArgumentError unless data.is_a?(Hash)
99
99
 
100
- current = Measurement::Current.new
100
+ current = Measurement::Result.new
101
101
  # current.updated_at = Data::LocalDateTime.parse(data['observation_time']) if data['observation_time']
102
102
  current.humidity = data['aws:humidity'].to_i
103
103
  current.condition = data['aws:current_condition'] if data['aws:current_condition']
@@ -124,13 +124,13 @@ module Barometer
124
124
 
125
125
  def self._build_forecast(data, metric=true)
126
126
  raise ArgumentError unless data.is_a?(Hash)
127
- forecasts = Measurement::ForecastArray.new
127
+ forecasts = Measurement::ResultArray.new
128
128
  # go through each forecast and create an instance
129
129
  if data && data["aws:forecast"]
130
130
  start_date = Date.parse(data['date'])
131
131
  i = 0
132
132
  data["aws:forecast"].each do |forecast|
133
- forecast_measurement = Measurement::Forecast.new
133
+ forecast_measurement = Measurement::Result.new
134
134
  icon_match = forecast['aws:image'].match(/cond(\d*)\.gif$/)
135
135
  forecast_measurement.icon = icon_match[1].to_i.to_s if icon_match
136
136
  forecast_measurement.date = start_date + i