sunwatch 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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fc61d157134686bb9e81364c4e6256c8c19cfa76
4
+ data.tar.gz: cbd1035338fb569bff8d9b19f978eed5f6ed65b2
5
+ SHA512:
6
+ metadata.gz: b0fde179369635f18a32b9f6bf381d067f0dc953c9d45ff8fedcfe1a623193a18016c5ef09acb3f06280e0d1550fff6eefa06d9ba27382f3125e40f33fc2801c
7
+ data.tar.gz: fe3c0d01527cfd07b15ef4da21eae03902816cbd4728871d0b146a92247e622e2b2353c02ee44804f2b97449a24bb944fbdb3e16622f5db863ab1364d4641e5a
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Jason Stenhouse
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.
@@ -0,0 +1,40 @@
1
+ ## Sunwatch
2
+
3
+ Provides daily or hourly UV information for the US by zipcode or city/state. UV data is provided by the EPA.
4
+
5
+ ### Usage
6
+
7
+ Daily UV info:
8
+
9
+ require 'sunwatch'
10
+
11
+ Sunwatch.daily_uv_info_for(city: 'Seattle', state: 'WA')
12
+ # or
13
+ Sunwatch.daily_uv_info_for(zipcode: '98103')
14
+
15
+ # return type
16
+ uv_info = Sunwatch.daily_uv_info_for(zipcode: '98103')
17
+ uv_info.zipcode # => 98103
18
+ uv_info.uv_index # => 3
19
+ uv_info.uv_alert # => 1
20
+
21
+ Hourly UV info:
22
+
23
+ require 'sunwatch'
24
+
25
+ Sunwatch.hourly_uv_info_for(city: 'Seattle', state: 'WA')
26
+ Sunwatch.hourly_uv_info_for(zipcode: '98103')
27
+
28
+ # return type
29
+ uv_info = Sunwatch.hourly_uv_info_for(zipcode: '98103')
30
+ uv_info.zipcode # => 98103
31
+
32
+ uv_info.hours.each do |hour|
33
+
34
+ ## Contributing
35
+
36
+ 1. [Fork it](https://github/jstenhouse/sunwatch/fork)
37
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
38
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
39
+ 4. Push to the branch (`git push origin my-new-feature`)
40
+ 5. Create a new Pull Request
@@ -0,0 +1,5 @@
1
+ require 'sunwatch/version'
2
+ require 'sunwatch/errors'
3
+ require 'sunwatch/response'
4
+ require 'sunwatch/client'
5
+ require 'sunwatch/sunwatch'
@@ -0,0 +1,70 @@
1
+ require 'httparty'
2
+ require 'json'
3
+
4
+ module Sunwatch
5
+ class Client
6
+
7
+ EPA_UV_URI = 'http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUV'
8
+
9
+ def self.uv_info_for(opts)
10
+ url = build_url(opts)
11
+ response = HTTParty.get(url)
12
+ raise_unavailable_error if response.code != 200
13
+ build_response(JSON.parse(response.body))
14
+ rescue HTTParty::Error => e
15
+ raise_unavailable_error(e.message)
16
+ end
17
+
18
+ private
19
+
20
+ def self.build_response(response)
21
+ if response.size == 1
22
+ build_daily_response(response.first)
23
+ else
24
+ build_hourly_response(response)
25
+ end
26
+ end
27
+
28
+ def self.build_daily_response(response)
29
+ Sunwatch::Response.new(city: response['CITY'],
30
+ state: response['STATE'],
31
+ zipcode: response['ZIP_CODE'],
32
+ uv_index: response['UV_INDEX'],
33
+ uv_alert: response['UV_ALERT'])
34
+ end
35
+
36
+ def self.build_hourly_response(response)
37
+ hours = []
38
+ response.each do |hour|
39
+ hours << { datetime: hour['DATE_TIME'], uv_value: hour['UV_VALUE'] }
40
+ end
41
+ Sunwatch::Response.new(city: response.first['CITY'],
42
+ state: response.first['STATE'],
43
+ zipcode: response.first['ZIP'], # wat. API uses ZIP for hourly, and ZIP_CODE for daily
44
+ hours: hours)
45
+ end
46
+
47
+ def self.raise_unavailable_error(msg = '')
48
+ raise Sunwatch::UnavailableError.new("UV Index info is unavailable: #{msg}")
49
+ end
50
+
51
+ def self.build_url(opts)
52
+ uri_timewindow = build_url_timewindow(opts)
53
+ uri_location = build_url_location(opts)
54
+ "#{EPA_UV_URI}#{uri_timewindow}/#{uri_location}/json"
55
+ end
56
+
57
+ def self.build_url_timewindow(opts)
58
+ opts[:timewindow] == :daily ? 'DAILY' : 'HOURLY'
59
+ end
60
+
61
+ def self.build_url_location(opts)
62
+ if opts[:zipcode]
63
+ "ZIP/#{opts[:zipcode]}"
64
+ else
65
+ "CITY/#{opts[:city]}/STATE/#{opts[:state]}"
66
+ end
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,4 @@
1
+ module Sunwatch
2
+ class ConfigurationError < StandardError; end
3
+ class UnavailableError < StandardError; end
4
+ end
@@ -0,0 +1,46 @@
1
+ module Sunwatch
2
+ class Response
3
+ Hour = Struct.new(:datetime, :uv_value)
4
+
5
+ attr_accessor :city, :state, :zipcode, :uv_index, :uv_alert, :hours
6
+
7
+ def initialize(opts)
8
+ @city = opts[:city]
9
+ @state = opts[:state]
10
+ @zipcode = opts[:zipcode]
11
+ @uv_index = opts[:uv_index]
12
+ @uv_alert = opts[:uv_alert]
13
+ if opts[:hours]
14
+ @hours = []
15
+ opts[:hours].each do |hour|
16
+ @hours << Hour.new(to_datetime(hour[:datetime]), hour[:uv_value])
17
+ end
18
+ end
19
+ end
20
+
21
+ def hourly?
22
+ @hours != nil
23
+ end
24
+
25
+ def daily?
26
+ @hours == nil
27
+ end
28
+
29
+ def ==(other)
30
+ self.class == other.class &&
31
+ @city == other.city &&
32
+ @state == other.state &&
33
+ @zipcode == other.zipcode &&
34
+ @uv_index == other.uv_index &&
35
+ @uv_alert == other.uv_alert &&
36
+ @hours == other.hours
37
+ end
38
+
39
+ private
40
+
41
+ def to_datetime(str_datetime)
42
+ # OCT/19/2014 05 AM
43
+ DateTime.strptime(str_datetime, "%b/%d/%Y %I %p")
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,40 @@
1
+ module Sunwatch
2
+ def self.daily_uv_info_for(opts = {})
3
+ validate_opts!(opts)
4
+ opts[:zipcode] = opts[:zipcode].to_s if opts[:zipcode] # allow integers
5
+ opts[:timewindow] = :daily
6
+ Sunwatch::Client.uv_info_for(opts)
7
+ end
8
+
9
+ def self.hourly_uv_info_for(opts = {})
10
+ validate_opts!(opts)
11
+ opts[:zipcode] = opts[:zipcode].to_s if opts[:zipcode] # allow integers
12
+ opts[:timewindow] = :hourly
13
+ Sunwatch::Client.uv_info_for(opts)
14
+ end
15
+
16
+ private
17
+
18
+ def self.validate_opts!(opts)
19
+ if opts[:zipcode]
20
+ validate_string_or_number!(:zipcode, opts[:zipcode])
21
+ elsif opts[:city] && opts[:state]
22
+ validate_string!(:city, opts[:city])
23
+ validate_string!(:state, opts[:state])
24
+ else
25
+ raise ConfigurationError.new('city/state or zipcode must be provided')
26
+ end
27
+ end
28
+
29
+ def self.validate_string!(opt, value)
30
+ unless value.respond_to?(:to_str)
31
+ raise ConfigurationError.new("#{opt.to_s} must be a string")
32
+ end
33
+ end
34
+
35
+ def self.validate_string_or_number!(opt, value)
36
+ unless value.respond_to?(:to_str) || value.respond_to?(:to_int)
37
+ raise ConfigurationError.new("#{opt.to_s} must be a string or integer")
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,3 @@
1
+ module Sunwatch
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,2 @@
1
+ require 'webmock/rspec'
2
+ require 'sunwatch'
@@ -0,0 +1,106 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sunwatch::Client do
4
+
5
+ describe '.uv_info_for' do
6
+
7
+ let(:daily_zipcode_json_response) { '[{"ZIP_CODE":12345,"UV_INDEX":2,"UV_ALERT":0}]' }
8
+ let(:daily_zipcode_response) { Sunwatch::Response.new(zipcode: 12345, uv_index: 2, uv_alert: 0) }
9
+
10
+ let(:daily_citystate_json_response) { '[{"CITY":"WASHINGTON","STATE":"DC","UV_INDEX":3,"UV_ALERT":1}]' }
11
+ let(:daily_citystate_response) { Sunwatch::Response.new(city: 'WASHINGTON', state: 'DC', uv_index: 3, uv_alert: 1) }
12
+
13
+ let(:hourly_zipcode_json_response) { '[{"ORDER":1,"ZIP":12345,"DATE_TIME":"OCT/18/2014 04 AM","UV_VALUE":0},{"ORDER":2,"ZIP":12345,"DATE_TIME":"OCT/18/2014 05 AM","UV_VALUE":1}]' }
14
+ let(:hourly_zipcode_response) { Sunwatch::Response.new(zipcode: 12345, hours: [{datetime: 'OCT/18/2014 04 AM', uv_value: 0}, {datetime: 'OCT/18/2014 05 AM', uv_value: 1}]) }
15
+
16
+ let(:hourly_citystate_json_response) { '[{"SEQUENCE":1,"CITY":"SEATTLE","STATE":"WA","DATE_TIME":"OCT/19/2014 04 AM","UV_VALUE":0},{"SEQUENCE":2,"CITY":"SEATTLE","STATE":"WA","DATE_TIME":"OCT/19/2014 05 AM","UV_VALUE":1}]' }
17
+ let(:hourly_citystate_response) { Sunwatch::Response.new(city: 'SEATTLE', state: 'WA', hours: [{datetime: 'OCT/19/2014 04 AM', uv_value: 0}, {datetime: 'OCT/19/2014 05 AM', uv_value: 1}]) }
18
+
19
+ before do
20
+ stub_request(:get, 'http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUVDAILY/ZIP/12345/json').to_return(body: daily_zipcode_json_response)
21
+ stub_request(:get, 'http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUVDAILY/CITY/Seattle/STATE/WA/json').to_return(body: daily_citystate_json_response)
22
+ stub_request(:get, 'http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUVHOURLY/ZIP/12345/json').to_return(body: hourly_zipcode_json_response)
23
+ stub_request(:get, 'http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUVHOURLY/CITY/Seattle/STATE/WA/json').to_return(body: hourly_citystate_json_response)
24
+ end
25
+
26
+ context 'a daily timewindow' do
27
+ context 'with zipcode' do
28
+ it 'fetches uv index info' do
29
+ response = Sunwatch::Client.uv_info_for(timewindow: :daily, zipcode: '12345')
30
+ expect(response).to eq(daily_zipcode_response)
31
+ end
32
+ end
33
+
34
+ context 'with city/state' do
35
+ it 'fetches uv index info' do
36
+ response = Sunwatch::Client.uv_info_for(timewindow: :daily, city: 'Seattle', state: 'WA')
37
+ expect(response).to eq(daily_citystate_response)
38
+ end
39
+ end
40
+ end
41
+
42
+ context 'an hourly timewindow' do
43
+ context 'with zipcode' do
44
+ it 'fetches uv index info' do
45
+ response = Sunwatch::Client.uv_info_for(timewindow: :hourly, zipcode: '12345')
46
+ expect(response).to eq(hourly_zipcode_response)
47
+ end
48
+ end
49
+
50
+ context 'with city/state' do
51
+ it 'fetches uv index info' do
52
+ response = Sunwatch::Client.uv_info_for(timewindow: :hourly, city: 'Seattle', state: 'WA')
53
+ expect(response).to eq(hourly_citystate_response)
54
+ end
55
+ end
56
+ end
57
+
58
+ context 'service unavailable' do
59
+
60
+ before do
61
+ stub_request(:get, 'http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUVHOURLY/ZIP/12345/json').to_return(
62
+ :status => ["503", "Temporarily Unavailable"])
63
+ end
64
+
65
+ it 'raises a service unavailable error' do
66
+ expect { Sunwatch::Client.uv_info_for(timewindow: :hourly, zipcode: '12345') }.to raise_error Sunwatch::UnavailableError
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+ describe '.build_url' do
73
+ context 'a daily timewindow' do
74
+ context 'with zipcode' do
75
+ it 'builds a daily timewindow with zipcode url' do
76
+ url = Sunwatch::Client.build_url(timewindow: :daily, zipcode: '12345')
77
+ expect(url).to eq('http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUVDAILY/ZIP/12345/json')
78
+ end
79
+ end
80
+
81
+ context 'with city/state' do
82
+ it 'builds a daily timewindow with city/state url' do
83
+ url = Sunwatch::Client.build_url(timewindow: :daily, city: 'Seattle', state: 'WA')
84
+ expect(url).to eq('http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUVDAILY/CITY/Seattle/STATE/WA/json')
85
+ end
86
+ end
87
+ end
88
+
89
+ context 'an hourly timewindow' do
90
+ context 'with zipcode' do
91
+ it 'builds an hourly timewindow with zipcode url' do
92
+ url = Sunwatch::Client.build_url(timewindow: :hourly, zipcode: '12345')
93
+ expect(url).to eq('http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUVHOURLY/ZIP/12345/json')
94
+ end
95
+ end
96
+
97
+ context 'with city/state' do
98
+ it 'builds an hourly timewindow with city/state url' do
99
+ url = Sunwatch::Client.build_url(timewindow: :hourly, city: 'Seattle', state: 'WA')
100
+ expect(url).to eq('http://iaspub.epa.gov/enviro/efservice/getEnvirofactsUVHOURLY/CITY/Seattle/STATE/WA/json')
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+
3
+ describe Sunwatch do
4
+
5
+ describe '.daily_uv_info_for' do
6
+
7
+ context 'invalid options' do
8
+ context 'with only city' do
9
+ it 'raises a configuration error' do
10
+ expect { Sunwatch.daily_uv_info_for(city: 'Seattle') }.to raise_error Sunwatch::ConfigurationError
11
+ end
12
+ end
13
+
14
+ context 'with only state' do
15
+ it 'raises a configuration error' do
16
+ expect { Sunwatch.daily_uv_info_for(state: 'WA') }.to raise_error Sunwatch::ConfigurationError
17
+ end
18
+ end
19
+
20
+ context 'with non-string/non-number zipcode' do
21
+ it 'raises a configuration error' do
22
+ expect { Sunwatch.daily_uv_info_for(zipcode: Object.new) }.to raise_error Sunwatch::ConfigurationError
23
+ end
24
+ end
25
+
26
+ context 'with non-string city' do
27
+ it 'raises a configuration error' do
28
+ expect { Sunwatch.daily_uv_info_for(city: 1) }.to raise_error Sunwatch::ConfigurationError
29
+ end
30
+ end
31
+
32
+ context 'with non-string state' do
33
+ it 'raises a configuration error' do
34
+ expect { Sunwatch.daily_uv_info_for(state: 1) }.to raise_error Sunwatch::ConfigurationError
35
+ end
36
+ end
37
+ end
38
+
39
+ context 'valid options' do
40
+ context 'with city and state' do
41
+ let(:valid_options) { { city: 'Seattle', state: 'WA' } }
42
+
43
+ it 'will send appropriate options to client' do
44
+ expect(Sunwatch::Client).to receive(:uv_info_for) { valid_options.merge(timewindow: :daily) }
45
+ Sunwatch.daily_uv_info_for(valid_options)
46
+ end
47
+ end
48
+
49
+ context 'with zipcode' do
50
+ let(:valid_options) { { zipcode: '12345' } }
51
+
52
+ it 'will send appropriate options to client' do
53
+ expect(Sunwatch::Client).to receive(:uv_info_for) { valid_options.merge(timewindow: :daily) }
54
+ Sunwatch.daily_uv_info_for(valid_options)
55
+ end
56
+ end
57
+ end
58
+ end
59
+
60
+ describe '.hourly_uv_info_for' do
61
+
62
+ context 'invalid options' do
63
+ context 'with only city' do
64
+ it 'raises a configuration error' do
65
+ expect { Sunwatch.hourly_uv_info_for(city: 'Seattle') }.to raise_error Sunwatch::ConfigurationError
66
+ end
67
+ end
68
+
69
+ context 'with only state' do
70
+ it 'raises a configuration error' do
71
+ expect { Sunwatch.hourly_uv_info_for(state: 'WA') }.to raise_error Sunwatch::ConfigurationError
72
+ end
73
+ end
74
+
75
+ context 'with non-string/non-number zipcode' do
76
+ it 'raises a configuration error' do
77
+ expect { Sunwatch.hourly_uv_info_for(zipcode: Object.new) }.to raise_error Sunwatch::ConfigurationError
78
+ end
79
+ end
80
+
81
+ context 'with non-string city' do
82
+ it 'raises a configuration error' do
83
+ expect { Sunwatch.hourly_uv_info_for(city: 1) }.to raise_error Sunwatch::ConfigurationError
84
+ end
85
+ end
86
+
87
+ context 'with non-string state' do
88
+ it 'raises a configuration error' do
89
+ expect { Sunwatch.hourly_uv_info_for(state: 1) }.to raise_error Sunwatch::ConfigurationError
90
+ end
91
+ end
92
+ end
93
+
94
+ context 'valid options' do
95
+ context 'with city and state' do
96
+ let(:valid_options) { { city: 'Seattle', state: 'WA' } }
97
+
98
+ it 'will send appropriate options to client' do
99
+ expect(Sunwatch::Client).to receive(:uv_info_for) { valid_options.merge(timewindow: :hourly) }
100
+ Sunwatch.hourly_uv_info_for(valid_options)
101
+ end
102
+ end
103
+
104
+ context 'with zipcode' do
105
+ let(:valid_options) { { zipcode: '12345' } }
106
+
107
+ it 'will send appropriate options to client' do
108
+ expect(Sunwatch::Client).to receive(:uv_info_for) { valid_options.merge(timewindow: :hourly) }
109
+ Sunwatch.hourly_uv_info_for(valid_options)
110
+ end
111
+ end
112
+ end
113
+ end
114
+
115
+ end
@@ -0,0 +1,23 @@
1
+ $LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
2
+
3
+ require 'sunwatch/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'sunwatch'
7
+ spec.version = Sunwatch::VERSION
8
+ spec.summary = 'Provides EPA UV index information for the US'
9
+ spec.description = 'Provides EPA UV index information for the US'
10
+ spec.authors = ['jstenhouse']
11
+ spec.email = 'jason.stenhouse@gmail.com'
12
+ spec.homepage = 'https://github.com/jstenhouse/sunwatch'
13
+ spec.licenses = ['MIT']
14
+
15
+ spec.files = `git ls-files`.split("\n")
16
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ spec.require_paths = ['lib']
18
+
19
+ spec.add_dependency 'httparty'
20
+
21
+ spec.add_development_dependency 'rspec'
22
+ spec.add_development_dependency 'webmock'
23
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sunwatch
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - jstenhouse
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: httparty
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
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
+ - !ruby/object:Gem::Dependency
42
+ name: webmock
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Provides EPA UV index information for the US
56
+ email: jason.stenhouse@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".gitignore"
62
+ - Gemfile
63
+ - LICENSE
64
+ - README.md
65
+ - lib/sunwatch.rb
66
+ - lib/sunwatch/client.rb
67
+ - lib/sunwatch/errors.rb
68
+ - lib/sunwatch/response.rb
69
+ - lib/sunwatch/sunwatch.rb
70
+ - lib/sunwatch/version.rb
71
+ - spec/spec_helper.rb
72
+ - spec/sunwatch/client_spec.rb
73
+ - spec/sunwatch/sunwatch_spec.rb
74
+ - sunwatch.gemspec
75
+ homepage: https://github.com/jstenhouse/sunwatch
76
+ licenses:
77
+ - MIT
78
+ metadata: {}
79
+ post_install_message:
80
+ rdoc_options: []
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ required_rubygems_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ requirements: []
94
+ rubyforge_project:
95
+ rubygems_version: 2.2.2
96
+ signing_key:
97
+ specification_version: 4
98
+ summary: Provides EPA UV index information for the US
99
+ test_files:
100
+ - spec/spec_helper.rb
101
+ - spec/sunwatch/client_spec.rb
102
+ - spec/sunwatch/sunwatch_spec.rb