barometer-weather_bug 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.
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