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.
Files changed (61) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +266 -0
  3. data/VERSION.yml +4 -0
  4. data/bin/barometer +63 -0
  5. data/lib/barometer.rb +52 -0
  6. data/lib/barometer/base.rb +52 -0
  7. data/lib/barometer/data.rb +15 -0
  8. data/lib/barometer/data/current.rb +93 -0
  9. data/lib/barometer/data/distance.rb +131 -0
  10. data/lib/barometer/data/forecast.rb +66 -0
  11. data/lib/barometer/data/geo.rb +98 -0
  12. data/lib/barometer/data/location.rb +20 -0
  13. data/lib/barometer/data/measurement.rb +161 -0
  14. data/lib/barometer/data/pressure.rb +133 -0
  15. data/lib/barometer/data/speed.rb +147 -0
  16. data/lib/barometer/data/sun.rb +35 -0
  17. data/lib/barometer/data/temperature.rb +164 -0
  18. data/lib/barometer/data/units.rb +55 -0
  19. data/lib/barometer/data/zone.rb +124 -0
  20. data/lib/barometer/extensions/graticule.rb +50 -0
  21. data/lib/barometer/extensions/httparty.rb +21 -0
  22. data/lib/barometer/query.rb +228 -0
  23. data/lib/barometer/services.rb +6 -0
  24. data/lib/barometer/services/google.rb +146 -0
  25. data/lib/barometer/services/noaa.rb +6 -0
  26. data/lib/barometer/services/service.rb +324 -0
  27. data/lib/barometer/services/weather_bug.rb +6 -0
  28. data/lib/barometer/services/weather_dot_com.rb +6 -0
  29. data/lib/barometer/services/wunderground.rb +285 -0
  30. data/lib/barometer/services/yahoo.rb +274 -0
  31. data/lib/barometer/weather.rb +187 -0
  32. data/spec/barometer_spec.rb +162 -0
  33. data/spec/data_current_spec.rb +225 -0
  34. data/spec/data_distance_spec.rb +336 -0
  35. data/spec/data_forecast_spec.rb +150 -0
  36. data/spec/data_geo_spec.rb +90 -0
  37. data/spec/data_location_spec.rb +59 -0
  38. data/spec/data_measurement_spec.rb +411 -0
  39. data/spec/data_pressure_spec.rb +336 -0
  40. data/spec/data_speed_spec.rb +374 -0
  41. data/spec/data_sun_spec.rb +76 -0
  42. data/spec/data_temperature_spec.rb +396 -0
  43. data/spec/data_zone_spec.rb +133 -0
  44. data/spec/fixtures/current_calgary_ab.xml +1 -0
  45. data/spec/fixtures/forecast_calgary_ab.xml +1 -0
  46. data/spec/fixtures/geocode_40_73.xml +1 -0
  47. data/spec/fixtures/geocode_90210.xml +1 -0
  48. data/spec/fixtures/geocode_T5B4M9.xml +1 -0
  49. data/spec/fixtures/geocode_calgary_ab.xml +1 -0
  50. data/spec/fixtures/geocode_newyork_ny.xml +1 -0
  51. data/spec/fixtures/google_calgary_ab.xml +1 -0
  52. data/spec/fixtures/yahoo_90210.xml +1 -0
  53. data/spec/query_spec.rb +469 -0
  54. data/spec/service_google_spec.rb +144 -0
  55. data/spec/service_wunderground_spec.rb +330 -0
  56. data/spec/service_yahoo_spec.rb +299 -0
  57. data/spec/services_spec.rb +1106 -0
  58. data/spec/spec_helper.rb +14 -0
  59. data/spec/units_spec.rb +101 -0
  60. data/spec/weather_spec.rb +265 -0
  61. metadata +119 -0
