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
@@ -8,6 +8,7 @@ module Barometer
8
8
 
9
9
  def self.fetch(query)
10
10
  raise ArgumentError unless _is_a_query?(query)
11
+ puts "geocoding: #{query.q}" if Barometer::debug?
11
12
  return nil unless _has_geocode_key?
12
13
  location = self.get(
13
14
  "http://maps.google.com/maps/geo",
@@ -0,0 +1,40 @@
1
+ module Barometer
2
+ #
3
+ # Web Service: Timezone
4
+ #
5
+ # uses geonames.org to obtain the full timezone for given coordinates
6
+ #
7
+ class WebService::Timezone < WebService
8
+
9
+ # get the full timezone for given coordinates
10
+ #
11
+ def self.fetch(latitude, longitude)
12
+ puts "timezone: #{latitude}, #{longitude}"
13
+ return nil unless latitude && longitude
14
+ _fetch_via_wunderground(latitude, longitude)
15
+ end
16
+
17
+ def self._fetch_via_geonames(latitude, longitude)
18
+ response = self.get(
19
+ "http://ws.geonames.org/timezone",
20
+ :query => { :lat => latitude, :lng => longitude },
21
+ :format => :xml,
22
+ :timeout => Barometer.timeout
23
+ )['geonames']['timezone']
24
+ response ? Data::Zone.new(response['timezoneId']) : nil
25
+ end
26
+
27
+ def self._fetch_via_wunderground(latitude, longitude)
28
+ response = self.get(
29
+ "http://api.wunderground.com/auto/wui/geo/ForecastXML/index.xml",
30
+ :query => {:query => "#{latitude},#{longitude}"},
31
+ :format => :xml,
32
+ :timeout => Barometer.timeout
33
+ )['forecast']['simpleforecast']['forecastday'].first
34
+ response ? Data::Zone.new(response['date']['tz_long']) : nil
35
+ end
36
+
37
+ end
38
+ end
39
+
40
+
@@ -9,11 +9,13 @@ module Barometer
9
9
  # get the weather_id for a given query
10
10
  #
11
11
  def self.fetch(query)
12
+ puts "fetch weather_id: #{query.q}" if Barometer::debug?
12
13
  return nil unless query
13
14
  raise ArgumentError unless _is_a_query?(query)
14
- response = self.get(
15
+
16
+ self.get(
15
17
  "http://xoap.weather.com/search/search",
16
- :query => { :where => query.q }, :format => :plain,
18
+ :query => { :where => _adjust_query(query.q) }, :format => :plain,
17
19
  :timeout => Barometer.timeout
18
20
  )
19
21
  end
@@ -21,6 +23,7 @@ module Barometer
21
23
  # get the location_date (geocode) for a given weather_id
22
24
  #
23
25
  def self.reverse(query)
26
+ puts "reverse weather_id: #{query.q}" if Barometer::debug?
24
27
  return nil unless query
25
28
  raise ArgumentError unless _is_a_query?(query)
26
29
  self.get(
@@ -30,6 +33,18 @@ module Barometer
30
33
  :timeout => Barometer.timeout
31
34
  )['rss']['channel']["yweather:location"]
32
35
  end
36
+
37
+ # filter out words that weather.com has trouble geo-locating
38
+ # mostly these are icao related
39
+ #
40
+ def self._adjust_query(query)
41
+ output = query.dup
42
+ words_to_remove = %w(international airport municipal)
43
+ words_to_remove.each do |word|
44
+ output.gsub!(/#{word}/i, "")
45
+ end
46
+ output
47
+ end
33
48
 
34
49
  end
35
50
  end
@@ -32,6 +32,23 @@ class Demometer < Sinatra::Default
32
32
  { :weather_dot_com => { :keys => { :partner => partner_key, :license => license_key } } }
33
33
  end
34
34
 
35
+ def config_weather_bug
36
+ if File.exists?(@@config_file)
37
+ keys = YAML.load_file(@@config_file)
38
+ if keys["weather_bug"] && keys["weather_bug"]["code"]
39
+ code = keys["weather_bug"]["code"].to_s
40
+ else
41
+ raise RunTimeError "no weatherbug.com keys"
42
+ exit
43
+ end
44
+ else
45
+ File.open(@@config_file, 'w') {|f| f << "\weather_bug:\n code: API_CODE" }
46
+ raise RunTimeError "no weatherbug.com keys"
47
+ exit
48
+ end
49
+ { :weather_bug => { :keys => { :code => code } } }
50
+ end
51
+
35
52
  helpers do
36
53
  def data(title, value)
37
54
  return if value.nil?
@@ -58,6 +75,13 @@ class Demometer < Sinatra::Default
58
75
  Barometer::Base.config[1] << config_weather_dot_com
59
76
  end
60
77
 
78
+ # setup weatherbug.com
79
+ if Barometer::Base.config && Barometer::Base.config[1] &&
80
+ Barometer::Base.config[1].include?(:weather_bug)
81
+ Barometer::Base.config[1].delete(:weather_bug)
82
+ Barometer::Base.config[1] << config_weather_bug
83
+ end
84
+
61
85
  if params[:query] && !params[:query][:q].empty?
62
86
  @barometer = Barometer.new(params[:query][:q])
63
87
  @weather = @barometer.measure(metric)
@@ -72,5 +96,9 @@ class Demometer < Sinatra::Default
72
96
  get '/readme.html' do
73
97
  erb :readme
74
98
  end
99
+
100
+ get '/about.html' do
101
+ erb :about
102
+ end
75
103
 
76
104
  end
@@ -1 +1,259 @@
1
- /* nothing to see here */
1
+ /*
2
+ Copyright: Blake Mizerany, www.sinatrarb.com
3
+ Permission Pending
4
+ */
5
+
6
+ body {
7
+ color:#000;
8
+ font-family:'lucida grande', 'lucida sans unicade', sans-serif;
9
+ font-size:100%;
10
+ line-height:1.3;
11
+ background-color:#fff;
12
+ margin:0;
13
+ padding:0;
14
+ }
15
+
16
+ /* HEADER */
17
+ #head {
18
+ text-align:center;
19
+ }
20
+ #head img {
21
+ vertical-align:middle;
22
+ margin:-10px 0 0 -82px;
23
+ padding:0 15px 0 0;
24
+ border:0;
25
+ }
26
+ #head h1 {
27
+ color:#000;
28
+ font-family:'georgia', 'bitstream vera serif', serif;
29
+ font-size:4em;
30
+ font-weight:normal;
31
+ letter-spacing:-3px;
32
+ line-height:1;
33
+ margin:0;
34
+ padding:20px 0 8px 0;
35
+ }
36
+ #head h1 a, #head h1 a:link, #head h1 a:visited, #head h1 a:hover {
37
+ color:#100;
38
+ text-decoration:none;
39
+ }
40
+ #head ul {
41
+ font-size:1.1em;
42
+ font-family:"lucida console", "monaco", "andale mono", "bitstream vera sans mono",
43
+ "consolas", monospace;
44
+ font-weight:normal;
45
+ text-transform:uppercase;
46
+ letter-spacing:2px;
47
+ text-align:center;
48
+ margin:0;
49
+ padding:0 40px 0.25em 40px;
50
+ }
51
+ #head ul li {
52
+ display:inline;
53
+ list-style-type:none;
54
+ padding:0 0.5em 0 0;
55
+ }
56
+ #head ul a, #head ul a:link, #head ul a:visited {
57
+ color:#56534f;
58
+ text-decoration:none;
59
+ }
60
+ #head ul a:hover {
61
+ color:#000;
62
+ text-decoration:underline
63
+ }
64
+
65
+ /* CONTENT */
66
+
67
+ #content {
68
+ color:#333;
69
+ font-size:1.1em;
70
+ max-width:44em;
71
+ min-width:27em;
72
+ margin:7px auto;
73
+ border-top:2px solid #837d7c;
74
+ }
75
+ strong {
76
+ font-weight:bold;
77
+ }
78
+
79
+ /* HEADINGS */
80
+
81
+ h1, h2, h3, h4, h5, h6 {
82
+ color:#000;
83
+ }
84
+ h1, h2 {
85
+ color:#211d1f;
86
+ font-family:'georgia', 'bitstream vera serif', serif;
87
+ font-weight:normal;
88
+ }
89
+ h1 a, h2 a { color:#222 }
90
+ h1 {
91
+ font-size:2.25em;
92
+ letter-spacing:-1px;
93
+ margin-bottom:0;
94
+ }
95
+ h2 {
96
+ font-size:1.5em;
97
+ letter-spacing:-1px;
98
+ margin:1.25em 0 -0.32em 0;
99
+ }
100
+ h3 {
101
+ color:#211d1f;
102
+ font-size:1.02em;
103
+ font-weight:bold;
104
+ margin:1.8em 0 -0.25em 0;
105
+ letter-spacing:-1px;
106
+ }
107
+ h3 a {
108
+ color:#000;
109
+ text-decoration:underline;
110
+ }
111
+
112
+ /* LINKS */
113
+ a {
114
+ color:#000;
115
+ text-decoration:underline;
116
+ }
117
+ a:hover {
118
+ color:#910;
119
+ text-decoration:underline;
120
+ }
121
+ a img {
122
+ border:none;
123
+ }
124
+ a.out {
125
+ background: url('/images/link-out.gif') center right no-repeat;
126
+ padding-right: 12px;
127
+ }
128
+
129
+
130
+ /* CODE */
131
+
132
+ code, pre, textarea, tt {
133
+ font-family:"lucida console", "monaco", "andale mono", "bitstream vera sans mono",
134
+ "consolas", monospace;
135
+ }
136
+ pre {
137
+ font-size:0.85em;
138
+ background:#f4f5f5;
139
+ border:2px solid #d5d0d2;
140
+ padding:0.5em;
141
+ line-height:1.15;
142
+ color:#222;
143
+ }
144
+ code, tt {
145
+ font-size:0.85em;
146
+ color:#444;
147
+ }
148
+ h1 code, h2 code, h3 code, h4 code {
149
+ color:#333;
150
+ }
151
+ pre code {
152
+ font-size:1em;
153
+ color:#222;
154
+ }
155
+
156
+ /* MISC */
157
+
158
+ hr {
159
+ margin:3em 0;
160
+ padding:0;
161
+ color:#eee;
162
+ }
163
+
164
+ /* HOME */
165
+
166
+ body#home {
167
+ background: #fff url(../images/legend.gif) no-repeat fixed right 130px;
168
+ }
169
+ #home #content {
170
+ font-size:1.05em;
171
+ margin:20px 0 0 0;
172
+ padding:0 20px;
173
+ border-width:0;
174
+ }
175
+ #home #head, #home #foot {
176
+ display:none;
177
+ }
178
+ .pipe {
179
+ clear:both;
180
+ padding:50px 0;
181
+ }
182
+ .pipe p {
183
+ color:#000;
184
+ font-size:62px;
185
+ font-family:'georgia', 'bitstream vera serif', serif;
186
+ letter-spacing:-3px;
187
+ line-height:1;
188
+ text-align:right;
189
+ margin:0em 43% 0 0;
190
+ padding:0 60px 0 0;
191
+ }
192
+ .pipe pre {
193
+ float:right;
194
+ background:transparent;
195
+ font-size:28px;
196
+ margin:0;
197
+ padding:5px 0 0 0;
198
+ width:42%;
199
+ border-width:0;
200
+ }
201
+ .pipe pre code {
202
+ color:#666;
203
+ background:transparent;
204
+ }
205
+ .pipe.shell p {
206
+ font-size:56px;
207
+ }
208
+ .pipe.shell pre {
209
+ font-size:18px;
210
+ }
211
+ .pipe.nav p {
212
+ font-size:100px;
213
+ letter-spacing:-6px;
214
+ }
215
+ .pipe.nav pre {
216
+ font-size:36px;
217
+ padding-top:20px;
218
+ text-transform:uppercase;
219
+ letter-spacing:4px;
220
+ line-height:1.25;
221
+ }
222
+ .pipe.nav {
223
+ padding:25px 0 50px 0;
224
+ }
225
+ .pipe.nav a, .pipe.nav a:link, .pipe.nav a:visited {
226
+ color:#444;
227
+ text-decoration:none;
228
+ }
229
+ .pipe.nav a:hover {
230
+ color:#000;
231
+ text-decoration:underline;
232
+ }
233
+
234
+ form {
235
+ text-align: center;
236
+ }
237
+
238
+ form .text-input input {
239
+ font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Helvetica, Arial, sans-serif;
240
+ margin: 10px 0 5px 10px;
241
+ color: #686868;
242
+ font-size: 40px;
243
+ text-align: left;
244
+ text-transform: lowercase;
245
+ }
246
+
247
+ form .submit-input input {
248
+ position: relative;
249
+ margin: 0 7% 0 0;
250
+ float: right;
251
+ }
252
+
253
+ form .options-input {
254
+ position: relative;
255
+ margin: 0 7% 0 0;
256
+ float: left;
257
+ text-align: left;
258
+ }
259
+
@@ -0,0 +1,94 @@
1
+ /*
2
+ Copyright: Blake Mizerany, www.sinatrarb.com
3
+ Permission Pending
4
+ */
5
+ body
6
+ { color: #000;
7
+ background: #fff;
8
+ font-size: 85%;
9
+ font-family: Helvetica, sans-serif;
10
+ line-height: 130%;
11
+ margin: 0.5cm; }
12
+
13
+ a
14
+ { color: #000;
15
+ text-decoration: underline; }
16
+
17
+ a img
18
+ { border: none; }
19
+
20
+ /* HEADER */
21
+ #head {
22
+ text-align: center;
23
+ }
24
+ #head img {
25
+ vertical-align:middle;
26
+ margin:-10px 0 0 -82px;
27
+ padding:0 15px 0 0;
28
+ border:0;
29
+ }
30
+ #head h1 {
31
+ color: #172533;
32
+ font-family: Georgia, "Times New Roman", 'bitstream vera serif', serif;
33
+ font-size: 500%;
34
+ font-weight: normal;
35
+ letter-spacing: -0.1em;
36
+ line-height: 1;
37
+ margin: 0;
38
+ padding: 20px 0 16px 0;
39
+ }
40
+ #head h1 a, #head h1 a:link, #head h1 a:visited, #head h1 a:hover {
41
+ color: #172533;
42
+ text-decoration: none;
43
+ }
44
+ #head ul {
45
+ font-size:1.1em;
46
+ font-family: 'Lucida Grande', 'lucida sans unicade', Verdana, sans-serif;
47
+ font-weight: normal;
48
+ text-transform: uppercase;
49
+ text-align: center;
50
+ margin: 0;
51
+ padding: 0 40px 10px 40px;
52
+ }
53
+ #head ul li {
54
+ display: inline;
55
+ list-style-type: none;
56
+ padding: 0 1.5em 0 0;
57
+ }
58
+ #head ul a, #head ul a:link, #head ul a:visited {
59
+ color: #1d2e40;
60
+ text-decoration: none;
61
+ }
62
+ #head ul a:hover {
63
+ color: #0e1c29;
64
+ text-decoration:underline
65
+ }
66
+
67
+
68
+
69
+ h2 {
70
+ font-size: 1.5em;
71
+ letter-spacing: -0.05em;
72
+ padding: 1.15em 0 0 0;
73
+ margin: 1.25em 0 0.25em 0;
74
+ border-top: 1mm solid #999;
75
+ }
76
+
77
+ h3 {
78
+ font-size: 1.1em;
79
+ font-weight:bold;
80
+ margin: 1.8em 0 0.25em 0;
81
+ letter-spacing: -0.05em;
82
+ }
83
+
84
+ h3 a {
85
+ text-decoration:underline;
86
+ }
87
+
88
+
89
+
90
+ pre {
91
+ border: 1pt solid #ccc;
92
+ padding: 0.5em;
93
+ white-space: pre-wrap; white-space: -moz-pre-wrap !important;
94
+ }