barometer-weather_bug 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a31444023e366197794d252581b83670556eea74
4
+ data.tar.gz: 258204151d1f49d6fa32c425b299802df1cde018
5
+ SHA512:
6
+ metadata.gz: 3defeebf481c0ffc3aa6b60c50f43268aceeddcee5cc4bc960f8de5105e719d6bae1ee3b82db25db439dedbeb0c25b75d3084e040a1e1436503a383d4725113a
7
+ data.tar.gz: a5d8c680a0aed1dab17a9c2443043202fa5af6d4d49ae7cb9950bf4e5347d2a3c3f2a26372197a7112ab90c85a55c3223c95e21214870fe922d5fcbd34e25f3f
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.0
4
+ - 2.0.0
5
+ - 1.9.3
6
+ script: 'bundle exec rake'
7
+ branches:
8
+ only:
9
+ - master
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
3
+
4
+ gem 'rake'
5
+
6
+ group :development, :test do
7
+ gem 'pry'
8
+ gem 'rspec', '>= 2.11'
9
+ end
10
+
11
+ group :test do
12
+ gem 'barometer-support', '>= 0.0.3'
13
+ gem 'multi_json'
14
+ gem 'vcr'
15
+ gem 'webmock'
16
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Mark Gangl
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # Barometer::WeatherBug
2
+
3
+ [![Build Status](https://travis-ci.org/attack/barometer-weather_bug.png?branch=master)](https://travis-ci.org/attack/barometer-weather_bug)
4
+ [![Gem Version](https://badge.fury.io/rb/barometer-weather_bug.png)](http://badge.fury.io/rb/barometer-weather_bug)
5
+ [![Code Climate](https://codeclimate.com/github/attack/barometer-weather_bug.png)](https://codeclimate.com/github/attack/barometer-weather_bug)
6
+
7
+ A wrapper for the WeatherBug weather API. This wrapper is
8
+ barometer compatiable and can be used with or without barometer.
9
+
10
+ ## Usage
11
+
12
+ This wrapper was designed to be used via [Barometer](https://github.com/attack/barometer), or on its own.
13
+
14
+ ### Directly
15
+
16
+ By using this wrapper directly, you lose any Barometer aggregation and
17
+ failover capabilities. Barometer is still dependency to provide a
18
+ framework for query conversion, weather service integration and data
19
+ processing.
20
+
21
+ ```ruby
22
+ query = Barometer::Query.new('42.7243,-73.6927')
23
+ keys = {api: 'forecast io apikey'}
24
+
25
+ result = Barometer::WeatherBug.call(query, keys: keys)
26
+ puts result.current.temperature.c
27
+ ```
28
+
29
+ ### via Barometer
30
+
31
+ Barometer is a weather service framework, providing aggregation and failover
32
+ capabilities. To make WeatherBug available to Barometer, you must register
33
+ it as an available weather service.
34
+
35
+ ```ruby
36
+ Barometer::WeatherService.register(:weather_bug, Barometer::WeatherBug)
37
+ ```
38
+
39
+ Then follow the instructions provided by [Barometer](https://github.com/attack/barometer).
40
+
41
+ ## Contributing
42
+
43
+ 1. Fork it
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create new Pull Request
48
+
49
+ ## Links
50
+
51
+ * repo: http://github.com/attack/barometer-weather_bug
52
+ * travis ci: https://travis-ci.org/attack/barometer-weather_bug
53
+ * code climate: https://codeclimate.com/github/attack/barometer-weather_bug
54
+
55
+ ## Copyright
56
+
57
+ Copyright (c) 2009-2014 Mark Gangl. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'rake'
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec) do |spec|
7
+ spec.pattern = 'spec/**/*_spec.rb'
8
+ spec.rspec_opts = ['--color']
9
+ end
10
+
11
+ task default: :spec
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+ $:.push File.expand_path('../lib', __FILE__)
3
+ require 'barometer/weather_bug/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'barometer-weather_bug'
7
+ spec.version = Barometer::WeatherBug::VERSION
8
+ spec.authors = ['Mark Gangl']
9
+ spec.email = ['mark@attackcorp.com']
10
+ spec.description = 'A barometer adapter for WeatherBug'
11
+ spec.summary = spec.description
12
+ spec.homepage = 'http://github.com/attack/barometer-weather_bug'
13
+ spec.license = 'MIT'
14
+
15
+ spec.platform = Gem::Platform::RUBY
16
+ spec.required_ruby_version = '>= 1.9.2'
17
+
18
+ spec.files = `git ls-files`.split($/)
19
+ spec.test_files = spec.files.grep(%r{^spec/})
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'barometer', '~> 0.9.5'
23
+
24
+ spec.add_development_dependency 'bundler'
25
+ end
@@ -0,0 +1,41 @@
1
+ require 'barometer'
2
+ require_relative 'weather_bug/version'
3
+ require_relative 'weather_bug/current_api'
4
+ require_relative 'weather_bug/current_response'
5
+ require_relative 'weather_bug/forecast_api'
6
+ require_relative 'weather_bug/forecast_response'
7
+
8
+ module Barometer
9
+ class WeatherBug
10
+ def self.call(query, config={})
11
+ WeatherBug.new(query, config).measure!
12
+ end
13
+
14
+ def initialize(query, config={})
15
+ @query = query
16
+ @api_code = config[:keys][:code] if config[:keys]
17
+ end
18
+
19
+ def measure!
20
+ validate_key!
21
+
22
+ current_weather_api = CurrentApi.new(query, api_code)
23
+ response = CurrentResponse.new.parse(current_weather_api.get)
24
+
25
+ forecast_weather_api = ForecastApi.new(current_weather_api.query, api_code)
26
+ ForecastResponse.new(response).parse(forecast_weather_api.get)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :query, :api_code
32
+
33
+ def validate_key!
34
+ unless api_code && !api_code.empty?
35
+ raise Barometer::WeatherService::KeyRequired
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ Barometer::WeatherService.register(:weather_bug, Barometer::WeatherBug)
@@ -0,0 +1,24 @@
1
+ require_relative 'query'
2
+
3
+ module Barometer
4
+ class WeatherBug
5
+ class CurrentApi < Utils::Api
6
+ def initialize(query, api_code)
7
+ @query = WeatherBug::Query.new(query)
8
+ @api_code = api_code
9
+ end
10
+
11
+ def url
12
+ "http://#{@api_code}.api.wxbug.net/getLiveWeatherRSS.aspx"
13
+ end
14
+
15
+ def params
16
+ {ACode: @api_code, OutputType: '1'}.merge(@query.to_param)
17
+ end
18
+
19
+ def unwrap_nodes
20
+ ['weather', 'ob']
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,31 @@
1
+ require_relative 'response/timezone'
2
+ require_relative 'response/current_weather'
3
+ require_relative 'response/station'
4
+
5
+ module Barometer
6
+ class WeatherBug
7
+ class CurrentResponse
8
+ def initialize
9
+ @response = Barometer::Response.new
10
+ end
11
+
12
+ def parse(payload)
13
+ response.add_query(payload.query)
14
+
15
+ response.timezone = WeatherBug::Response::TimeZone.new(payload).parse
16
+ response.current = WeatherBug::Response::CurrentWeather.new(payload, timezone).parse
17
+ response.station = WeatherBug::Response::Station.new(payload).parse
18
+
19
+ response
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :response
25
+
26
+ def timezone
27
+ response.timezone
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'query'
2
+
3
+ module Barometer
4
+ class WeatherBug
5
+ class ForecastApi < Utils::Api
6
+ def initialize(query, api_code)
7
+ @query = WeatherBug::Query.new(query)
8
+ @api_code = api_code
9
+ end
10
+
11
+ def url
12
+ "http://#{@api_code}.api.wxbug.net/getForecastRSS.aspx"
13
+ end
14
+
15
+ def params
16
+ {ACode: @api_code, OutputType: '1'}.merge(@query.to_param)
17
+ end
18
+
19
+ def unwrap_nodes
20
+ ['weather', 'forecasts']
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,27 @@
1
+ require_relative 'response/forecasted_weather'
2
+ require_relative 'response/location'
3
+
4
+ module Barometer
5
+ class WeatherBug
6
+ class ForecastResponse
7
+ def initialize(response)
8
+ @response = response
9
+ end
10
+
11
+ def parse(payload)
12
+ response.forecast = WeatherBug::Response::ForecastedWeather.new(payload, timezone).parse
13
+ response.location = WeatherBug::Response::Location.new(payload).parse
14
+
15
+ response
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :response
21
+
22
+ def timezone
23
+ response.timezone
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,40 @@
1
+ require 'delegate'
2
+
3
+ module Barometer
4
+ class WeatherBug
5
+ class Query < SimpleDelegator
6
+ attr_reader :converted_query
7
+
8
+ def self.accepted_formats
9
+ [:short_zipcode, :coordinates]
10
+ end
11
+
12
+ def initialize(query)
13
+ super
14
+ @converted_query = convert_query
15
+ end
16
+
17
+ def to_param
18
+ {UnitType: unit_type}.merge(format_query)
19
+ end
20
+
21
+ private
22
+
23
+ def convert_query
24
+ convert!(*self.class.accepted_formats)
25
+ end
26
+
27
+ def format_query
28
+ if converted_query.format == :short_zipcode
29
+ {zipCode: converted_query.q}
30
+ else
31
+ {lat: converted_query.geo.latitude, long: converted_query.geo.longitude}
32
+ end
33
+ end
34
+
35
+ def unit_type
36
+ converted_query.metric? ? '1' : '0'
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,80 @@
1
+ require_relative 'time_helper'
2
+ require_relative 'sun'
3
+
4
+ module Barometer
5
+ class WeatherBug
6
+ class Response
7
+ class CurrentWeather
8
+ def initialize(payload, timezone)
9
+ @payload = payload
10
+ @timezone = timezone
11
+ @current = Barometer::Response::Current.new
12
+ end
13
+
14
+ def parse
15
+ current.observed_at = observed_at
16
+ current.stale_at = stale_at
17
+ current.humidity = humidity
18
+ current.condition = condition
19
+ current.icon = icon
20
+ current.temperature = temperature
21
+ current.dew_point = dew_point
22
+ current.wind_chill = wind_chill
23
+ current.wind = wind
24
+ current.pressure = pressure
25
+ current.sun = WeatherBug::Response::Sun.new(payload, timezone).parse
26
+
27
+ current
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :payload, :timezone, :current
33
+
34
+ def units
35
+ payload.units
36
+ end
37
+
38
+ def observed_at
39
+ @observed_at ||= TimeHelper.new(payload, timezone).parse('ob_date')
40
+ end
41
+
42
+ def stale_at
43
+ Utils::Time.add_one_hour(observed_at)
44
+ end
45
+
46
+ def humidity
47
+ payload.fetch('humidity')
48
+ end
49
+
50
+ def condition
51
+ payload.fetch('current_condition')
52
+ end
53
+
54
+ def icon
55
+ payload.using(/cond(\d*)\.gif/).fetch('current_condition', '@icon')
56
+ end
57
+
58
+ def temperature
59
+ [units, payload.fetch('temp')]
60
+ end
61
+
62
+ def dew_point
63
+ [units, payload.fetch('dew_point')]
64
+ end
65
+
66
+ def wind_chill
67
+ [units, payload.fetch('feels_like')]
68
+ end
69
+
70
+ def wind
71
+ [units, payload.fetch('wind_speed'), payload.fetch('wind_direction_degrees')]
72
+ end
73
+
74
+ def pressure
75
+ [units, payload.fetch('pressure')]
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,65 @@
1
+ module Barometer
2
+ class WeatherBug
3
+ class Response
4
+ class ForecastedWeather
5
+ def initialize(payload, timezone)
6
+ @payload = payload
7
+ @timezone = timezone
8
+ @predictions = Barometer::Response::PredictionCollection.new
9
+ end
10
+
11
+ def parse
12
+ each_prediction do |prediction, forecast_payload, index|
13
+ prediction.date = date(index), timezone
14
+ prediction.condition = condition(forecast_payload)
15
+ prediction.icon = icon(forecast_payload)
16
+ prediction.high = high(forecast_payload)
17
+ prediction.low = low(forecast_payload)
18
+ end
19
+
20
+ predictions
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :payload, :timezone, :predictions
26
+
27
+ def units
28
+ payload.units
29
+ end
30
+
31
+ def each_prediction
32
+ payload.fetch_each_with_index('forecast') do |forecast_payload, index|
33
+ predictions.build do |prediction|
34
+ yield prediction, forecast_payload, index
35
+ end
36
+ end
37
+ end
38
+
39
+ def start_date
40
+ Date.strptime(payload.fetch('@date'), '%m/%d/%Y %H:%M:%S %p')
41
+ end
42
+
43
+ def date(index)
44
+ start_date + index
45
+ end
46
+
47
+ def condition(forecast_payload)
48
+ forecast_payload.fetch('short_prediction')
49
+ end
50
+
51
+ def icon(forecast_payload)
52
+ forecast_payload.using(/cond0*([1-9][0-9]*)\.gif$/).fetch('image')
53
+ end
54
+
55
+ def high(forecast_payload)
56
+ [units, forecast_payload.fetch('high')]
57
+ end
58
+
59
+ def low(forecast_payload)
60
+ [units, forecast_payload.fetch('low')]
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,21 @@
1
+ module Barometer
2
+ class WeatherBug
3
+ class Response
4
+ class Location < WeatherService::Response::Location
5
+ private
6
+
7
+ def city
8
+ payload.fetch('location', 'city')
9
+ end
10
+
11
+ def state_code
12
+ payload.fetch('location', 'state')
13
+ end
14
+
15
+ def zip_code
16
+ payload.fetch('location', 'zip')
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,41 @@
1
+ module Barometer
2
+ class WeatherBug
3
+ class Response
4
+ class Station < WeatherService::Response::Location
5
+ private
6
+
7
+ def id
8
+ payload.fetch('station_id')
9
+ end
10
+
11
+ def name
12
+ payload.fetch('station')
13
+ end
14
+
15
+ def city
16
+ payload.using(/^([\w ]*?),/).fetch('city_state')
17
+ end
18
+
19
+ def state_code
20
+ payload.using(/^[\w ^,]*?,([\w ^,]*)/).fetch('city_state')
21
+ end
22
+
23
+ def country
24
+ payload.fetch('country')
25
+ end
26
+
27
+ def zip_code
28
+ payload.fetch('city_state', '@zipcode')
29
+ end
30
+
31
+ def latitude
32
+ payload.fetch('latitude')
33
+ end
34
+
35
+ def longitude
36
+ payload.fetch('longitude')
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,30 @@
1
+ require_relative 'time_helper'
2
+
3
+ module Barometer
4
+ class WeatherBug
5
+ class Response
6
+ class Sun
7
+ def initialize(payload, timezone)
8
+ @payload = payload
9
+ @timezone = timezone
10
+ end
11
+
12
+ def parse
13
+ Data::Sun.new(rise: local_sunrise_time, set: local_sunset_time)
14
+ end
15
+
16
+ private
17
+
18
+ attr_reader :payload, :timezone
19
+
20
+ def local_sunrise_time
21
+ TimeHelper.new(payload, timezone).parse('sunrise')
22
+ end
23
+
24
+ def local_sunset_time
25
+ TimeHelper.new(payload, timezone).parse('sunset')
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,50 @@
1
+ module Barometer
2
+ class WeatherBug
3
+ class Response
4
+ class TimeHelper
5
+ def initialize(payload, timezone)
6
+ @payload = payload
7
+ @timezone = timezone
8
+ end
9
+
10
+ def parse(key)
11
+ return unless local_time(key)
12
+ timezone.local_to_utc(local_time(key))
13
+ end
14
+
15
+ private
16
+
17
+ attr_reader :payload, :timezone, :key
18
+
19
+ def local_time(key)
20
+ @key = key
21
+ @local_time ||= Utils::Time.parse(year, month, day, hour, minute, second)
22
+ end
23
+
24
+ def year
25
+ payload.fetch(key, 'year', '@number')
26
+ end
27
+
28
+ def month
29
+ payload.fetch(key, 'month', '@number')
30
+ end
31
+
32
+ def day
33
+ payload.fetch(key, 'day', '@number')
34
+ end
35
+
36
+ def hour
37
+ payload.fetch(key, 'hour', '@hour_24')
38
+ end
39
+
40
+ def minute
41
+ payload.fetch(key, 'minute', '@number')
42
+ end
43
+
44
+ def second
45
+ payload.fetch(key, 'second', '@number')
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,13 @@
1
+ module Barometer
2
+ class WeatherBug
3
+ class Response
4
+ class TimeZone < WeatherService::Response::TimeZone
5
+ private
6
+
7
+ def time_zone
8
+ payload.fetch('ob_date', 'time_zone', '@abbrv')
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module Barometer
2
+ class WeatherBug
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ {"http_interactions":[{"request":{"method":"get","uri":"http://WEATHERBUG_CODE.api.wxbug.net/getLiveWeatherRSS.aspx?ACode=WEATHERBUG_CODE&OutputType=1&UnitType=1&zipCode=90210","body":{"encoding":"UTF-8","string":""},"headers":{}},"response":{"status":{"code":200,"message":"OK"},"headers":{"Cache-Control":["private"],"Content-Type":["application/xml; charset=utf-8"],"Date":["Sat, 26 Oct 2013 14:55:07 GMT"],"Server":["Microsoft-IIS/7.5"],"Set-Cookie":["ASP.NET_SessionId=2q2lm10ejga21x3jdps0f0rm; path=/; HttpOnly"],"X-Aspnet-Version":["4.0.30319"],"X-Powered-By":["ASP.NET"],"Content-Length":["4076"],"Connection":["keep-alive"]},"body":{"encoding":"UTF-8","string":"<aws:weather xmlns:aws=\"http://www.aws.com/aws\"><aws:api version=\"2.0\" /><aws:WebURL>http://weather.weatherbug.com/CA/Valley Village-weather.html?ZCode=Z5546&amp;Units=1&amp;stat=NRTSH</aws:WebURL><aws:InputLocationURL>http://weather.weatherbug.com/CA/Beverly Hills-weather.html?ZCode=Z5546&amp;Units=1</aws:InputLocationURL><aws:ob><aws:ob-date><aws:year number=\"2013\" /><aws:month number=\"10\" text=\"October\" abbrv=\"Oct\" /><aws:day number=\"26\" text=\"Saturday\" abbrv=\"Sat\" /><aws:hour number=\"7\" hour-24=\"07\" /><aws:minute number=\"54\" /><aws:second number=\"00\" /><aws:am-pm abbrv=\"AM\" /><aws:time-zone offset=\"-7\" text=\"Pacific Daylight Time (USA)\" abbrv=\"PDT\" /></aws:ob-date><aws:requested-station-id /><aws:station-id>NRTSH</aws:station-id><aws:station>Campbell Hall School</aws:station><aws:city-state zipcode=\"91617\">Valley Village, CA</aws:city-state><aws:country>USA</aws:country><aws:latitude>34.1536102294922</aws:latitude><aws:longitude>-118.398056030273</aws:longitude><aws:site-url>http://www.campbell.pvt.k12.ca.us/</aws:site-url><aws:aux-temp units=\"&amp;deg;C\">18</aws:aux-temp><aws:aux-temp-rate units=\"&amp;deg;C\">0.0</aws:aux-temp-rate><aws:current-condition icon=\"http://deskwx.weatherbug.com/images/Forecast/icons/cond026.gif\">Mostly Sunny</aws:current-condition><aws:dew-point units=\"&amp;deg;C\">11</aws:dew-point><aws:elevation units=\"m\">192</aws:elevation><aws:feels-like units=\"&amp;deg;C\">12</aws:feels-like><aws:gust-time><aws:year number=\"2013\" /><aws:month number=\"10\" text=\"October\" abbrv=\"Oct\" /><aws:day number=\"26\" text=\"Saturday\" abbrv=\"Sat\" /><aws:hour number=\"12\" hour-24=\"00\" /><aws:minute number=\"59\" /><aws:second number=\"00\" /><aws:am-pm abbrv=\"AM\" /><aws:time-zone offset=\"-7\" text=\"Pacific Daylight Time (USA)\" abbrv=\"PDT\" /></aws:gust-time><aws:gust-direction>S</aws:gust-direction><aws:gust-direction-degrees>174</aws:gust-direction-degrees><aws:gust-speed units=\"km/h\">2</aws:gust-speed><aws:humidity units=\"%\">97</aws:humidity><aws:humidity-high units=\"%\">97</aws:humidity-high><aws:humidity-low units=\"%\">89</aws:humidity-low><aws:humidity-rate>0</aws:humidity-rate><aws:indoor-temp units=\"&amp;deg;C\">24</aws:indoor-temp><aws:indoor-temp-rate units=\"&amp;deg;C\">0</aws:indoor-temp-rate><aws:light>0</aws:light><aws:light-rate>0</aws:light-rate><aws:moon-phase moon-phase-img=\"http://api.wxbug.net/images/moonphase/mphase19.gif\">59</aws:moon-phase><aws:pressure units=\"mb\">1017.27</aws:pressure><aws:pressure-high units=\"mb\">1017.27</aws:pressure-high><aws:pressure-low units=\"mb\">1016.60</aws:pressure-low><aws:pressure-rate units=\"mb/h\">0.68</aws:pressure-rate><aws:rain-month units=\"mm\">0.00</aws:rain-month><aws:rain-rate units=\"mm/h\">0.00</aws:rain-rate><aws:rain-rate-max units=\"mm/h\">0.00</aws:rain-rate-max><aws:rain-today units=\"mm\">0.00</aws:rain-today><aws:rain-year units=\"mm\">87.63</aws:rain-year><aws:temp units=\"&amp;deg;C\">11.9</aws:temp><aws:temp-high units=\"&amp;deg;C\">16</aws:temp-high><aws:temp-low units=\"&amp;deg;C\">11</aws:temp-low><aws:temp-rate units=\"&amp;deg;C/h\">0.6</aws:temp-rate><aws:sunrise><aws:year number=\"2013\" /><aws:month number=\"10\" text=\"October\" abbrv=\"Oct\" /><aws:day number=\"26\" text=\"Saturday\" abbrv=\"Sat\" /><aws:hour number=\"7\" hour-24=\"07\" /><aws:minute number=\"07\" /><aws:second number=\"55\" /><aws:am-pm abbrv=\"AM\" /><aws:time-zone offset=\"-7\" text=\"Pacific Daylight Time (USA)\" abbrv=\"PDT\" /></aws:sunrise><aws:sunset><aws:year number=\"2013\" /><aws:month number=\"10\" text=\"October\" abbrv=\"Oct\" /><aws:day number=\"26\" text=\"Saturday\" abbrv=\"Sat\" /><aws:hour number=\"6\" hour-24=\"18\" /><aws:minute number=\"06\" /><aws:second number=\"47\" /><aws:am-pm abbrv=\"PM\" /><aws:time-zone offset=\"-7\" text=\"Pacific Daylight Time (USA)\" abbrv=\"PDT\" /></aws:sunset><aws:wet-bulb units=\"&amp;deg;C\">11.65</aws:wet-bulb><aws:wind-speed units=\"km/h\">0</aws:wind-speed><aws:wind-speed-avg units=\"km/h\">0</aws:wind-speed-avg><aws:wind-direction>S</aws:wind-direction><aws:wind-direction-degrees>173</aws:wind-direction-degrees><aws:wind-direction-avg>S</aws:wind-direction-avg></aws:ob></aws:weather>\r\n"},"http_version":null},"recorded_at":"Sat, 26 Oct 2013 14:55:07 GMT"},{"request":{"method":"get","uri":"http://WEATHERBUG_CODE.api.wxbug.net/getForecastRSS.aspx?ACode=WEATHERBUG_CODE&OutputType=1&UnitType=1&zipCode=90210","body":{"encoding":"UTF-8","string":""},"headers":{}},"response":{"status":{"code":200,"message":"OK"},"headers":{"Cache-Control":["private"],"Content-Type":["application/xml; charset=utf-8"],"Date":["Sat, 26 Oct 2013 14:55:07 GMT"],"Server":["Microsoft-IIS/7.5"],"Set-Cookie":["ASP.NET_SessionId=ppstsmui0taeaponkcny3cjz; path=/; HttpOnly"],"X-Aspnet-Version":["4.0.30319"],"X-Powered-By":["ASP.NET"],"Content-Length":["4096"],"Connection":["keep-alive"]},"body":{"encoding":"UTF-8","string":"<aws:weather xmlns:aws=\"http://www.aws.com/aws\"><aws:api version=\"2.0\" /><aws:WebURL>http://weather.weatherbug.com/CA/Beverly Hills-weather/local-forecast/7-day-forecast.html?ZCode=Z5546&amp;Units=1</aws:WebURL><aws:forecasts type=\"Detailed\" date=\"10/26/2013 3:15:00 AM\"><aws:location><aws:city>Beverly Hills</aws:city><aws:state>CA</aws:state><aws:zip>90210</aws:zip><aws:zone>CA041</aws:zone></aws:location><aws:forecast><aws:title alttitle=\"SAT\">Saturday</aws:title><aws:short-prediction>Partly Cloudy</aws:short-prediction><aws:image isNight=\"0\" icon=\"cond003.gif\">http://deskwx.weatherbug.com/images/Forecast/icons/cond003.gif</aws:image><aws:description>Saturday</aws:description><aws:prediction>Areas of low clouds and fog in the morning then sunny. Highs from the lower to mid 70s at the beaches to around 80 inland.</aws:prediction><aws:high units=\"&amp;deg;C\">27</aws:high><aws:low units=\"&amp;deg;C\">15</aws:low></aws:forecast><aws:forecast><aws:title alttitle=\"SUN\">Sunday</aws:title><aws:short-prediction>Partly Cloudy</aws:short-prediction><aws:image isNight=\"0\" icon=\"cond003.gif\">http://deskwx.weatherbug.com/images/Forecast/icons/cond003.gif</aws:image><aws:description>Sunday</aws:description><aws:prediction>Areas of low clouds and fog in the morning then sunny. Highs from the upper 60s at the beaches to the upper 70s inland.</aws:prediction><aws:high units=\"&amp;deg;C\">26</aws:high><aws:low units=\"&amp;deg;C\">13</aws:low></aws:forecast><aws:forecast><aws:title alttitle=\"MON\">Monday</aws:title><aws:short-prediction>40% Chance Rain Shower</aws:short-prediction><aws:image isNight=\"0\" icon=\"cond109.gif\">http://deskwx.weatherbug.com/images/Forecast/icons/cond109.gif</aws:image><aws:description>Monday</aws:description><aws:prediction>Mostly cloudy. A slight chance of showers in the morning then a chance of showers in the afternoon. Highs in the 60s. Southeast winds around 15 mph in the afternoon. Chance of precipitation 40 percent.</aws:prediction><aws:high units=\"&amp;deg;C\">18</aws:high><aws:low units=\"&amp;deg;C\">11</aws:low></aws:forecast><aws:forecast><aws:title alttitle=\"TUE\">Tuesday</aws:title><aws:short-prediction>Partly Cloudy</aws:short-prediction><aws:image isNight=\"0\" icon=\"cond003.gif\">http://deskwx.weatherbug.com/images/Forecast/icons/cond003.gif</aws:image><aws:description>Tuesday</aws:description><aws:prediction>Mostly cloudy with a 20 percent chance of showers in the morning then partly cloudy in the afternoon. Highs in the lower to mid 60s.</aws:prediction><aws:high units=\"&amp;deg;C\">17</aws:high><aws:low units=\"&amp;deg;C\">12</aws:low></aws:forecast><aws:forecast><aws:title alttitle=\"WED\">Wednesday</aws:title><aws:short-prediction>Mostly Sunny</aws:short-prediction><aws:image isNight=\"0\" icon=\"cond026.gif\">http://deskwx.weatherbug.com/images/Forecast/icons/cond026.gif</aws:image><aws:description>Wednesday</aws:description><aws:prediction>Mostly clear. Highs from the mid 60s at the beaches to the mid 70s inland. Lows in the 50s.</aws:prediction><aws:high units=\"&amp;deg;C\">22</aws:high><aws:low units=\"&amp;deg;C\">12</aws:low></aws:forecast><aws:forecast><aws:title alttitle=\"THU\">Thursday</aws:title><aws:short-prediction>Mostly Sunny</aws:short-prediction><aws:image isNight=\"0\" icon=\"cond026.gif\">http://deskwx.weatherbug.com/images/Forecast/icons/cond026.gif</aws:image><aws:description>Thursday</aws:description><aws:prediction>Mostly clear. Highs from the mid 60s at the beaches to the mid 70s inland. Lows in the 50s.</aws:prediction><aws:high units=\"&amp;deg;C\">23</aws:high><aws:low units=\"&amp;deg;C\">13</aws:low></aws:forecast><aws:forecast><aws:title alttitle=\"FRI\">Friday</aws:title><aws:short-prediction>Sunny</aws:short-prediction><aws:image isNight=\"0\" icon=\"cond007.gif\">http://deskwx.weatherbug.com/images/Forecast/icons/cond007.gif</aws:image><aws:description>Friday</aws:description><aws:prediction>Sunny. Highs from around 70 at the beaches to around 80 inland.</aws:prediction><aws:high units=\"&amp;deg;C\">26</aws:high><aws:low units=\"&amp;deg;C\">--</aws:low></aws:forecast></aws:forecasts></aws:weather>\r\n"},"http_version":null},"recorded_at":"Sat, 26 Oct 2013 14:55:07 GMT"}],"recorded_with":"VCR 2.6.0"}
@@ -0,0 +1,31 @@
1
+ require 'rspec'
2
+ require 'pry'
3
+ require 'vcr'
4
+ require 'webmock/rspec'
5
+ require 'barometer/support'
6
+
7
+ require_relative '../lib/barometer/weather_bug'
8
+
9
+ Dir['./spec/support/**/*.rb'].sort.each {|f| require f}
10
+
11
+ WEATHERBUG_CODE = Barometer::Support::KeyFileParser.find(:weather_bug, :code) || 'weatherbug'
12
+ downcased_weatherbug_code = WEATHERBUG_CODE.to_s
13
+ downcased_weatherbug_code[0] = WEATHERBUG_CODE.to_s[0..0].downcase
14
+
15
+ VCR.configure do |config|
16
+ config.cassette_library_dir = 'spec/cassettes'
17
+ config.hook_into :webmock
18
+ config.default_cassette_options = { record: :none, serialize_with: :json }
19
+
20
+ config.filter_sensitive_data('WEATHERBUG_CODE') { WEATHERBUG_CODE.to_s }
21
+ # weather bug uses api as host name. this is downcased when the request it made
22
+ config.filter_sensitive_data('WEATHERBUG_CODE') { downcased_weatherbug_code }
23
+
24
+ config.configure_rspec_metadata!
25
+ end
26
+
27
+ RSpec.configure do |config|
28
+ config.treat_symbols_as_metadata_keys_with_true_values = true
29
+ config.include Barometer::Support::Matchers
30
+ config.include Barometer::Support::Factory
31
+ end
@@ -0,0 +1,64 @@
1
+ require_relative '../spec_helper'
2
+
3
+ module Barometer
4
+ describe WeatherBug::CurrentResponse do
5
+ it "parses the timezones correctly" do
6
+ payload = Barometer::Utils::Payload.new({
7
+ 'ob_date' => {
8
+ 'year' => { '@number' => '2013' },
9
+ 'month' => { '@number' => '5' },
10
+ 'day' => { '@number' => '18' },
11
+ 'hour' => { '@hour_24' => '10' },
12
+ 'minute' => { '@number' => '46' },
13
+ 'second' => { '@number' => '0' },
14
+ 'time_zone' => { '@abbrv' => 'PDT' }
15
+ }
16
+ })
17
+ response = WeatherBug::CurrentResponse.new.parse(payload)
18
+
19
+ utc_observed_at = Time.utc(2013,5,18,17,46,0)
20
+ utc_stale_at = Time.utc(2013,5,18,18,46,0)
21
+
22
+ expect( response.current.observed_at.utc ).to eq utc_observed_at
23
+ expect( response.current.stale_at.utc ).to eq utc_stale_at
24
+ expect( response.timezone.to_s ).to eq 'PDT'
25
+ end
26
+
27
+ it "parses sun timezones correctly" do
28
+ payload = Barometer::Utils::Payload.new({
29
+ 'ob_date' => {
30
+ 'year' => { '@number' => '2013' },
31
+ 'month' => { '@number' => '4' },
32
+ 'day' => { '@number' => '13' },
33
+ 'hour' => { '@hour_24' => '10' },
34
+ 'minute' => { '@number' => '23' },
35
+ 'second' => { '@number' => '0' },
36
+ 'time_zone' => { '@abbrv' => 'PDT' }
37
+ },
38
+ 'sunrise' => {
39
+ 'year' => { '@number' => '2013' },
40
+ 'month' => { '@number' => '4' },
41
+ 'day' => { '@number' => '13' },
42
+ 'hour' => { '@hour_24' => '6' },
43
+ 'minute' => { '@number' => '44' },
44
+ 'second' => { '@number' => '19' },
45
+ },
46
+ 'sunset' => {
47
+ 'year' => { '@number' => '2013' },
48
+ 'month' => { '@number' => '4' },
49
+ 'day' => { '@number' => '13' },
50
+ 'hour' => { '@hour_24' => '17' },
51
+ 'minute' => { '@number' => '31' },
52
+ 'second' => { '@number' => '50' },
53
+ }
54
+ })
55
+ response = WeatherBug::CurrentResponse.new.parse(payload)
56
+
57
+ utc_current_sun_rise = Time.utc(2013,4,13,13,44,19)
58
+ utc_current_sun_set = Time.utc(2013,4,14,0,31,50)
59
+
60
+ expect( response.current.sun.rise.utc ).to eq utc_current_sun_rise
61
+ expect( response.current.sun.set.utc ).to eq utc_current_sun_set
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,23 @@
1
+ require_relative '../spec_helper'
2
+
3
+ module Barometer
4
+ describe WeatherBug::ForecastResponse do
5
+ let(:current_response) { Barometer::Response.new }
6
+
7
+ it "parses the timezones correctly" do
8
+ current_response.timezone = Barometer::Data::Zone.new('PDT')
9
+
10
+ payload = Barometer::Utils::Payload.new({
11
+ "@date" => "4/13/2013 10:23:00 AM",
12
+ "forecast" => [{"high" => "13"}]
13
+ })
14
+ response = WeatherBug::ForecastResponse.new(current_response).parse(payload)
15
+
16
+ utc_starts_at = Time.utc(2013,4,13,7,0,0)
17
+ utc_ends_at = Time.utc(2013,4,14,6,59,59)
18
+
19
+ expect( response.forecast[0].starts_at.utc ).to eq utc_starts_at
20
+ expect( response.forecast[0].ends_at.utc ).to eq utc_ends_at
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,44 @@
1
+ require_relative '../spec_helper'
2
+
3
+ module Barometer
4
+ describe WeatherBug::Query do
5
+ describe '#to_param' do
6
+ let(:converted_query) { double(:converted_query).as_null_object }
7
+ let(:query) { WeatherBug::Query.new(converted_query) }
8
+
9
+ context 'when the query is a :short_zipcode' do
10
+ before { converted_query.stub(format: :short_zipcode, q: '90210') }
11
+
12
+ it 'includes the correct parameters' do
13
+ expect( query.to_param[:zipCode] ).to eq '90210'
14
+ end
15
+ end
16
+
17
+ context 'and the query is a :coordinates' do
18
+ let(:geo) { double(:geo, latitude: '11.22', longitude: '33.44') }
19
+ before { converted_query.stub(format: :coordinates, geo: geo) }
20
+
21
+ it 'includes the correct parameters' do
22
+ expect( query.to_param[:lat] ).to eq '11.22'
23
+ expect( query.to_param[:long] ).to eq '33.44'
24
+ end
25
+ end
26
+
27
+ context 'and the query is metric' do
28
+ before { converted_query.stub(metric?: true) }
29
+
30
+ it 'includes the correct parameters' do
31
+ expect( query.to_param[:UnitType] ).to eq '1'
32
+ end
33
+ end
34
+
35
+ context 'and the query is imperial' do
36
+ before { converted_query.stub(metric?: false) }
37
+
38
+ it 'includes the correct parameters' do
39
+ expect( query.to_param[:UnitType] ).to eq '0'
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,80 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module Barometer
4
+ describe WeatherBug, vcr: {
5
+ cassette_name: 'WeatherService::WeatherBug'
6
+ } do
7
+
8
+ it 'auto-registers this weather service as :weather_bug' do
9
+ expect( Barometer::WeatherService.source(:weather_bug) ).to eq Barometer::WeatherBug
10
+ end
11
+
12
+ describe '.call' do
13
+ context 'when no keys are provided' do
14
+ let(:query) { build_query }
15
+
16
+ it 'raises an error' do
17
+ expect {
18
+ WeatherBug.call(query)
19
+ }.to raise_error(Barometer::WeatherService::KeyRequired)
20
+ end
21
+ end
22
+
23
+ context 'when keys are provided' do
24
+ let(:converted_query) { ConvertedQuery.new('90210', :short_zipcode, :metric) }
25
+ let(:query) { build_query.tap{|q|q.stub(:convert! => converted_query)} }
26
+ let(:config) { {keys: {code: WEATHERBUG_CODE}} }
27
+
28
+ subject { WeatherBug.call(query, config) }
29
+
30
+ it 'converts the query to accepted formats' do
31
+ subject
32
+ expect( query ).to have_received(:convert!).with(:short_zipcode, :coordinates).at_least(:once)
33
+ end
34
+
35
+ it 'includes the expected data' do
36
+ expect( subject.query ).to eq '90210'
37
+ expect( subject.format ).to eq :short_zipcode
38
+ expect( subject ).to be_metric
39
+
40
+ should have_data(:current, :observed_at).as_format(:time)
41
+ should have_data(:current, :stale_at).as_format(:time)
42
+
43
+ should have_data(:current, :humidity).as_format(:float)
44
+ should have_data(:current, :condition).as_format(:string)
45
+ should have_data(:current, :icon).as_format(:number)
46
+ should have_data(:current, :temperature).as_format(:temperature)
47
+ should have_data(:current, :dew_point).as_format(:temperature)
48
+ should have_data(:current, :wind_chill).as_format(:temperature)
49
+ should have_data(:current, :wind).as_format(:vector)
50
+ should have_data(:current, :pressure).as_format(:pressure)
51
+ should have_data(:current, :sun, :rise).as_format(:time)
52
+ should have_data(:current, :sun, :set).as_format(:time)
53
+
54
+ should have_data(:station, :id).as_value('NRTSH')
55
+ should have_data(:station, :name).as_value('Campbell Hall School')
56
+ should have_data(:station, :city).as_value('Valley Village')
57
+ should have_data(:station, :state_code).as_value('CA')
58
+ should have_data(:station, :country).as_value('USA')
59
+ should have_data(:station, :zip_code).as_value('91617')
60
+ should have_data(:station, :latitude).as_value(34.1536102294922)
61
+ should have_data(:station, :longitude).as_value(-118.398056030273)
62
+
63
+ should have_data(:location, :city).as_value('Beverly Hills')
64
+ should have_data(:location, :state_code).as_value('CA')
65
+ should have_data(:location, :zip_code).as_value('90210')
66
+
67
+ should have_data(:timezone, :to_s).as_format(/^P[DS]T$/i)
68
+
69
+ expect( subject.forecast.size ).to eq 7
70
+ should have_forecast(:starts_at).as_format(:time)
71
+ should have_forecast(:ends_at).as_format(:time)
72
+ should have_forecast(:condition).as_format(:string)
73
+ should have_forecast(:icon).as_format(:number)
74
+ should have_forecast(:high).as_format(:temperature)
75
+ should have_forecast(:low).as_format(:temperature)
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: barometer-weather_bug
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mark Gangl
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: barometer
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.5
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.9.5
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ description: A barometer adapter for WeatherBug
42
+ email:
43
+ - mark@attackcorp.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - ".rspec"
50
+ - ".travis.yml"
51
+ - Gemfile
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - barometer-weather_bug.gemspec
56
+ - lib/barometer/weather_bug.rb
57
+ - lib/barometer/weather_bug/current_api.rb
58
+ - lib/barometer/weather_bug/current_response.rb
59
+ - lib/barometer/weather_bug/forecast_api.rb
60
+ - lib/barometer/weather_bug/forecast_response.rb
61
+ - lib/barometer/weather_bug/query.rb
62
+ - lib/barometer/weather_bug/response/current_weather.rb
63
+ - lib/barometer/weather_bug/response/forecasted_weather.rb
64
+ - lib/barometer/weather_bug/response/location.rb
65
+ - lib/barometer/weather_bug/response/station.rb
66
+ - lib/barometer/weather_bug/response/sun.rb
67
+ - lib/barometer/weather_bug/response/time_helper.rb
68
+ - lib/barometer/weather_bug/response/timezone.rb
69
+ - lib/barometer/weather_bug/version.rb
70
+ - spec/cassettes/WeatherService_WeatherBug.json
71
+ - spec/spec_helper.rb
72
+ - spec/weather_bug/current_response_spec.rb
73
+ - spec/weather_bug/forecast_response_spec.rb
74
+ - spec/weather_bug/query_spec.rb
75
+ - spec/weather_bug_spec.rb
76
+ homepage: http://github.com/attack/barometer-weather_bug
77
+ licenses:
78
+ - MIT
79
+ metadata: {}
80
+ post_install_message:
81
+ rdoc_options: []
82
+ require_paths:
83
+ - lib
84
+ required_ruby_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: 1.9.2
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ requirements: []
95
+ rubyforge_project:
96
+ rubygems_version: 2.2.2
97
+ signing_key:
98
+ specification_version: 4
99
+ summary: A barometer adapter for WeatherBug
100
+ test_files:
101
+ - spec/cassettes/WeatherService_WeatherBug.json
102
+ - spec/spec_helper.rb
103
+ - spec/weather_bug/current_response_spec.rb
104
+ - spec/weather_bug/forecast_response_spec.rb
105
+ - spec/weather_bug/query_spec.rb
106
+ - spec/weather_bug_spec.rb