@@ -0,0 +1,133 @@
1
+ module Barometer
2
+ #
3
+ # A simple Pressure 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: the metric units for pressure aren't commonly used, except
12
+ # that this class was designed for storing weather data,
13
+ # and it seems that it is more common in this case
14
+ #
15
+ class Pressure < Barometer::Units
16
+
17
+ METRIC_UNITS = "mb"
18
+ IMPERIAL_UNITS = "in"
19
+
20
+ attr_accessor :millibars, :inches
21
+
22
+ def initialize(metric=true)
23
+ @millibars = nil
24
+ @inches = nil
25
+ super(metric)
26
+ end
27
+
28
+ def metric_default=(value); self.mb = value; end
29
+ def imperial_default=(value); self.in = value; end
30
+
31
+ #
32
+ # CONVERTERS
33
+ #
34
+
35
+ def self.mb_to_in(mb)
36
+ return nil unless mb && (mb.is_a?(Integer) || mb.is_a?(Float))
37
+ mb.to_f * 0.02953
38
+ end
39
+
40
+ def self.in_to_mb(inches)
41
+ return nil unless inches &&
42
+ (inches.is_a?(Integer) || inches.is_a?(Float))
43
+ inches.to_f * 33.8639
44
+ end
45
+
46
+ #
47
+ # ACCESSORS
48
+ #
49
+
50
+ # store millibars
51
+ def mb=(mb)
52
+ return if !mb || !(mb.is_a?(Integer) || mb.is_a?(Float))
53
+ @millibars = mb.to_f
54
+ self.update_inches(mb.to_f)
55
+ end
56
+
57
+ # store inches
58
+ def in=(inches)
59
+ return if !inches || !(inches.is_a?(Integer) || inches.is_a?(Float))
60
+ @inches = inches.to_f
61
+ self.update_millibars(inches.to_f)
62
+ end
63
+
64
+ # return the stored millibars or convert from inches
65
+ def mb(as_integer=true)
66
+ mb = (@millibars || Pressure.in_to_mb(@inches))
67
+ mb ? (as_integer ? mb.to_i : (100*mb).round/100.0) : nil
68
+ end
69
+
70
+ # return the stored inches or convert from millibars
71
+ def in(as_integer=true)
72
+ inches = (@inches || Pressure.mb_to_in(@millibars))
73
+ inches ? (as_integer ? inches.to_i : (100*inches).round/100.0) : nil
74
+ end
75
+
76
+ #
77
+ # OPERATORS
78
+ #
79
+
80
+ def <=>(other)
81
+ self.mb <=> other.mb
82
+ end
83
+
84
+ #
85
+ # HELPERS
86
+ #
87
+
88
+ # will just return the value (no units)
89
+ def to_i(metric=nil)
90
+ (metric || (metric.nil? && self.metric?)) ? self.mb : self.in
91
+ end
92
+
93
+ # will just return the value (no units) with more precision
94
+ def to_f(metric=nil)
95
+ (metric || (metric.nil? && self.metric?)) ? self.mb(false) : self.in(false)
96
+ end
97
+
98
+ # will return the value with units
99
+ def to_s(metric=nil)
100
+ (metric || (metric.nil? && self.metric?)) ? "#{self.mb} #{METRIC_UNITS}" : "#{self.in} #{IMPERIAL_UNITS}"
101
+ end
102
+
103
+ # will just return the units (no value)
104
+ def units(metric=nil)
105
+ (metric || (metric.nil? && self.metric?)) ? METRIC_UNITS : IMPERIAL_UNITS
106
+ end
107
+
108
+ # when we set inches, it is possible the a non-equivalent value of
109
+ # millibars remains. if so, clear it.
110
+ def update_millibars(inches)
111
+ return unless @millibars
112
+ difference = Pressure.in_to_mb(inches.to_f) - @millibars
113
+ # only clear millibars if the stored millibars is off be more then 1 unit
114
+ # then the conversion of inches
115
+ @millibars = nil unless difference.abs <= 1.0
116
+ end
117
+
118
+ # when we set millibars, it is possible the a non-equivalent value of
119
+ # inches remains. if so, clear it.
120
+ def update_inches(mb)
121
+ return unless @inches
122
+ difference = Pressure.mb_to_in(mb.to_f) - @inches
123
+ # only clear inches if the stored inches is off be more then 1 unit
124
+ # then the conversion of millibars
125
+ @inches = nil unless difference.abs <= 1.0
126
+ end
127
+
128
+ def nil?
129
+ (@millibars || @inches) ? false : true
130
+ end
131
+
132
+ end
133
+ end
@@ -0,0 +1,147 @@
1
+ module Barometer
2
+ #
3
+ # A simple Speed 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
+ # Speed is a vector, thus it has a perticular direction, although
10
+ # the direction is independent of the units
11
+ #
12
+ # All comparison operations will be done in metric
13
+ #
14
+ # NOTE: this currently only supports the scale of
15
+ # kilometers (km) and miles (m) per hour. There is currently
16
+ # no way to scale to smaller units (eg km -> m -> mm)
17
+ class Speed < Barometer::Units
18
+
19
+ METRIC_UNITS = "kph"
20
+ IMPERIAL_UNITS = "mph"
21
+
22
+ attr_accessor :kilometers, :miles
23
+ attr_accessor :degrees, :direction
24
+
25
+ def initialize(metric=true)
26
+ @kilometers = nil
27
+ @miles = nil
28
+ @degrees = nil
29
+ @direction = nil
30
+ super(metric)
31
+ end
32
+
33
+ def metric_default=(value); self.kph = value; end
34
+ def imperial_default=(value); self.mph = value; end
35
+
36
+ #
37
+ # CONVERTERS
38
+ #
39
+
40
+ def self.km_to_m(km)
41
+ return nil unless km && (km.is_a?(Integer) || km.is_a?(Float))
42
+ km.to_f * 0.622
43
+ end
44
+
45
+ def self.m_to_km(m)
46
+ return nil unless m && (m.is_a?(Integer) || m.is_a?(Float))
47
+ m.to_f * 1.609
48
+ end
49
+
50
+ #
51
+ # ACCESSORS
52
+ #
53
+
54
+ # store kilometers per hour
55
+ def kph=(kph)
56
+ return if !kph || !(kph.is_a?(Integer) || kph.is_a?(Float))
57
+ @kilometers = kph.to_f
58
+ self.update_miles(kph.to_f)
59
+ end
60
+
61
+ # store miles per hour
62
+ def mph=(mph)
63
+ return if !mph || !(mph.is_a?(Integer) || mph.is_a?(Float))
64
+ @miles = mph.to_f
65
+ self.update_kilometers(mph.to_f)
66
+ end
67
+
68
+ def direction=(direction)
69
+ return if !direction || !direction.is_a?(String)
70
+ @direction = direction
71
+ end
72
+
73
+ def degrees=(degrees)
74
+ return if !degrees || !(degrees.is_a?(Integer) || degrees.is_a?(Float))
75
+ @degrees = degrees
76
+ end
77
+
78
+ # return the stored kilometers or convert from miles
79
+ def kph(as_integer=true)
80
+ km = (@kilometers || Speed.m_to_km(@miles))
81
+ km ? (as_integer ? km.to_i : (100*km).round/100.0) : nil
82
+ end
83
+
84
+ # return the stored miles or convert from kilometers
85
+ def mph(as_integer=true)
86
+ m = (@miles || Speed.km_to_m(@kilometers))
87
+ m ? (as_integer ? m.to_i : (100*m).round/100.0) : nil
88
+ end
89
+
90
+ #
91
+ # OPERATORS
92
+ #
93
+
94
+ def <=>(other)
95
+ self.kph <=> other.kph
96
+ end
97
+
98
+ #
99
+ # HELPERS
100
+ #
101
+
102
+ # will just return the value (no units)
103
+ def to_i(metric=nil)
104
+ (metric || (metric.nil? && self.metric?)) ? self.kph : self.mph
105
+ end
106
+
107
+ # will just return the value (no units) with more precision
108
+ def to_f(metric=nil)
109
+ (metric || (metric.nil? && self.metric?)) ? self.kph(false) : self.mph(false)
110
+ end
111
+
112
+ # will return the value with units
113
+ def to_s(metric=nil)
114
+ (metric || (metric.nil? && self.metric?)) ? "#{self.kph} #{METRIC_UNITS}" : "#{self.mph} #{IMPERIAL_UNITS}"
115
+ end
116
+
117
+ # will just return the units (no value)
118
+ def units(metric=nil)
119
+ (metric || (metric.nil? && self.metric?)) ? METRIC_UNITS : IMPERIAL_UNITS
120
+ end
121
+
122
+ # when we set miles, it is possible the a non-equivalent value of
123
+ # kilometers remains. if so, clear it.
124
+ def update_kilometers(m)
125
+ return unless @kilometers
126
+ difference = Speed.m_to_km(m.to_f) - @kilometers
127
+ # only clear kilometers if the stored kilometers is off be more then 1 unit
128
+ # then the conversion of miles
129
+ @kilometers = nil unless difference.abs <= 1.0
130
+ end
131
+
132
+ # when we set kilometers, it is possible the a non-equivalent value of
133
+ # miles remains. if so, clear it.
134
+ def update_miles(km)
135
+ return unless @miles
136
+ difference = Speed.km_to_m(km.to_f) - @miles
137
+ # only clear miles if the stored miles is off be more then 1 unit
138
+ # then the conversion of kilometers
139
+ @miles = nil unless difference.abs <= 1.0
140
+ end
141
+
142
+ def nil?
143
+ (@kilometers || @miles) ? false : true
144
+ end
145
+
146
+ end
147
+ end
@@ -0,0 +1,35 @@
1
+ module Barometer
2
+ #
3
+ # A simple Sun class
4
+ #
5
+ # Used to store sunrise and sunset information
6
+ #
7
+ class Sun
8
+
9
+ def initialize(rise=nil, set=nil)
10
+ raise ArgumentError unless (rise.is_a?(Time) || rise.nil?)
11
+ raise ArgumentError unless (set.is_a?(Time) || set.nil?)
12
+ @rise_utc = rise
13
+ @set_utc = set
14
+ end
15
+
16
+ def rise; @rise_utc; end
17
+ def set; @set_utc; end
18
+
19
+ # useful for incrementing the sunrise and sunset times by exactly
20
+ # N days ... used when using the same sun data for other days
21
+ def self.add_days!(sun, n=1)
22
+ raise ArgumentError unless sun.is_a?(Barometer::Sun)
23
+ raise ArgumentError unless n.is_a?(Fixnum)
24
+ seconds_to_add = 60*60*24*n
25
+ rise_utc = sun.rise + seconds_to_add
26
+ set_utc = sun.set + seconds_to_add
27
+ self.new(rise_utc, set_utc)
28
+ end
29
+
30
+ def nil?
31
+ (@rise_utc || @set_utc) ? false : true
32
+ end
33
+
34
+ end
35
+ end
@@ -0,0 +1,164 @@
1
+ module Barometer
2
+ #
3
+ # A simple Temperature 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 the absolute
10
+ # scale of Kelvin (K)
11
+ #
12
+ class Temperature < Barometer::Units
13
+
14
+ METRIC_UNITS = "C"
15
+ IMPERIAL_UNITS = "F"
16
+
17
+ attr_accessor :celsius, :fahrenheit, :kelvin
18
+
19
+ def initialize(metric=true)
20
+ @celsius = nil
21
+ @fahrenheit = nil
22
+ @kelvin = nil
23
+ super(metric)
24
+ end
25
+
26
+ def metric_default=(value); self.c = value; end
27
+ def imperial_default=(value); self.f = value; end
28
+
29
+ #
30
+ # CONVERTERS
31
+ #
32
+
33
+ def self.c_to_k(c)
34
+ return nil unless c && (c.is_a?(Integer) || c.is_a?(Float))
35
+ 273.15 + c.to_f
36
+ end
37
+
38
+ # Tf = (9/5)*Tc+32
39
+ def self.c_to_f(c)
40
+ return nil unless c && (c.is_a?(Integer) || c.is_a?(Float))
41
+ ((9.0/5.0)*c.to_f)+32.0
42
+ end
43
+
44
+ # Tc = (5/9)*(Tf-32)
45
+ def self.f_to_c(f)
46
+ return nil unless f && (f.is_a?(Integer) || f.is_a?(Float))
47
+ (5.0/9.0)*(f.to_f-32.0)
48
+ end
49
+
50
+ def self.f_to_k(f)
51
+ return nil unless f && (f.is_a?(Integer) || f.is_a?(Float))
52
+ c = self.f_to_c(f.to_f)
53
+ self.c_to_k(c)
54
+ end
55
+
56
+ def self.k_to_c(k)
57
+ return nil unless k && (k.is_a?(Integer) || k.is_a?(Float))
58
+ k.to_f - 273.15
59
+ end
60
+
61
+ def self.k_to_f(k)
62
+ return nil unless k && (k.is_a?(Integer) || k.is_a?(Float))
63
+ c = self.k_to_c(k.to_f)
64
+ self.c_to_f(c)
65
+ end
66
+
67
+ #
68
+ # ACCESSORS
69
+ #
70
+
71
+ # store celsius and kelvin
72
+ def c=(c)
73
+ return if !c || !(c.is_a?(Integer) || c.is_a?(Float))
74
+ @celsius = c.to_f
75
+ @kelvin = Temperature.c_to_k(c.to_f)
76
+ self.update_fahrenheit(c.to_f)
77
+ end
78
+
79
+ # store fahrenheit and kelvin
80
+ def f=(f)
81
+ return if !f || !(f.is_a?(Integer) || f.is_a?(Float))
82
+ @fahrenheit = f.to_f
83
+ @kelvin = Temperature.f_to_k(f.to_f)
84
+ self.update_celsius(f.to_f)
85
+ end
86
+
87
+ # store kelvin, convert to all
88
+ def k=(k)
89
+ return if !k || !(k.is_a?(Integer) || k.is_a?(Float))
90
+ @kelvin = k.to_f
91
+ @celsius = Temperature.k_to_c(k.to_f)
92
+ @fahrenheit = Temperature.k_to_f(k.to_f)
93
+ end
94
+
95
+ # return the stored celsius or convert from Kelvin
96
+ def c(as_integer=true)
97
+ c = (@celsius || Temperature.k_to_c(@kelvin))
98
+ c ? (as_integer ? c.to_i : (100*c).round/100.0) : nil
99
+ end
100
+
101
+ # return the stored fahrenheit or convert from Kelvin
102
+ def f(as_integer=true)
103
+ f = (@fahrenheit || Temperature.k_to_f(@kelvin))
104
+ f ? (as_integer ? f.to_i : (100*f).round/100.0) : nil
105
+ end
106
+
107
+ #
108
+ # OPERATORS
109
+ #
110
+
111
+ def <=>(other)
112
+ @kelvin <=> other.kelvin
113
+ end
114
+
115
+ #
116
+ # HELPERS
117
+ #
118
+
119
+ # will just return the value (no units)
120
+ def to_i(metric=nil)
121
+ (metric || (metric.nil? && self.metric?)) ? self.c : self.f
122
+ end
123
+
124
+ # will just return the value (no units) with more precision
125
+ def to_f(metric=nil)
126
+ (metric || (metric.nil? && self.metric?)) ? self.c(false) : self.f(false)
127
+ end
128
+
129
+ # will return the value with units
130
+ def to_s(metric=nil)
131
+ (metric || (metric.nil? && self.metric?)) ? "#{self.c} #{METRIC_UNITS}" : "#{self.f} #{IMPERIAL_UNITS}"
132
+ end
133
+
134
+ # will just return the units (no value)
135
+ def units(metric=nil)
136
+ (metric || (metric.nil? && self.metric?)) ? METRIC_UNITS : IMPERIAL_UNITS
137
+ end
138
+
139
+ # when we set fahrenheit, it is possible the a non-equivalent value of
140
+ # celsius remains. if so, clear it.
141
+ def update_celsius(f)
142
+ return unless @celsius
143
+ difference = Temperature.f_to_c(f.to_f) - @celsius
144
+ # only clear celsius if the stored celsius is off be more then 1 degree
145
+ # then the conversion of fahrenheit
146
+ @celsius = nil unless difference.abs <= 1.0
147
+ end
148
+
149
+ # when we set celsius, it is possible the a non-equivalent value of
150
+ # fahrenheit remains. if so, clear it.
151
+ def update_fahrenheit(c)
152
+ return unless @fahrenheit
153
+ difference = Temperature.c_to_f(c.to_f) - @fahrenheit
154
+ # only clear fahrenheit if the stored fahrenheit is off be more then 1 degree
155
+ # then the conversion of celsius
156
+ @fahrenheit = nil unless difference.abs <= 1.0
157
+ end
158
+
159
+ def nil?
160
+ (@celsius || @fahrenheit || @kelvin) ? false : true
161
+ end
162
+
163
+ end
164
+ end