weather_report 0.0.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.
- data/History.txt +4 -0
- data/Manifest.txt +14 -0
- data/PostInstall.txt +2 -0
- data/README.rdoc +119 -0
- data/Rakefile +28 -0
- data/lib/weather_report.rb +221 -0
- data/script/console +10 -0
- data/script/console.cmd +1 -0
- data/script/destroy +14 -0
- data/script/destroy.cmd +1 -0
- data/script/generate +14 -0
- data/script/generate.cmd +1 -0
- data/test/test_helper.rb +3 -0
- data/test/test_weather_report.rb +115 -0
- metadata +91 -0
data/History.txt
ADDED
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
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"
|
data/script/console.cmd
ADDED
@@ -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)
|
data/script/destroy.cmd
ADDED
@@ -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)
|
data/script/generate.cmd
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
@ruby script/generate %*
|
data/test/test_helper.rb
ADDED
@@ -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
|