weather_report 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2009-05-04
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,14 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ PostInstall.txt
5
+ Rakefile
6
+ lib/weather_report.rb
7
+ script/console
8
+ script/console.cmd
9
+ script/destroy
10
+ script/destroy.cmd
11
+ script/generate
12
+ script/generate.cmd
13
+ test/test_helper.rb
14
+ test/test_weather_report.rb
data/PostInstall.txt ADDED
@@ -0,0 +1,2 @@
1
+
2
+ For more information on weather_report, see http://www.cordinc.com/projects/weather_report
data/README.rdoc ADDED
@@ -0,0 +1,119 @@
1
+ = weather_report
2
+
3
+ Homepage:: http://www.cordinc.com/projects/weather_report
4
+ Author:: Charles Cordingley
5
+ Copyright:: (c) 2009 Charles Cordingley
6
+ License:: MIT
7
+
8
+ == DESCRIPTION:
9
+
10
+ Connect to the BBC Backstage (http://backstage.bbc.co.uk) weather API and get weather observations and forecasts for thousands of cities worldwide. No
11
+ login is required to the BBC for use.
12
+
13
+ == TODO
14
+
15
+ * Allow weather to be shown in either metric or imperial units (currently only metric)
16
+ * Be able to seach or lookup location ids
17
+ * Add weather sources other than the BBC
18
+
19
+ == SYNOPSIS:
20
+
21
+ After requiring the library, create a WeatherReport object with a BBC weather location id:
22
+
23
+ require 'weather_report'
24
+ # 8 is the BBC Backstage weather code for London, UK
25
+ londonWeather = WeatherReport.new(8)
26
+
27
+ Then you can get the observations or forecasts for that location:
28
+
29
+ londonWeather.observation.temperature
30
+ londonWeather.forecast.for_tomorrow.max_temperature
31
+
32
+ Calls to the observation or forecast data after the first call for a location will just return return cached data. Use force_reload = true on the call to force
33
+ the data to be reloaded from the BBC.
34
+
35
+ # use the cached data
36
+ londonWeather.observation.reading_date
37
+ # reload the data
38
+ londonWeather.observation(force_reload = true).reading_date
39
+
40
+ Forecasts can be specified in a number of ways:
41
+
42
+ londonWeather.forecast.for_tomorrow.max_temperature
43
+ londonWeather.forecast.for_today.max_temperature
44
+ # also today
45
+ londonWeather.forecast.for(Date.today).max_temperature
46
+ # day after tomorrow
47
+ londonWeather.forecast.for(Date.today+2).max_temperature
48
+ # The date can also be specified as a date string
49
+ londonWeather.forecast.for("2009-05-06").max_temperature
50
+ # The underlying structure is an array, so you can just index into it. The below is the same as today
51
+ londonWeather.forecast[0].max_temperature
52
+
53
+ The full set of attributes is:
54
+
55
+ londonWeather.observation.reading_date
56
+ londonWeather.observation.name
57
+ londonWeather.observation.country
58
+ londonWeather.observation.latitude
59
+ londonWeather.observation.longtitude
60
+ londonWeather.observation.temperature
61
+ londonWeather.observation.wind_speed
62
+ londonWeather.observation.wind_direction
63
+ londonWeather.observation.humidity
64
+ londonWeather.observation.pressure
65
+ londonWeather.observation.pressure_state
66
+ londonWeather.observation.visibility
67
+ londonWeather.observation.humidity
68
+
69
+ londonWeather.forecast.reading_date
70
+ londonWeather.forecast.name
71
+ londonWeather.forecast.country
72
+ londonWeather.forecast.latitude
73
+ londonWeather.forecast.longtitude
74
+ londonWeather.forecast.for_today.date
75
+ londonWeather.forecast.for_today.max_temperature
76
+ londonWeather.forecast.for_today.min_temperature
77
+ londonWeather.forecast.for_today.wind_speed
78
+ londonWeather.forecast.for_today.wind_direction
79
+ londonWeather.forecast.for_today.humidity
80
+ londonWeather.forecast.for_today.pressure
81
+ londonWeather.forecast.for_today.visibility
82
+ londonWeather.forecast.for_today.humidity
83
+
84
+ == REQUIREMENTS:
85
+
86
+ The only external dependencies are REXML and net/http which are include as part of most Ruby installations.
87
+
88
+ == INSTALL:
89
+
90
+ The weather_report library is distributed itself as a RubyGem and is available immediately after installation.
91
+
92
+ sudo gem install weather_report
93
+
94
+ Alternately, download the gem and install manually.
95
+
96
+ == LICENSE:
97
+
98
+ (The MIT License)
99
+
100
+ Copyright (c) 2009 FIXME full name
101
+
102
+ Permission is hereby granted, free of charge, to any person obtaining
103
+ a copy of this software and associated documentation files (the
104
+ 'Software'), to deal in the Software without restriction, including
105
+ without limitation the rights to use, copy, modify, merge, publish,
106
+ distribute, sublicense, and/or sell copies of the Software, and to
107
+ permit persons to whom the Software is furnished to do so, subject to
108
+ the following conditions:
109
+
110
+ The above copyright notice and this permission notice shall be
111
+ included in all copies or substantial portions of the Software.
112
+
113
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
114
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
115
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
116
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
117
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
118
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
119
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,28 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/weather_report'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('weather_report', WeatherReport::VERSION) do |p|
7
+ p.developer('Charles Cordingley', 'inquiries at cordinc dot com')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
10
+ p.rubyforge_name = 'weather-report'
11
+ # p.extra_deps = [
12
+ # ['activesupport','>= 2.0.2'],
13
+ # ]
14
+ p.extra_dev_deps = [
15
+ ['newgem', ">= #{::Newgem::VERSION}"]
16
+ ]
17
+
18
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
19
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
20
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
21
+ p.rsync_args = '-av --delete --ignore-errors'
22
+ end
23
+
24
+ require 'newgem/tasks' # load /tasks/*.rake
25
+ Dir['tasks/**/*.rake'].each { |t| load t }
26
+
27
+ # TODO - want other tests/tasks run by default? Add them to the list
28
+ # task :default => [:spec, :features]
@@ -0,0 +1,221 @@
1
+ require 'net/http'
2
+ require "rexml/document"
3
+
4
+ $:.unshift(File.dirname(__FILE__)) unless
5
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
6
+
7
+ # Class containing weather observations and forecasts for the location specified by id in the constructor.
8
+ class WeatherReport
9
+
10
+ VERSION = '0.0.1'
11
+
12
+ # The id is the number (1..9999) the BBC uses to identify cities for weather reports
13
+ attr_reader :id
14
+
15
+ # Raised when there is no response from the server
16
+ class NoResponseError < StandardError
17
+ end
18
+
19
+ # Raised when the data returned from BBC is not in the expected format
20
+ class FormatError < StandardError
21
+ end
22
+
23
+ # Requires a valid BBC Backstage weather id (or any call to the API will return a FormatError)
24
+ def initialize(location_id)
25
+ @id = location_id
26
+ end
27
+
28
+ # Returns the weather observation for the current id. If one is not currently loaded then this will go to the BBC Backstage API and download it.
29
+ # Alternatively, by specifying force_reload = true the observation will be loaded from the BBC regardless of whether one has already been downloaded.
30
+ def observation(force_reload = false)
31
+ @observation = WeatherReportObservation.new(fetch(observation_url())) if force_reload or @observation.nil?
32
+ @observation
33
+ end
34
+
35
+ # Returns the weather forecast for the current id. If one is not currently loaded then this will go to the BBC Backstage API and download it.
36
+ # Alternatively, by specifying force_reload = true the observation will be loaded from the BBC regardless of whether one has already been downloaded.
37
+ def forecast(force_reload = false)
38
+ @forecast = WeatherReportForecasts.new(fetch(forecast_url())) if force_reload or @forecast.nil?
39
+ @forecast
40
+ end
41
+
42
+ protected
43
+
44
+ # Fetch Response from the api
45
+ def fetch(url)
46
+ response = Net::HTTP.get_response(URI.parse(url)).body
47
+
48
+ # Check if a response was returned at all
49
+ raise(WeatherReport::NoResponseError, "WeatherReport Error: No Response.") unless response
50
+
51
+ response
52
+ end
53
+
54
+ # The url for getting current weather observations from BBC Backstage
55
+ def observation_url()
56
+ "http://news.bbc.co.uk/weather/forecast/#{@id}/ObservationsRSS.rss"
57
+ end
58
+
59
+ # The url for getting weather forecasts from BBC Backstage
60
+ def forecast_url()
61
+ "http://news.bbc.co.uk/weather/forecast/#{@id}/Next3DaysRSS.rss"
62
+ end
63
+
64
+ end
65
+
66
+ # Module to load and provide accessors for shared location specific
67
+ module Location
68
+
69
+ TITLE = /(.+) for ([\w -\.]*), ([\w -\.]*)/
70
+
71
+ attr_reader :name, :country, :latitude, :longtitude
72
+
73
+ # load the location based data (name, country, latitude, longtitude) from the backstage feed
74
+ def loadLocation(xmlDoc)
75
+ xmlDoc.elements.each("rss/channel/title") { |element|
76
+ md = TITLE.match(element.text)
77
+ @name = md[2] if md
78
+ @country = md[3] if md
79
+ }
80
+
81
+ xmlDoc.elements.each("rss/channel/item[1]/geo:lat") { |element| @latitude = element.text.to_f }
82
+ xmlDoc.elements.each("rss/channel/item[1]/geo:long") { |element| @longtitude = element.text.to_f }
83
+ end
84
+ end
85
+
86
+ # The current weather observations (at least at the time of reading - given by attribute reading_date)
87
+ class WeatherReportObservation
88
+ include Location
89
+
90
+ DESCRIPTION = /Temperature: ([-\d\.]+|N\/A|NA|\(none\))(.+)Wind Direction: ([\w -\/\(\)]*), Wind Speed: ([-\d\.]+|N\/A|NA|\(none\))mph, Relative Humidity: ([\d\.]+|N\/A|NA|\(none\))(.*), Pressure: ([\d\.]+|N\/A|NA|\(none\))mB, ([\w -\/]+), Visibility: ([\w -\/]+)/
91
+ SUMMARY = /(.+):(\W+)([\w -\/\(\)]+). (.+)/m
92
+
93
+ attr_reader :temperature, :wind_direction, :wind_speed, :visibility, :pressure, :pressure_state, :humidity, :reading_date
94
+
95
+ # Constructs the weather observation from an XML string or file containing the XML in BBC Backstage weather format
96
+ def initialize(document)
97
+ doc = REXML::Document.new document
98
+
99
+ loadLocation(doc)
100
+ @reading_date = DateTime.now
101
+ doc.elements.each("rss/channel/item[1]/title[1]") { |element|
102
+ md = SUMMARY.match(element.text)
103
+ @description = md[3]
104
+ }
105
+
106
+ doc.elements.each("rss/channel/item[1]/description[1]") { |element|
107
+ md = DESCRIPTION.match(element.text)
108
+ @temperature = md[1].to_f
109
+ @wind_direction = md[3]
110
+ @wind_speed = md[4].to_f * 1.61
111
+ @humidity = md[5].to_f
112
+ @pressure = md[7].to_f
113
+ @pressure_state = md[8]
114
+ @visibility = md[9]
115
+ }
116
+
117
+ rescue
118
+ raise WeatherReport::FormatError
119
+ end
120
+
121
+ end
122
+
123
+ # A collection of forecasts for a particular location
124
+ class WeatherReportForecasts < Array
125
+ include Location
126
+
127
+ attr_reader :reading_date
128
+
129
+ # Constructs the weather forecasts from an XML string or file containing the XML in BBC Backstage weather format
130
+ def initialize(document)
131
+ doc = REXML::Document.new document
132
+ @reading_date = DateTime.now
133
+ loadLocation(doc)
134
+ doc.elements.each("rss/channel/image/url") { |element| @image_url = element.text }
135
+
136
+ doc.elements.each("rss/channel/item/") { |element|
137
+ self << WeatherReportForecast.new(element)
138
+ }
139
+
140
+ rescue
141
+ raise WeatherReport::FormatError
142
+ end
143
+
144
+ # Returns the forecast for today, or nil is there is no such forecast.
145
+ def for_today
146
+ self.for(Date.today)
147
+ end
148
+
149
+ # Returns the forecast for tomorrow, or nil is there is no such forecast.
150
+ def for_tomorrow
151
+ self.for(Date.today+1)
152
+ end
153
+
154
+ # Returns a forecast for a day given by a Date, DateTime, Time, or a string that can be parsed to a date.
155
+ # If there is no forecast for the given date then nil is returned.
156
+ def for(date = Date.today)
157
+ date = case date.class.name
158
+ when 'String'
159
+ Date.parse(date)
160
+ when 'Date'
161
+ date
162
+ when 'DateTime'
163
+ Date.new(date.year, date.month, date.day)
164
+ when 'Time'
165
+ Date.new(date.year, date.month, date.day)
166
+ end
167
+
168
+ day = nil
169
+ self.each do |fd|
170
+ day = fd if date == fd.date
171
+ end
172
+ return day
173
+ end
174
+
175
+ # A forecast for a single day
176
+ class WeatherReportForecast
177
+
178
+ SUMMARY = /([\w -\/]+): ([\w -]+|N\/A|NA|\(none\)), Max Temp: (.*)/m
179
+ DESCRIPTION = /Max Temp: ([-\d\.]+|N\/A|NA|\(none\))(.+)Min Temp: ([-\d\.]+|N\/A|NA|\(none\))(.+)Wind Direction: ([\w -\/\(\)]*), Wind Speed: ([-\d\.]+|N\/A|NA|\(none\))mph, Visibility: ([\w -\/]+), Pressure: ([\d\.]+|N\/A|NA|\(none\))mB, Humidity: ([\d\.]+|N\/A|NA|\(none\))(.*), (.+)/m
180
+
181
+ attr_reader :max_temperature, :min_temperature, :wind_direction, :wind_speed, :visibility, :pressure, :humidity, :date
182
+
183
+ # Constructs the single day forecast from an REXML element containing the forecast in BBC Backstage weather format
184
+ def initialize(item)
185
+ item.elements.each("title[1]") { |element|
186
+ md = SUMMARY.match(element.text)
187
+ @description = md[2]
188
+ diff = day_diff(md[1])
189
+ raise(WeatherReport::FormatError, "WeatherReport Error: Day mismatch.") if diff.nil?
190
+ @date = Date.today+diff
191
+ }
192
+
193
+ item.elements.each("description[1]") { |element|
194
+ md = DESCRIPTION.match(element.text)
195
+ @max_temperature = md[1].to_f
196
+ @min_temperature = md[3].to_f
197
+ @wind_direction = md[5]
198
+ @wind_speed = md[6].to_f * 1.61
199
+ @visibility = md[7]
200
+ @pressure = md[8].to_f
201
+ @humidity = md[9].to_f
202
+ }
203
+ end
204
+
205
+ protected
206
+
207
+ # Calculate the number of days the given day name is from today's day name assuming it is no more than 5 days in the future or no further back than yesterday.
208
+ # Eg. If today is Wednesday, then if passed Tuesday this function will return -1, if passed Friday it will return 2, and if passed Wednesday it will return 0.
209
+ def day_diff(day_from)
210
+ start = Date::DAYNAMES.index(day_from.downcase.gsub!(/^[a-z]|\s+[a-z]/) { |a| a.upcase })
211
+ return if start.nil?
212
+ finish = Date.today.wday
213
+ result = start - finish
214
+ result = result+7 if result < -1
215
+ result = result-7 if result >5
216
+ result
217
+ end
218
+
219
+ end
220
+
221
+ end
data/script/console ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/weather_report.rb'}"
9
+ puts "Loading weather_report gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1 @@
1
+ @ruby script/console %*
data/script/destroy ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1 @@
1
+ @ruby script/destroy %*
data/script/generate ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1 @@
1
+ @ruby script/generate %*
@@ -0,0 +1,3 @@
1
+ require 'stringio'
2
+ require 'test/unit'
3
+ require File.dirname(__FILE__) + '/../lib/weather_report'
@@ -0,0 +1,115 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestWeatherReport < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ w = WeatherReport.new(92)
10
+ assert_not_nil(w)
11
+ assert_equal(w.id, 92)
12
+ end
13
+
14
+ def test_fine_observation
15
+ obs = WeatherReportObservation.new(File.read(File.dirname(__FILE__) + '/BBC_ObservationsRSS.rss'))
16
+ assert_not_nil(obs)
17
+ assert_equal(obs.name, "Perth")
18
+ assert_equal(obs.country, "Australia")
19
+ assert_equal(obs.latitude, -31.93)
20
+ assert_equal(obs.longtitude, 115.97)
21
+ assert_equal(obs.temperature, 15)
22
+ assert_equal(obs.wind_direction, "SW")
23
+ assert_equal(obs.wind_speed, 1.61)
24
+ assert_equal(obs.visibility, "Very good")
25
+ assert_equal(obs.pressure, 1026)
26
+ assert_equal(obs.pressure_state, "rising")
27
+ assert_equal(obs.humidity, 52)
28
+ end
29
+
30
+ def test_no_wind_observation
31
+ obs = WeatherReportObservation.new(File.read(File.dirname(__FILE__) + '/BBC_no_wind_ObservationsRSS.rss'))
32
+ assert_not_nil(obs)
33
+ assert_equal(obs.name, "Perth")
34
+ assert_equal(obs.country, "Australia")
35
+ assert_equal(obs.latitude, -31.93)
36
+ assert_equal(obs.longtitude, 115.97)
37
+ assert_equal(obs.temperature, 10)
38
+ assert_equal(obs.wind_direction, "")
39
+ assert_equal(obs.wind_speed, 0)
40
+ assert_equal(obs.visibility, "Excellent")
41
+ assert_equal(obs.pressure, 1025)
42
+ assert_equal(obs.pressure_state, "falling")
43
+ assert_equal(obs.humidity, 63)
44
+ end
45
+
46
+ def test_error_observation
47
+ assert_raise(WeatherReport::FormatError) { WeatherReportObservation.new(File.read(File.dirname(__FILE__) + '/error.rss'))}
48
+ end
49
+
50
+ def test_error_forecast
51
+ assert_raise(WeatherReport::FormatError) { WeatherReportForecasts.new(File.read(File.dirname(__FILE__) + '/error.rss'))}
52
+ end
53
+
54
+ def test_current_forecast
55
+ doc = File.read(File.dirname(__FILE__) + '/BBC_Next3DaysRSS.rss')
56
+ doc = doc.gsub("<TODAY>", Date::DAYNAMES[Date.today.wday]).gsub("<TOMORROW>", Date::DAYNAMES[(Date.today+1).wday]).gsub("<DAY_AFTER_TOMORROW>", Date::DAYNAMES[(Date.today+2).wday])
57
+ f = WeatherReportForecasts.new(doc)
58
+ assert_equal(f.name, "Perth")
59
+ assert_equal(f.country, "Australia")
60
+ assert_equal(f.latitude, -31.93)
61
+ assert_equal(f.longtitude, 115.95)
62
+
63
+ assert_equal(f.for_today.max_temperature, 28)
64
+ assert_equal(f.for_today.min_temperature, 14)
65
+ assert_equal(f.for_today.wind_direction, "ENE")
66
+ assert_equal(f.for_today.wind_speed, 9.66)
67
+ assert_equal(f.for_today.visibility, "very good")
68
+ assert_equal(f.for_today.pressure, 1026)
69
+ assert_equal(f.for_today.humidity, 30)
70
+
71
+ assert_equal(f.for_tomorrow.max_temperature, 27)
72
+ assert_equal(f.for_tomorrow.min_temperature, 14)
73
+ assert_equal(f.for_tomorrow.wind_direction, "ENE")
74
+ assert((f.for_tomorrow.wind_speed - 11.27).abs < 0.01)
75
+ assert_equal(f.for_tomorrow.visibility, "very good")
76
+ assert_equal(f.for_tomorrow.pressure, 1028)
77
+ assert_equal(f.for_tomorrow.humidity, 33)
78
+
79
+ assert_equal(f.for(Date.today+2).max_temperature, 25)
80
+ assert_equal(f.for(Date.today+2).min_temperature, 14)
81
+ assert_equal(f.for(Date.today+2).wind_direction, "ENE")
82
+ assert_equal(f.for(Date.today+2).wind_speed, 14.49)
83
+ assert_equal(f.for(Date.today+2).visibility, "very good")
84
+ assert_equal(f.for(Date.today+2).pressure, 1028)
85
+ assert_equal(f.for(Date.today+2).humidity, 37)
86
+
87
+ assert_nil(f.for(Date.today+3))
88
+ assert_nil(f.for(Date.today-1))
89
+ end
90
+
91
+ def test_shift_back_forecast
92
+ doc = File.read(File.dirname(__FILE__) + '/BBC_Next3DaysRSS.rss')
93
+ doc = doc.gsub("<TODAY>", Date::DAYNAMES[(Date.today-1).wday]).gsub("<TOMORROW>", Date::DAYNAMES[Date.today.wday]).gsub("<DAY_AFTER_TOMORROW>", Date::DAYNAMES[(Date.today+1).wday])
94
+ f = WeatherReportForecasts.new(doc)
95
+
96
+ assert_equal(f.for(Date.today-1).max_temperature, 28)
97
+ assert_equal(f.for(Date.today).max_temperature, 27)
98
+ assert_equal(f.for(Date.today+1).max_temperature, 25)
99
+ assert_nil(f.for(Date.today+2))
100
+ assert_nil(f.for(Date.today-2))
101
+ end
102
+
103
+ def test_shift_forward_forecast
104
+ doc = File.read(File.dirname(__FILE__) + '/BBC_Next3DaysRSS.rss')
105
+ doc = doc.gsub("<TODAY>", Date::DAYNAMES[(Date.today+1).wday]).gsub("<TOMORROW>", Date::DAYNAMES[(Date.today+2).wday]).gsub("<DAY_AFTER_TOMORROW>", Date::DAYNAMES[(Date.today+3).wday])
106
+ f = WeatherReportForecasts.new(doc)
107
+
108
+ assert_equal(f.for_tomorrow.max_temperature, 28)
109
+ assert_equal(f.for(Date.today+2).max_temperature, 27)
110
+ assert_equal(f.for(Date.today+3).max_temperature, 25)
111
+ assert_nil(f.for_today)
112
+ assert_nil(f.for(Date.today+4))
113
+ end
114
+
115
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: weather_report
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Charles Cordingley
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-05-10 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: newgem
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.3.0
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: hoe
27
+ type: :development
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.0
34
+ version:
35
+ description: Connect to the BBC Backstage (http://backstage.bbc.co.uk) weather API and get weather observations and forecasts for thousands of cities worldwide. No login is required to the BBC for use.
36
+ email:
37
+ - inquiries at cordinc dot com
38
+ executables: []
39
+
40
+ extensions: []
41
+
42
+ extra_rdoc_files:
43
+ - History.txt
44
+ - Manifest.txt
45
+ - README.rdoc
46
+ - PostInstall.txt
47
+ files:
48
+ - History.txt
49
+ - Manifest.txt
50
+ - README.rdoc
51
+ - PostInstall.txt
52
+ - Rakefile
53
+ - lib/weather_report.rb
54
+ - script/console
55
+ - script/console.cmd
56
+ - script/destroy
57
+ - script/destroy.cmd
58
+ - script/generate
59
+ - script/generate.cmd
60
+ - test/test_helper.rb
61
+ - test/test_weather_report.rb
62
+ has_rdoc: true
63
+ homepage: "Homepage:: http://www.cordinc.com/projects/weather_report"
64
+ post_install_message: PostInstall.txt
65
+ rdoc_options:
66
+ - --main
67
+ - README.rdoc
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: "0"
75
+ version:
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: "0"
81
+ version:
82
+ requirements: []
83
+
84
+ rubyforge_project: weather-report
85
+ rubygems_version: 1.3.1
86
+ signing_key:
87
+ specification_version: 2
88
+ summary: Connect to the BBC Backstage (http://backstage.bbc.co.uk) weather API and get weather observations and forecasts for thousands of cities worldwide
89
+ test_files:
90
+ - test/test_helper.rb
91
+ - test/test_weather_report.rb