wunderground 1.0.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.
- data/Gemfile +15 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +145 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/wunderground.rb +75 -0
- data/test/helper.rb +19 -0
- data/test/test_wunderground.rb +201 -0
- data/wunderground.gemspec +80 -0
- data/wunderground_ruby.gemspec +79 -0
- metadata +172 -0
data/Gemfile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "json", "> 1.4.0"
|
4
|
+
gem "httparty", "> 0.6.0"
|
5
|
+
gem "addressable"
|
6
|
+
|
7
|
+
group :development, :test do
|
8
|
+
gem "shoulda", ">= 0"
|
9
|
+
gem "bundler", "~> 1.0.0"
|
10
|
+
gem "jeweler", "~> 1.5.1"
|
11
|
+
gem "simplecov", ">= 0"
|
12
|
+
gem "mocha", "> 0.9.11"
|
13
|
+
gem "ruby-debug19", :require => "ruby-debug", :platforms => [:ruby_19]
|
14
|
+
gem "ruby-debug", :platforms => [:ruby_18]
|
15
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2012 Winfred Nadeau
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
# Wunderground Ruby API wrapper
|
2
|
+
|
3
|
+
Wunderground Ruby is an API wrapper for interacting with the [Wunderground API](http://www.wunderground.com/weather/api/)
|
4
|
+
|
5
|
+
|
6
|
+
##Installation
|
7
|
+
|
8
|
+
$ gem install wunderground_ruby
|
9
|
+
|
10
|
+
or in your Gemfile
|
11
|
+
|
12
|
+
gem 'wunderground_ruby'
|
13
|
+
|
14
|
+
##Requirements
|
15
|
+
|
16
|
+
A Wunderground account and API key.
|
17
|
+
If a request is attempted without an APIkey, this wrapper will raise a MissingAPIKey exception
|
18
|
+
|
19
|
+
JSON only at the moment.
|
20
|
+
|
21
|
+
##Usage
|
22
|
+
|
23
|
+
You can create an instance of the API wrapper and pass it the API key:
|
24
|
+
|
25
|
+
w_api = Wunderground.new("your apikey")
|
26
|
+
|
27
|
+
You can also set the environment variable "WUNDERGROUND_API_KEY" and wunderground_ruby will use it when you create an instance:
|
28
|
+
|
29
|
+
w_api = Wunderground.new
|
30
|
+
|
31
|
+
This gem/wrapper uses some method_missing fun to make it easier to get feature and location data from Wunderground
|
32
|
+
|
33
|
+
Any number of [features](http://www.wunderground.com/weather/api/d/documentation.html#request) work by passing the features from the method straight into the request URL.
|
34
|
+
|
35
|
+
Check out below and test file for more examples.
|
36
|
+
|
37
|
+
Standard request breakdown:
|
38
|
+
|
39
|
+
wrapper_instance.[feature]_and_[another feature]_for("location string",optional: "hash", values: "at the end")
|
40
|
+
|
41
|
+
##Optional Hash
|
42
|
+
|
43
|
+
This ugly little guy handles the nonconformists in Wunderground's API request structure and the pervasive request timeout option.
|
44
|
+
Luckily there are only three of these baddies, and only if you need them. (details below)
|
45
|
+
|
46
|
+
optional_hash = {lang: "FR", geo_ip:"127.0.0.1", timeout: 20}
|
47
|
+
|
48
|
+
Note: If needing to use these options, please place them as the last parameter(s) to the method call.
|
49
|
+
|
50
|
+
Can you think of a better way to handle these? Pull requests welcome.
|
51
|
+
|
52
|
+
##Features
|
53
|
+
|
54
|
+
The method_missing magic happens here.
|
55
|
+
|
56
|
+
w_api.forecast_for("WA","Spokane")
|
57
|
+
w_api.forecast_and_conditions_for("1234.1234,-1234.1234") #a lat/long string
|
58
|
+
w_api.webcams_and_conditions_and_alerts_for("33043") #a zipcode
|
59
|
+
|
60
|
+
##Locations
|
61
|
+
|
62
|
+
Any location string that Wunderground accepts will pass straight through this wrapper to their API, _except for a specific geo-ip._ (examples below)
|
63
|
+
|
64
|
+
#there is some handy array joining, if needed
|
65
|
+
w_api.forecast_for("WA/Spokane") #equivalent to the next example
|
66
|
+
w_api.forecast_for("WA","Spokane") #equivalent to the previous example
|
67
|
+
|
68
|
+
#zipcodes,lat/long, aiport codes, all of them just pass straight through this wrapper and into the request URL
|
69
|
+
w_api.conditions_for("77898")
|
70
|
+
|
71
|
+
#weather station code uniqueness - they use the 'pws:' prefix for weather station codes. So does this wrapper.
|
72
|
+
w_api.conditions_for("pws:STATIONCODE")
|
73
|
+
|
74
|
+
w_api.conditions_for("autoip") #passes straight through, but only gets the weather for your server's IP, so not very useful probably
|
75
|
+
|
76
|
+
For geocoding a specific ip address as the location, just provide an IP like this:
|
77
|
+
|
78
|
+
w_api.alerts_for(geo_ip: "127.0.0.1")
|
79
|
+
|
80
|
+
This was the quickest workaround to the non-conformity of the auto_ip request format.
|
81
|
+
|
82
|
+
|
83
|
+
##Language Support
|
84
|
+
|
85
|
+
Because the Language modifier in Wunderground's request structure uses a colon, which doesn't jive with the method_missing design, adding a specific language to one request can be done like this:
|
86
|
+
|
87
|
+
w_api.forecast_for("France","Paris", lang 'FR')
|
88
|
+
|
89
|
+
Also, you can set the default language in the constructor or with a setter.
|
90
|
+
|
91
|
+
w_api = Wunderground.new("apikey",language: "FR")
|
92
|
+
w_api.language = 'FR'
|
93
|
+
w_api.forecast_for("France","Paris") #automatically includes /lang:FR/ in the request url, so results will be in French
|
94
|
+
w_api.forecast_for("France","Paris",lang: 'DE') #this will override the French(FR) default with German(DE)
|
95
|
+
|
96
|
+
##History and Planner Helpers
|
97
|
+
|
98
|
+
While it is possible to call
|
99
|
+
|
100
|
+
w_api.history20101231_for("77789")
|
101
|
+
w_api.planner03150323_for("FL","Destin")
|
102
|
+
|
103
|
+
to get the history/planner data for this date/location. You may enjoy more flexibility when using history_for and planner_for:
|
104
|
+
|
105
|
+
w_api.history_for("20101010","AL","Birmingham")
|
106
|
+
w_api.history_for(1.year.ago,"33909")
|
107
|
+
w_api.history_for(Date.now, "France/Paris",lang: "FR")
|
108
|
+
w_api.history_for(Date.now, geo_ip:"123.4.5.6", lang: "FR")
|
109
|
+
w_api.planner_for("03150323","AL","Gulf Shores")
|
110
|
+
w_api.planner_for(Time.now,Time.now+7.days, geo_ip: "10.0.0.1")
|
111
|
+
w_api.planner_for(Time.now,Time.now+7.days,"33030")
|
112
|
+
|
113
|
+
.history_for and .planner_for accepts a preformatted string or any Date/Time/DateTime-like object that responds to .strftime to auto-format the date.
|
114
|
+
|
115
|
+
|
116
|
+
## Request Timeout
|
117
|
+
|
118
|
+
wunderground_ruby defaults to a 30 second timeout. You can optionally set your own timeout (in seconds) in three ways like so:
|
119
|
+
|
120
|
+
w_api = Wunderground.new("apikey",timeout: 60)
|
121
|
+
w_api.timeout = 5
|
122
|
+
w_api.history_for(1.year.ago, geo_ip: '127.0.0.1', timeout:60)
|
123
|
+
|
124
|
+
|
125
|
+
### Error Handling
|
126
|
+
|
127
|
+
By default you are expected to handle errors returned by the APIs manually. (see their documentation for more information about these errors)
|
128
|
+
|
129
|
+
If you set the `throws_exceptions` boolean attribute for a given instance then
|
130
|
+
wunderground_ruby will attempt to intercept the errors and raise an APIError exception if you feel like catching it.
|
131
|
+
|
132
|
+
##Contributing
|
133
|
+
|
134
|
+
Do eet.
|
135
|
+
|
136
|
+
##Thanks
|
137
|
+
|
138
|
+
* [Amro Mousa](https://github.com/amro) - design inspiration
|
139
|
+
|
140
|
+
|
141
|
+
##Copyrights
|
142
|
+
|
143
|
+
* Copyright (c) 2012 Winfred Nadeau. See LICENSE.txt for details.
|
144
|
+
|
145
|
+
Winfred Nadeau is not affiliated with [Wunderground.com](http://wunderground.com), so check them out for licensing/copyright/legal/TOS details regarding their API and their data.
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'rake'
|
11
|
+
|
12
|
+
require 'jeweler'
|
13
|
+
Jeweler::Tasks.new do |gem|
|
14
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
15
|
+
gem.name = "wunderground"
|
16
|
+
gem.homepage = "http://github.com/wnadeau/wunderground_ruby"
|
17
|
+
gem.license = "MIT"
|
18
|
+
gem.summary = %Q{A simple ruby API wrapper for interacting with the Wunderground API}
|
19
|
+
gem.description = %Q{A simple ruby API wrapper for interacting with the Wunderground API}
|
20
|
+
gem.email = "winfred.nadeau@gmail.com"
|
21
|
+
gem.authors = ["Winfred Nadeau"]
|
22
|
+
end
|
23
|
+
Jeweler::RubygemsDotOrgTasks.new
|
24
|
+
|
25
|
+
require 'rake/testtask'
|
26
|
+
Rake::TestTask.new(:test) do |test|
|
27
|
+
test.libs << 'lib' << 'test'
|
28
|
+
test.pattern = 'test/**/test_*.rb'
|
29
|
+
test.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
task :default => :test
|
33
|
+
|
34
|
+
require 'rdoc/task'
|
35
|
+
Rake::RDocTask.new do |rdoc|
|
36
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
37
|
+
|
38
|
+
rdoc.rdoc_dir = 'rdoc'
|
39
|
+
rdoc.title = "Wunderground #{version}"
|
40
|
+
rdoc.rdoc_files.include('README*')
|
41
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
42
|
+
end
|
43
|
+
desc "Open an irb session preloaded with this library"
|
44
|
+
task :console do
|
45
|
+
exec "irb -rubygems -I lib -r wunderground"
|
46
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
data/lib/wunderground.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'json'
|
3
|
+
require 'cgi'
|
4
|
+
require 'addressable/uri'
|
5
|
+
|
6
|
+
class Wunderground
|
7
|
+
include HTTParty
|
8
|
+
format :json
|
9
|
+
default_timeout 30
|
10
|
+
|
11
|
+
class MissingAPIKey < RuntimeError; end
|
12
|
+
class APIError < RuntimeError; end
|
13
|
+
|
14
|
+
attr_accessor :api_key, :timeout, :throws_exceptions, :language
|
15
|
+
|
16
|
+
def initialize(api_key = nil, extra_params = {})
|
17
|
+
@api_key = api_key || ENV['WUNDERGROUND_API_KEY'] || ENV['WUNDERGROUND_APIKEY'] || self.class.api_key
|
18
|
+
@timeout = extra_params[:timeout] || 30
|
19
|
+
@throws_exceptions = extra_params[:throws_exceptions] || false
|
20
|
+
@language = extra_params[:language]
|
21
|
+
end
|
22
|
+
|
23
|
+
def base_api_url
|
24
|
+
"http://api.wunderground.com/api/#{api_key}/"
|
25
|
+
end
|
26
|
+
def history_for(date,*args)
|
27
|
+
history = (date.class == String ? "history_#{date}" : "history_#{date.strftime("%Y%m%d")}")
|
28
|
+
send("#{history}_for",*args)
|
29
|
+
end
|
30
|
+
def planner_for(date,*args)
|
31
|
+
send("planner_#{date}_for",args) and return if date.class == String
|
32
|
+
range = date.strftime("%m%d") << args[0].strftime("%m%d")
|
33
|
+
args.delete_at(0)
|
34
|
+
send("planner_#{range}_for",*args)
|
35
|
+
end
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def call(method, timeout)
|
40
|
+
raise MissingAPIKey if @api_key.nil?
|
41
|
+
response = self.class.get(base_api_url << method, :timeout => (timeout || @timeout))
|
42
|
+
begin
|
43
|
+
response = JSON.parse(response.body)
|
44
|
+
rescue
|
45
|
+
response = response.body
|
46
|
+
end
|
47
|
+
|
48
|
+
if @throws_exceptions && response.is_a?(Hash) && response["response"]["error"]
|
49
|
+
raise APIError, "#{response["response"]["error"]["type"]}: #{response["response"]["error"]["description"]})"
|
50
|
+
end
|
51
|
+
|
52
|
+
response
|
53
|
+
end
|
54
|
+
|
55
|
+
def method_missing(method, *args)
|
56
|
+
raise NoMethodError, "undefined method: #{method} for Wunderground" unless method.to_s.end_with?("_for")
|
57
|
+
url = method.to_s.gsub("_for","").gsub("_and_","/")
|
58
|
+
url << "/lang:#{@language}" if @language
|
59
|
+
if args.last.instance_of? Hash
|
60
|
+
opts = args.pop
|
61
|
+
url = url.sub(/\/lang:.*/,'') and url << "/lang:#{opts[:lang]}" if opts[:lang]
|
62
|
+
ip_address = opts[:geo_ip] and args.push("autoip") if opts[:geo_ip]
|
63
|
+
timeout = opts[:timeout]
|
64
|
+
end
|
65
|
+
call(url <<'/q/'<< args.join('/') << ".json" << (ip_address ? "?geo_ip=#{ip_address}" : ''),timeout)
|
66
|
+
end
|
67
|
+
|
68
|
+
class << self
|
69
|
+
attr_accessor :api_key, :timeout
|
70
|
+
def method_missing(sym, *args, &block)
|
71
|
+
new(self.api_key, self.attributes).send(sym, *args, &block)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
data/test/helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'test/unit'
|
13
|
+
require 'shoulda'
|
14
|
+
require 'mocha'
|
15
|
+
|
16
|
+
|
17
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
18
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
19
|
+
require 'wunderground'
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'cgi'
|
3
|
+
require 'ruby-debug'
|
4
|
+
require 'addressable/uri'
|
5
|
+
|
6
|
+
class TestWunderground < Test::Unit::TestCase
|
7
|
+
|
8
|
+
context "attributes" do
|
9
|
+
|
10
|
+
setup do
|
11
|
+
@api_key = "12345"
|
12
|
+
end
|
13
|
+
|
14
|
+
should "have no API by default" do
|
15
|
+
@wunderground = Wunderground.new
|
16
|
+
assert_equal(nil, @wunderground.api_key)
|
17
|
+
end
|
18
|
+
|
19
|
+
should "set an API key in constructor" do
|
20
|
+
@wunderground = Wunderground.new(@api_key)
|
21
|
+
assert_equal(@api_key, @wunderground.api_key)
|
22
|
+
end
|
23
|
+
should 'set timeout and language in constructor' do
|
24
|
+
@wunderground = Wunderground.new(@api_key,timeout: 60, language: 'FR')
|
25
|
+
assert_equal(60,@wunderground.timeout)
|
26
|
+
assert_equal('FR',@wunderground.language)
|
27
|
+
end
|
28
|
+
should "set an API key from the 'WUNDERGROUND_API_KEY' ENV variable" do
|
29
|
+
ENV['WUNDERGROUND_API_KEY'] = @api_key
|
30
|
+
@wunderground = Wunderground.new
|
31
|
+
assert_equal(@api_key, @wunderground.api_key)
|
32
|
+
ENV.delete('WUNDERGROUND_API_KEY')
|
33
|
+
end
|
34
|
+
|
35
|
+
should "set an API key from the 'WUNDERGROUND_APIKEY' ENV variable" do
|
36
|
+
ENV['WUNDERGROUND_APIKEY'] = @api_key
|
37
|
+
@wunderground = Wunderground.new
|
38
|
+
assert_equal(@api_key, @wunderground.api_key)
|
39
|
+
ENV.delete('WUNDERGROUND_APIKEY')
|
40
|
+
end
|
41
|
+
|
42
|
+
should "set an API key via setter" do
|
43
|
+
@wunderground = Wunderground.new
|
44
|
+
@wunderground.api_key = @api_key
|
45
|
+
assert_equal(@api_key, @wunderground.api_key)
|
46
|
+
end
|
47
|
+
|
48
|
+
should "set and get timeout" do
|
49
|
+
@wunderground = Wunderground.new
|
50
|
+
timeout = 30
|
51
|
+
@wunderground.timeout = timeout
|
52
|
+
assert_equal(timeout, @wunderground.timeout)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
context "api url" do
|
57
|
+
setup do
|
58
|
+
@wunderground = Wunderground.new("123")
|
59
|
+
@url = "http://api.wunderground.com/api/123/"
|
60
|
+
end
|
61
|
+
should "raise exception at empty api key" do
|
62
|
+
@wunderground.api_key=nil
|
63
|
+
expect_get(@url,{timeout:30})
|
64
|
+
assert_raise Wunderground::MissingAPIKey do
|
65
|
+
@wunderground.forecast_for("CA","San Fransisco")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
should "contain api key" do
|
70
|
+
expect_get(@url+"forecast/q/ME/Portland.json",{timeout:30})
|
71
|
+
@wunderground.forecast_for("ME","Portland")
|
72
|
+
end
|
73
|
+
should 'contain multiple Wunderground methods from ruby method' do
|
74
|
+
expect_get(@url+"forecast/conditions/q/.json",{timeout: 30})
|
75
|
+
@wunderground.forecast_and_conditions_for()
|
76
|
+
end
|
77
|
+
should 'contain language modifier for method with {lang:"code"} hash' do
|
78
|
+
expect_get(@url+"forecast/lang:FR/q/ME/Portland.json",{timeout: 30})
|
79
|
+
@wunderground.forecast_for("ME","Portland", lang: 'FR')
|
80
|
+
end
|
81
|
+
context 'location parameter' do
|
82
|
+
should 'formats query of type array' do
|
83
|
+
expect_get(@url+"forecast/q/ME/Portland.json",{timeout: 30})
|
84
|
+
@wunderground.forecast_for("ME","Portland")
|
85
|
+
end
|
86
|
+
should 'formats query of type string' do
|
87
|
+
expect_get(@url+"forecast/q/1234.1234,-1234.1234.json",{timeout: 30})
|
88
|
+
@wunderground.forecast_for("1234.1234,-1234.1234")
|
89
|
+
expect_get(@url+"forecast/q/pws:WHAT.json",{timeout: 30})
|
90
|
+
@wunderground.forecast_for("pws:WHAT")
|
91
|
+
end
|
92
|
+
should 'formats query of type geo_ip' do
|
93
|
+
expect_get(@url+"forecast/q/autoip.json?geo_ip=127.0.0.1",{timeout: 30})
|
94
|
+
@wunderground.forecast_for(geo_ip: "127.0.0.1")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
context 'language support' do
|
98
|
+
setup {@wunderground.language = "FR"}
|
99
|
+
should 'automatically set language for all location types' do
|
100
|
+
expect_get(@url+"forecast/lang:FR/q/pws:KCATAHOE2.json",{timeout: 30})
|
101
|
+
@wunderground.forecast_for("pws:KCATAHOE2")
|
102
|
+
end
|
103
|
+
should 'have optional language override on call' do
|
104
|
+
expect_get(@url+"forecast/lang:DE/q/ME/Portland.json",{timeout: 30})
|
105
|
+
@wunderground.forecast_for("ME","Portland", lang: 'DE')
|
106
|
+
end
|
107
|
+
should 'pass language through history helper' do
|
108
|
+
expect_get(@url+"history_#{Time.now.strftime("%Y%m%d")}/lang:DE/q/ME/Portland.json",{timeout: 30})
|
109
|
+
@wunderground.history_for(Time.now,"ME","Portland",lang: 'DE')
|
110
|
+
end
|
111
|
+
should 'pass language through planner helper' do
|
112
|
+
expect_get(@url+"planner_#{Time.now.strftime("%m%d")}#{(Time.now + 700000).strftime('%m%d')}/lang:DE/q/ME/Portland.json",{timeout: 30})
|
113
|
+
@wunderground.planner_for(Time.now,(Time.now+700000),"ME","Portland", lang: 'DE')
|
114
|
+
end
|
115
|
+
should 'pass language through planner helper with IP' do
|
116
|
+
expect_get(@url+"planner_#{Time.now.strftime('%m%d')}#{(Time.now +
|
117
|
+
700000).strftime('%m%d')}/lang:DE/q/autoip.json?geo_ip=127.0.0.1",{timeout: 30})
|
118
|
+
@wunderground.planner_for(Time.now,(Time.now+700000),lang: "DE",geo_ip: "127.0.0.1")
|
119
|
+
end
|
120
|
+
should 'encode string arguments' do
|
121
|
+
expect_get(@url+"planner_#{Time.now.strftime('%m%d')}#{(Time.now +
|
122
|
+
700000).strftime('%m%d')}/lang:DE/q/autoip.json?geo_ip=127.0.0.1",{timeout: 30})
|
123
|
+
@wunderground.planner_for(Time.now,(Time.now+700000),lang: "DE",geo_ip: "127.0.0.1")
|
124
|
+
end
|
125
|
+
end
|
126
|
+
context 'for history_for(date,location) helper' do
|
127
|
+
should 'pass string dates straight to URL' do
|
128
|
+
expect_get(@url+"history_20110121/q/ME/Portland.json",{timeout: 30})
|
129
|
+
@wunderground.history_for("20110121","ME","Portland")
|
130
|
+
end
|
131
|
+
should 'accept Time objects' do
|
132
|
+
expect_get(@url+"history_#{Time.now.strftime("%Y%m%d")}/q/ME/Portland.json",{timeout: 30})
|
133
|
+
@wunderground.history_for(Time.now,"ME","Portland")
|
134
|
+
end
|
135
|
+
should 'accept Date objects' do
|
136
|
+
expect_get(@url+"history_#{Time.now.strftime("%Y%m%d")}/q/ME/Portland.json",{timeout: 30})
|
137
|
+
@wunderground.history_for(Time.now.to_date,"ME","Portland")
|
138
|
+
end
|
139
|
+
should 'accept Date object and pass optional hash object' do
|
140
|
+
expect_get(@url+"history_#{Time.now.strftime("%Y%m%d")}/lang:FR/q/autoip.json?geo_ip=127.0.0.1",{timeout: 30})
|
141
|
+
@wunderground.history_for(Time.now.to_datetime,geo_ip: '127.0.0.1',lang: 'FR')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
context 'for planner_for helper' do
|
145
|
+
should 'pass string date ranges through' do
|
146
|
+
expect_get(@url+"planner_03130323/q/ME/Portland.json",timeout: 30)
|
147
|
+
@wunderground.planner_for("03130323","ME","Portland")
|
148
|
+
end
|
149
|
+
should 'turn two date objects into a properly formatted string' do
|
150
|
+
expect_get(@url+"planner_#{Time.now.strftime('%m%d')}#{(Time.now +
|
151
|
+
700000).strftime('%m%d')}/lang:FR/q/autoip.json?geo_ip=127.0.0.1",timeout: 30)
|
152
|
+
@wunderground.planner_for(Time.now,(Time.now + 700000),geo_ip: '127.0.0.1',lang:'FR')
|
153
|
+
end
|
154
|
+
end
|
155
|
+
context 'timeout passed through optional hash' do
|
156
|
+
should 'work for helper' do
|
157
|
+
expect_get(@url+"planner_#{Time.now.strftime('%m%d')}#{(Time.now+700000).strftime('%m%d')}/lang:FR/q/autoip.json?geo_ip=127.0.0.1",timeout: 60)
|
158
|
+
@wunderground.planner_for(Time.now,(Time.now + 700000),geo_ip: '127.0.0.1',lang:'FR',timeout: 60)
|
159
|
+
end
|
160
|
+
should 'work for regular calls' do
|
161
|
+
expect_get(@url+"forecast/q/pws:WHAT.json",timeout: 60)
|
162
|
+
@wunderground.forecast_for("pws:WHAT", timeout: 60)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
context "Wunderground instances" do
|
169
|
+
setup do
|
170
|
+
@key = "TESTKEY"
|
171
|
+
@wunderground = Wunderground.new(@key)
|
172
|
+
@url = "http://api.wunderground.com/api/TESTKEY/forecast/q/ME/Portland.json"
|
173
|
+
@returns = Struct.new(:body).new(["array", "entries"].to_json)
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
should 'throw exception if non-standard function_for(location) method is called' do
|
178
|
+
assert_raise NoMethodError do
|
179
|
+
@wunderground.scramble
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
should "throw exception if configured to and the API replies with a JSON hash containing a key called 'error'" do
|
184
|
+
@wunderground.throws_exceptions = true
|
185
|
+
Wunderground.stubs(:get).returns(Struct.new(:body).new({response:{'error' => 'bad things'}}.to_json))
|
186
|
+
assert_raise Wunderground::APIError do
|
187
|
+
@wunderground.forecast_for("CA","San_Fransisco")
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
|
193
|
+
private
|
194
|
+
|
195
|
+
def expect_get(expected_url,expected_options={})
|
196
|
+
Wunderground.expects(:get).with{|url, opts|
|
197
|
+
url == expected_url &&
|
198
|
+
opts[:timeout] == expected_options[:timeout]
|
199
|
+
}.returns(Struct.new(:body).new("") )
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "wunderground"
|
8
|
+
s.version = "1.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Winfred Nadeau"]
|
12
|
+
s.date = "2012-07-03"
|
13
|
+
s.description = "A simple ruby API wrapper for interacting with the Wunderground API"
|
14
|
+
s.email = "winfred.nadeau@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"Gemfile",
|
21
|
+
"LICENSE.txt",
|
22
|
+
"README.markdown",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION",
|
25
|
+
"lib/wunderground.rb",
|
26
|
+
"test/helper.rb",
|
27
|
+
"test/test_wunderground.rb",
|
28
|
+
"wunderground.gemspec",
|
29
|
+
"wunderground_ruby.gemspec"
|
30
|
+
]
|
31
|
+
s.homepage = "http://github.com/wnadeau/wunderground_ruby"
|
32
|
+
s.licenses = ["MIT"]
|
33
|
+
s.require_paths = ["lib"]
|
34
|
+
s.rubygems_version = "1.8.10"
|
35
|
+
s.summary = "A simple ruby API wrapper for interacting with the Wunderground API"
|
36
|
+
s.test_files = [
|
37
|
+
"test/helper.rb",
|
38
|
+
"test/test_wunderground.rb"
|
39
|
+
]
|
40
|
+
|
41
|
+
if s.respond_to? :specification_version then
|
42
|
+
s.specification_version = 3
|
43
|
+
|
44
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
45
|
+
s.add_runtime_dependency(%q<json>, ["> 1.4.0"])
|
46
|
+
s.add_runtime_dependency(%q<httparty>, ["> 0.6.0"])
|
47
|
+
s.add_runtime_dependency(%q<addressable>, [">= 0"])
|
48
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
49
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
50
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
|
51
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
52
|
+
s.add_development_dependency(%q<mocha>, ["> 0.9.11"])
|
53
|
+
s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
|
54
|
+
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<json>, ["> 1.4.0"])
|
57
|
+
s.add_dependency(%q<httparty>, ["> 0.6.0"])
|
58
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
59
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
60
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
61
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
62
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
63
|
+
s.add_dependency(%q<mocha>, ["> 0.9.11"])
|
64
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
65
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
66
|
+
end
|
67
|
+
else
|
68
|
+
s.add_dependency(%q<json>, ["> 1.4.0"])
|
69
|
+
s.add_dependency(%q<httparty>, ["> 0.6.0"])
|
70
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
71
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
72
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
73
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
74
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
75
|
+
s.add_dependency(%q<mocha>, ["> 0.9.11"])
|
76
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
77
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "wunderground_ruby"
|
8
|
+
s.version = "0.3.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Winfred Nadeau"]
|
12
|
+
s.date = "2012-01-22"
|
13
|
+
s.description = "A simple ruby API wrapper for interacting with the Wunderground API"
|
14
|
+
s.email = "winfred.nadeau@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"Gemfile",
|
21
|
+
"LICENSE.txt",
|
22
|
+
"README.markdown",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION",
|
25
|
+
"lib/wunderground.rb",
|
26
|
+
"test/helper.rb",
|
27
|
+
"test/test_wunderground.rb",
|
28
|
+
"wunderground_ruby.gemspec"
|
29
|
+
]
|
30
|
+
s.homepage = "http://github.com/wnadeau/wunderground_ruby"
|
31
|
+
s.licenses = ["MIT"]
|
32
|
+
s.require_paths = ["lib"]
|
33
|
+
s.rubygems_version = "1.8.10"
|
34
|
+
s.summary = "A simple ruby API wrapper for interacting with the Wunderground API"
|
35
|
+
s.test_files = [
|
36
|
+
"test/helper.rb",
|
37
|
+
"test/test_wunderground.rb"
|
38
|
+
]
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
s.specification_version = 3
|
42
|
+
|
43
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
44
|
+
s.add_runtime_dependency(%q<json>, ["> 1.4.0"])
|
45
|
+
s.add_runtime_dependency(%q<httparty>, ["> 0.6.0"])
|
46
|
+
s.add_runtime_dependency(%q<addressable>, [">= 0"])
|
47
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
48
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
49
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
|
50
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
51
|
+
s.add_development_dependency(%q<mocha>, ["> 0.9.11"])
|
52
|
+
s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
|
53
|
+
s.add_development_dependency(%q<ruby-debug>, [">= 0"])
|
54
|
+
else
|
55
|
+
s.add_dependency(%q<json>, ["> 1.4.0"])
|
56
|
+
s.add_dependency(%q<httparty>, ["> 0.6.0"])
|
57
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
58
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
59
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
60
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
61
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
62
|
+
s.add_dependency(%q<mocha>, ["> 0.9.11"])
|
63
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
64
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
65
|
+
end
|
66
|
+
else
|
67
|
+
s.add_dependency(%q<json>, ["> 1.4.0"])
|
68
|
+
s.add_dependency(%q<httparty>, ["> 0.6.0"])
|
69
|
+
s.add_dependency(%q<addressable>, [">= 0"])
|
70
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
71
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
72
|
+
s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
|
73
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
74
|
+
s.add_dependency(%q<mocha>, ["> 0.9.11"])
|
75
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
76
|
+
s.add_dependency(%q<ruby-debug>, [">= 0"])
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
metadata
ADDED
@@ -0,0 +1,172 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wunderground
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Winfred Nadeau
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-07-03 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: json
|
16
|
+
requirement: &70184098296440 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>'
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.4.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *70184098296440
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: httparty
|
27
|
+
requirement: &70184098295860 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>'
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 0.6.0
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *70184098295860
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: addressable
|
38
|
+
requirement: &70184098295260 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *70184098295260
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: shoulda
|
49
|
+
requirement: &70184098294680 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70184098294680
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: bundler
|
60
|
+
requirement: &70184098294100 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ~>
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: 1.0.0
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70184098294100
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jeweler
|
71
|
+
requirement: &70184098293560 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ~>
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: 1.5.1
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *70184098293560
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: simplecov
|
82
|
+
requirement: &70184098292980 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70184098292980
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: mocha
|
93
|
+
requirement: &70184098292400 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>'
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: 0.9.11
|
99
|
+
type: :development
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *70184098292400
|
102
|
+
- !ruby/object:Gem::Dependency
|
103
|
+
name: ruby-debug19
|
104
|
+
requirement: &70184098291460 !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: *70184098291460
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: ruby-debug
|
115
|
+
requirement: &70184098288900 !ruby/object:Gem::Requirement
|
116
|
+
none: false
|
117
|
+
requirements:
|
118
|
+
- - ! '>='
|
119
|
+
- !ruby/object:Gem::Version
|
120
|
+
version: '0'
|
121
|
+
type: :development
|
122
|
+
prerelease: false
|
123
|
+
version_requirements: *70184098288900
|
124
|
+
description: A simple ruby API wrapper for interacting with the Wunderground API
|
125
|
+
email: winfred.nadeau@gmail.com
|
126
|
+
executables: []
|
127
|
+
extensions: []
|
128
|
+
extra_rdoc_files:
|
129
|
+
- LICENSE.txt
|
130
|
+
- README.markdown
|
131
|
+
files:
|
132
|
+
- Gemfile
|
133
|
+
- LICENSE.txt
|
134
|
+
- README.markdown
|
135
|
+
- Rakefile
|
136
|
+
- VERSION
|
137
|
+
- lib/wunderground.rb
|
138
|
+
- test/helper.rb
|
139
|
+
- test/test_wunderground.rb
|
140
|
+
- wunderground.gemspec
|
141
|
+
- wunderground_ruby.gemspec
|
142
|
+
homepage: http://github.com/wnadeau/wunderground_ruby
|
143
|
+
licenses:
|
144
|
+
- MIT
|
145
|
+
post_install_message:
|
146
|
+
rdoc_options: []
|
147
|
+
require_paths:
|
148
|
+
- lib
|
149
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
150
|
+
none: false
|
151
|
+
requirements:
|
152
|
+
- - ! '>='
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '0'
|
155
|
+
segments:
|
156
|
+
- 0
|
157
|
+
hash: -3588021643652236154
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
none: false
|
160
|
+
requirements:
|
161
|
+
- - ! '>='
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
164
|
+
requirements: []
|
165
|
+
rubyforge_project:
|
166
|
+
rubygems_version: 1.8.10
|
167
|
+
signing_key:
|
168
|
+
specification_version: 3
|
169
|
+
summary: A simple ruby API wrapper for interacting with the Wunderground API
|
170
|
+
test_files:
|
171
|
+
- test/helper.rb
|
172
|
+
- test/test_wunderground.rb
|