gull 0.3.4 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8e31bf5dcc237447beaebab3385d8d87b2615d88
4
- data.tar.gz: c123ff556c38b50041abd35bf2211406a4da70cc
2
+ SHA256:
3
+ metadata.gz: eb20ff9550e66bb6897227d930069551cc9882c1eef9f285d7a1ba74e0b2133e
4
+ data.tar.gz: b50b4e87e416dce952046c357e2c06d1d826b84e451141e237570418569d4b1d
5
5
  SHA512:
6
- metadata.gz: 014efe76f247bbdcb3a2159617ce700c5b291b141071f6cb74a546ee93a8126264128f0858ba15d882f2bbdd05a1a7ddb976d6a7a4131367aabdf9138006901b
7
- data.tar.gz: 21a3d3fe3471ff03773a6958ed6af9908f198d284259b809e77f89a6219f1d21c14216304eb36f3b96d96b182162acccd1a8ad208f1c58aab321b98068ce09e9
6
+ metadata.gz: b06376a56d00f2fa3ee684f4897b02439d24cd910722779a1f696e4d2a596550fa82cd7efb2e83c94934550fdaf406a266cddcab78a97b41d9fbdf6a13f65373
7
+ data.tar.gz: ca1f9f07f27e928571b1d0ed54bbe2275bccd8389995073f0892b4c5e469d176ea5084fa09bf0bdbca923b225105627da4f45e986fd5cd06e245a82a4515a577
@@ -0,0 +1,23 @@
1
+ name: CI
2
+ on:
3
+ push:
4
+ branches: [master]
5
+ pull_request:
6
+ branches: [master]
7
+ jobs:
8
+ test:
9
+ runs-on: ubuntu-latest
10
+ strategy:
11
+ matrix:
12
+ ruby-version: ['3.1', '3.2', '3.3', '3.4']
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - name: Set up Ruby ${{ matrix.ruby-version }}
16
+ uses: ruby/setup-ruby@v1
17
+ with:
18
+ ruby-version: ${{ matrix.ruby-version }}
19
+ bundler-cache: true
20
+ - name: Run tests
21
+ run: bundle exec rspec
22
+ - name: Run linter
23
+ run: bundle exec rubocop
data/.gitignore CHANGED
@@ -1,22 +1,6 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
1
+ /.bundle
2
+ /coverage
3
+ /pkg
4
+ /tmp
6
5
  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
18
- *.bundle
19
- *.so
20
- *.o
21
- *.a
22
- mkmf.log
6
+ .ruby-version
data/.rubocop.yml CHANGED
@@ -1,5 +1,38 @@
1
1
  AllCops:
2
+ TargetRubyVersion: 3.1
3
+ NewCops: enable
4
+ SuggestExtensions: false
2
5
  Exclude:
3
6
  - 'spec/spec_helper.rb'
7
+ - 'gull.gemspec'
8
+ - 'vendor/**/*'
9
+ Metrics/BlockLength:
10
+ Exclude:
11
+ - 'spec/**/*'
12
+ Metrics/MethodLength:
13
+ Max: 20
14
+ Exclude:
15
+ - 'spec/**/*'
16
+ Metrics/AbcSize:
17
+ Max: 35
18
+ Exclude:
19
+ - 'spec/**/*'
20
+ Metrics/ClassLength:
21
+ Enabled: false
22
+ Metrics/CyclomaticComplexity:
23
+ Enabled: false
24
+ Metrics/PerceivedComplexity:
25
+ Enabled: false
26
+ Layout/LineLength:
27
+ Max: 80
28
+ Exclude:
29
+ - 'spec/**/*'
4
30
  Style/StringLiterals:
5
- EnforcedStyle: single_quotes
31
+ EnforcedStyle: single_quotes
32
+ Style/StringConcatenation:
33
+ Exclude:
34
+ - 'spec/**/*'
35
+ Style/Documentation:
36
+ Enabled: false
37
+ Naming/PredicateMethod:
38
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,38 +1,57 @@
1
- #### 0.3.4 (12/16/2015)
2
- Fixed parser to handle empty geocode.
1
+ 1.0.0 (03/07/2026) - Major rewrite: migrate from defunct `alerts.weather.gov` XML feed to `api.weather.gov/alerts` JSON API. Drop all runtime dependencies (`httpclient`, `nokogiri`) in favor of Ruby stdlib (`net/http`, `json`). Require Ruby >= 3.1. Add `area` option for state-based filtering. Replace Travis CI with GitHub Actions. Add RuboCop. **Breaking:** remove `url` option (use `area` instead), remove `Polygon#image_url`, remove `strict` option.
3
2
 
4
- #### 0.3.3 (11/25/2015)
5
- Handle additional service failure scenarios.
6
3
  ***
7
- #### 0.3.2 (11/10/2015)
8
- Added BadResponseError to client error handling.
4
+
5
+ 0.4.0 (07/26/2016) - Merged pull request #2 from [schrockwell](https://github.com/schrockwell), which adds `to_wkt` to `Polygon` which formats the polygon points as Well-Known Text (WKT). Removed `centroid` method, use new `to_wkt` method with an external geospatial library instead.
6
+
7
+ ***
8
+
9
+ 0.3.4 (12/16/2015) - Fixed parser to handle empty geocode.
10
+
9
11
  ***
10
- #### 0.3.1 (6/25/2015)
11
- Added nested error handling for other HTTPClient errors. HttpError has original attribute exposing the root error.
12
+
13
+ 0.3.3 (11/25/2015) - Handle additional service failure scenarios.
14
+
12
15
  ***
13
- #### 0.3.0 (6/23/2015)
14
- Added Client class for error handling (bad entries accessed via errors array). Exposed option to turn on strict XML parsing for debugging. Alert.fetch uses new Client but is backwards compatible, however it doesn't give you access to errors array.
16
+
17
+ 0.3.2 (11/10/2015) - Added BadResponseError to client error handling.
18
+
19
+ ***
20
+
21
+ 0.3.1 (6/25/2015) - Added nested error handling for other HTTPClient errors. HttpError has original attribute exposing the root error.
22
+
23
+ ***
24
+
25
+ 0.3.0 (6/23/2015) - Added Client class for error handling (bad entries accessed via errors array). Exposed option to turn on strict XML parsing for debugging. Alert.fetch uses new Client but is backwards compatible, however it doesn't give you access to errors array.
26
+
15
27
  ***
16
- #### 0.2.13 (6/20/2015)
17
- Handle missing cap section
28
+
29
+ 0.2.13 (6/20/2015) - Handle missing cap section
30
+
18
31
  ***
19
- #### 0.2.12 (6/12/2015)
20
- Fix issue with missing link elements
32
+
33
+ 0.2.12 (6/12/2015) - Fix issue with missing link elements
34
+
21
35
  ***
22
- #### 0.2.11 (5/29/2015)
23
- Added method to get original polygon string
36
+
37
+ 0.2.11 (5/29/2015) -Added method to get original polygon string
38
+
24
39
  ***
25
- #### 0.2.10 (3/23/2015)
26
- Added option to override default alert service URI.
40
+
41
+ 0.2.10 (3/23/2015) - Added option to override default alert service URI.
42
+
27
43
  ***
28
- #### 0.2.1 (10/02/2014)
29
- Added static map image to polygons.
44
+
45
+ 0.2.1 (10/02/2014) - Added static map image to polygons.
46
+
30
47
  ***
31
- #### 0.2.0 (10/02/2014)
32
- Introduced Polygon type.
48
+
49
+ 0.2.0 (10/02/2014) - Introduced Polygon type.
50
+
33
51
  ***
34
- #### 0.1.1 (10/01/2014)
35
- Refactored and simplified alert processing.
52
+
53
+ 0.1.1 (10/01/2014) - Refactored and simplified alert processing.
54
+
36
55
  ***
37
- #### 0.1.0 (10/01/2014)
38
- Initial release, basic functionality of fetching and parsing alerts.
56
+
57
+ 0.1.0 (10/01/2014) - Initial release, basic functionality of fetching and parsing alerts.
data/Gemfile CHANGED
@@ -1,9 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source 'https://rubygems.org'
2
4
 
3
5
  # Specify your gem's dependencies in gull.gemspec
4
6
  gemspec
5
-
6
- gem 'coveralls', require: false
7
- gem 'guard'
8
- gem 'guard-rspec', require: false
9
- gem 'simplecov', require: false
data/Guardfile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  guard :rspec, cmd: 'bundle exec rspec' do
2
4
  watch(%r{^spec/.+_spec\.rb$})
3
5
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Seth Deckard
1
+ Copyright (c) 2014-2026 Seth Deckard
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,12 +1,8 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/gull.svg)](http://badge.fury.io/rb/gull)
2
- [![Build Status](https://travis-ci.org/sethdeckard/gull.svg?branch=master)](https://travis-ci.org/sethdeckard/gull)
3
- [![Coverage Status](https://coveralls.io/repos/sethdeckard/gull/badge.png)](https://coveralls.io/r/sethdeckard/gull)
4
- [![Code Climate](https://codeclimate.com/github/sethdeckard/gull/badges/gpa.svg)](https://codeclimate.com/github/sethdeckard/gull)
5
- [![Dependency Status](https://gemnasium.com/sethdeckard/gull.svg)](https://gemnasium.com/sethdeckard/gull)
6
- [![security](https://hakiri.io/github/sethdeckard/gull/master.svg)](https://hakiri.io/github/sethdeckard/gull/master)
2
+ [![CI](https://github.com/sethdeckard/gull/actions/workflows/ci.yml/badge.svg)](https://github.com/sethdeckard/gull/actions/workflows/ci.yml)
7
3
  # Gull
8
4
 
9
- Ruby client for parsing NOAA/NWS alerts, warnings, and watches. The name comes from the type of bird featured on the NOAA logo.
5
+ Ruby client for parsing NOAA/NWS alerts, warnings, and watches. The name comes from the type of bird featured on the NOAA logo. Zero runtime dependencies -- uses only Ruby stdlib (`net/http`, `json`).
10
6
 
11
7
  ## Installation
12
8
 
@@ -49,49 +45,22 @@ alert.certainty
49
45
  alert.vtec
50
46
  ```
51
47
 
52
- To get alerts for a single state, territory, or marine zone just pass an optional URL
48
+ To get alerts for a single state or territory, pass the area option:
53
49
 
54
50
  ```ruby
55
- oklahoma_url = 'http://alerts.weather.gov/cap/ok.php?x=1'
56
- alerts = Gull::Alert.fetch(url: oklahoma_url)
51
+ alerts = Gull::Alert.fetch(area: 'OK')
57
52
  ```
58
53
 
59
- You can also generate a map (a really long URL pointing to a map) of the polygon if alert has one (requires Google Static Maps API Key)
60
-
61
- ```ruby
62
- alert.polygon.image_url 'YOUR_GOOGLE_API_KEY'
63
-
64
- => "http://maps.googleapis.com/maps/api/staticmap?size=640x640&maptype=roadmap&path=color:0xff0000|weight:3|fillcolor:0xff000060|38.73,-94.22|38.75,-94.16|38.57,-93.94|38.4,-93.84|38.4,-93.91|38.73,-94.22&key=YOUR_GOOGLE_API_KEY"
65
- ```
66
-
67
- Options can be passed for map to override defaults
68
-
69
- ```ruby
70
- options = { width: 600, height: 300, color: '0xfbf000', weight: 4,
71
- fillcolor: '0xfbf00070', maptype: 'hybrid' }
72
- alert.polygon.image_url 'YOUR_GOOGLE_API_KEY', options
73
- ```
74
-
75
- Get the centroid of the polygon (to display a map pin, etc.)
76
-
77
- ```ruby
78
- alert.polygon.centroid
79
-
80
- => [34.835, -91.205]
81
- ```
82
-
83
54
  ##Notes, Caveats
84
- This library provides a simplified/flattened model of the [Common Alerting Protocol](http://docs.oasis-open.org/emergency/cap/v1.2/CAP-v1.2-os.html) based only on the elements NWS utilizes in their public RSS feeds. If you need a complete CAP parser I suggest looking at [RCAP](https://github.com/farrel/RCAP).
85
-
86
- The NWS will often cancel or update alerts before their expiration time. The public alert feed only provides current active alerts and does not include these separate update and cancellation CAP messages. If you're persisting these alerts you need to design for this scenario.
55
+ This library fetches active alerts from the [NWS API](https://api.weather.gov) (`api.weather.gov/alerts/active`), which returns GeoJSON. No authentication is required but the API does require a `User-Agent` header (set automatically by the gem).
87
56
 
88
- The public RSS feeds are not always reliable, if you are using this for critical purposes then you should explore other options.
57
+ The NWS will often cancel or update alerts before their expiration time. The API only returns currently active alerts.
89
58
 
90
59
  ### Urgency
91
60
 
92
- | Symbol | Definition
61
+ | Symbol | Definition
93
62
  | :------------- |:-------------
94
- | :immediate | Responsive action should betaken immediately
63
+ | :immediate | Responsive action should be taken immediately
95
64
  | :expected | Responsive action should be taken soon (within next hour)
96
65
  | :future | Responsive action should be taken in the near future
97
66
  | :past | Responsive action is no longer required
@@ -99,7 +68,7 @@ The public RSS feeds are not always reliable, if you are using this for critical
99
68
 
100
69
  ### Severity
101
70
 
102
- | Symbol | Definition
71
+ | Symbol | Definition
103
72
  | :------------- |:-------------
104
73
  | :extreme | Extraordinary threat to life or property
105
74
  | :severe | Significant threat to life or property
@@ -109,7 +78,7 @@ The public RSS feeds are not always reliable, if you are using this for critical
109
78
 
110
79
  ### Certainty
111
80
 
112
- | Symbol | Definition
81
+ | Symbol | Definition
113
82
  | :------------- |:-------------
114
83
  | :very_likely | Highly likely (p > ~ 85%) or certain
115
84
  | :likely | Likely (p > ~50%)
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rspec/core/rake_task'
3
5
 
data/gull.gemspec CHANGED
@@ -1,5 +1,6 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
3
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
5
  require 'gull/version'
5
6
 
@@ -9,20 +10,29 @@ Gem::Specification.new do |spec|
9
10
  spec.authors = ['Seth Deckard']
10
11
  spec.email = ['seth@deckard.me']
11
12
  spec.summary = 'Client for parsing NOAA/NWS alerts, warnings, and watches.'
12
- spec.description = 'Client for parsing NOAA/NWS alerts, warnings, and watches.'
13
+ spec.description = 'Fetches and parses NOAA/NWS alerts, warnings, and watches from api.weather.gov. Zero runtime dependencies.'
13
14
  spec.homepage = 'https://github.com/sethdeckard/gull'
14
15
  spec.license = 'MIT'
16
+ spec.required_ruby_version = '>= 3.1'
17
+
18
+ spec.metadata = {
19
+ 'source_code_uri' => 'https://github.com/sethdeckard/gull',
20
+ 'changelog_uri' => 'https://github.com/sethdeckard/gull/blob/master/CHANGELOG.md',
21
+ 'bug_tracker_uri' => 'https://github.com/sethdeckard/gull/issues'
22
+ }
15
23
 
16
- spec.files = `git ls-files -z`.split("\x0")
24
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
25
+ f.match(%r{^(AGENTS|CLAUDE)\.md$})
26
+ end
17
27
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
28
  spec.require_paths = ['lib']
20
29
 
21
- spec.add_runtime_dependency 'httpclient'
22
- spec.add_runtime_dependency 'nokogiri', '>= 1.6.2'
23
-
24
- spec.add_development_dependency 'bundler', '>= 1.6'
30
+ spec.add_development_dependency 'bundler'
31
+ spec.add_development_dependency 'guard-rspec'
25
32
  spec.add_development_dependency 'rake'
26
33
  spec.add_development_dependency 'rspec', '>= 3.0'
34
+ spec.add_development_dependency 'rubocop'
35
+ spec.add_development_dependency 'rubocop-rake'
36
+ spec.add_development_dependency 'simplecov'
27
37
  spec.add_development_dependency 'webmock'
28
38
  end
data/lib/gull/alert.rb CHANGED
@@ -1,80 +1,89 @@
1
- require 'httpclient'
2
- require 'nokogiri'
1
+ # frozen_string_literal: true
3
2
 
4
3
  module Gull
5
- # Gull represents an NWS/NOAA alert and provides the ability to fetch
6
- # them from the public web service
7
4
  class Alert
8
- attr_accessor :id, :title, :summary, :link, :alert_type, :polygon, :area,
9
- :effective_at, :expires_at, :updated_at, :published_at,
10
- :urgency, :severity, :certainty, :geocode, :vtec
5
+ attr_accessor :id, :title, :summary, :link, :alert_type, :polygon,
6
+ :area, :effective_at, :expires_at, :updated_at,
7
+ :published_at, :urgency, :severity, :certainty,
8
+ :geocode, :vtec
11
9
 
12
10
  def initialize
13
11
  self.geocode = Geocode.new
14
12
  end
15
13
 
16
14
  def self.fetch(options = {})
17
- client = Client.new options
15
+ client = Client.new(options)
18
16
  client.fetch
19
17
  end
20
18
 
21
- def parse(element)
22
- parse_core_attributes element
23
- parse_times element
24
- parse_categories element
25
-
26
- parse_polygon element.xpath('cap:polygon').inner_text
27
- parse_geocode element.xpath('cap:geocode')
28
- parse_vtec element.xpath('cap:parameter')
19
+ def parse(feature)
20
+ props = feature['properties']
21
+ parse_core_attributes(feature, props)
22
+ parse_times(props)
23
+ parse_categories(props)
24
+ parse_polygon(feature)
25
+ parse_geocode(props)
26
+ parse_vtec(props)
29
27
  end
30
28
 
31
29
  private
32
30
 
33
- def parse_core_attributes(element)
34
- self.id = element.css('id').inner_text
35
- self.title = element.css('title').inner_text
36
- self.summary = element.css('summary').inner_text
37
- self.link = parse_link element
38
- self.alert_type = element.xpath('cap:event').inner_text
39
- self.area = element.xpath('cap:areaDesc').inner_text
31
+ def parse_core_attributes(feature, props)
32
+ self.id = props['id']
33
+ self.title = props['headline']
34
+ self.summary = props['description']
35
+ self.link = props['@id'] || feature['id']
36
+ self.alert_type = props['event']
37
+ self.area = props['areaDesc']
40
38
  end
41
39
 
42
- def parse_link(element)
43
- link = element.css('link').first
44
- link.attributes['href'].value unless link.nil?
40
+ def parse_times(props)
41
+ self.effective_at = Time.parse(props['effective'])
42
+ self.expires_at = Time.parse(props['expires'])
43
+ self.published_at = Time.parse(props['sent'])
44
+ self.updated_at = Time.parse(props['onset'] || props['sent'])
45
45
  end
46
46
 
47
- def parse_times(element)
48
- self.updated_at = Time.parse(element.css('updated').inner_text)
49
- self.published_at = Time.parse(element.css('published').inner_text)
50
- self.effective_at = Time.parse(element.xpath('cap:effective').inner_text)
51
- self.expires_at = Time.parse(element.xpath('cap:expires').inner_text)
47
+ def parse_categories(props)
48
+ self.urgency = code_to_symbol(props['urgency'])
49
+ self.severity = code_to_symbol(props['severity'])
50
+ self.certainty = code_to_symbol(props['certainty'])
52
51
  end
53
52
 
54
- def parse_categories(element)
55
- self.urgency = code_to_symbol element.xpath('cap:urgency').inner_text
56
- self.severity = code_to_symbol element.xpath('cap:severity').inner_text
57
- self.certainty = code_to_symbol element.xpath('cap:certainty').inner_text
58
- end
53
+ def parse_polygon(feature)
54
+ geometry = feature['geometry']
55
+ return if geometry.nil?
56
+
57
+ coords = geometry['coordinates']
58
+ return if coords.nil? || coords.empty?
59
59
 
60
- def parse_polygon(text)
61
- return if text.empty?
62
- self.polygon = Polygon.new text
60
+ ring = coords.first
61
+ ring = ring.first if geometry['type'] == 'MultiPolygon'
62
+ self.polygon = Polygon.new(ring)
63
63
  end
64
64
 
65
- def parse_geocode(element)
66
- return if element.children.css('value').first.nil?
65
+ def parse_geocode(props)
66
+ geocode_data = props['geocode']
67
+ return if geocode_data.nil?
67
68
 
68
- geocode.fips6 = element.children.css('value').first.inner_text
69
- geocode.ugc = element.children.css('value').last.inner_text
69
+ ugc = geocode_data['UGC']
70
+ geocode.ugc = ugc&.join(' ')
71
+
72
+ fips = geocode_data['SAME']
73
+ geocode.fips6 = fips&.join(' ')
70
74
  end
71
75
 
72
- def parse_vtec(element)
73
- value = element.children.css('value').inner_text
74
- self.vtec = value.empty? ? nil : value
76
+ def parse_vtec(props)
77
+ params = props['parameters']
78
+ return if params.nil?
79
+
80
+ vtec_values = params['VTEC']
81
+ self.vtec = vtec_values&.first
75
82
  end
76
83
 
77
84
  def code_to_symbol(code)
85
+ return :unknown if code.nil?
86
+
78
87
  code.tr(' ', '_').downcase.to_sym
79
88
  end
80
89
  end
data/lib/gull/client.rb CHANGED
@@ -1,65 +1,73 @@
1
- require 'httpclient'
2
- require 'nokogiri'
1
+ # frozen_string_literal: true
3
2
 
4
3
  module Gull
5
- # Client exposes methods and options for fetching alerts from the NWS/NOAA
6
- # web service
7
4
  class Client
5
+ URL = 'https://api.weather.gov/alerts/active'
6
+ USER_AGENT = "gull/#{VERSION} (Ruby #{RUBY_VERSION})".freeze
7
+
8
8
  attr_accessor :errors
9
9
 
10
10
  def initialize(options = {})
11
- @options = {
12
- url: 'http://alerts.weather.gov/cap/us.php?x=1',
13
- strict: false
14
- }.merge options
11
+ @options = options
15
12
  end
16
13
 
17
14
  def fetch
18
15
  self.errors = []
19
- content = response
20
- document = Nokogiri::XML content do |config|
21
- config.strict if @options[:strict]
22
- end
23
- process document.xpath('//xmlns:feed/xmlns:entry', namespaces)
16
+ json = response
17
+ data = JSON.parse(json)
18
+ process(data['features'] || [])
24
19
  end
25
20
 
26
21
  private
27
22
 
28
23
  def response
29
- client = HTTPClient.new
30
- begin
31
- return client.get_content @options[:url]
32
- rescue HTTPClient::TimeoutError
33
- raise TimeoutError, 'Timeout while connecting to NWS web service'
34
- rescue HTTPClient::KeepAliveDisconnected, HTTPClient::BadResponseError,
35
- SocketError, Errno::ECONNREFUSED, Errno::ECONNRESET
36
- raise HttpError, 'Could not connect to NWS web service'
24
+ uri = build_uri
25
+ http = Net::HTTP.new(uri.host, uri.port)
26
+ http.use_ssl = uri.scheme == 'https'
27
+ request = Net::HTTP::Get.new(uri)
28
+ request['User-Agent'] = USER_AGENT
29
+ request['Accept'] = 'application/geo+json'
30
+ result = http.request(request)
31
+ unless result.is_a?(Net::HTTPSuccess)
32
+ raise HttpError, "NWS API returned #{result.code}"
37
33
  end
34
+
35
+ result.body
36
+ rescue Net::OpenTimeout, Net::ReadTimeout
37
+ raise TimeoutError,
38
+ 'Timeout while connecting to NWS web service'
39
+ rescue SocketError, Errno::ECONNREFUSED, Errno::ECONNRESET
40
+ raise HttpError,
41
+ 'Could not connect to NWS web service'
38
42
  end
39
43
 
40
- def process(entries)
41
- alerts = []
42
- entries.each do |entry|
43
- alert = create_instance entry
44
- alerts.push alert unless alert.nil?
45
- errors.push entry if alert.nil?
44
+ def build_uri
45
+ uri = URI(URL)
46
+ if @options[:area]
47
+ params = URI.decode_www_form(uri.query || '')
48
+ params << ['area', @options[:area]]
49
+ uri.query = URI.encode_www_form(params)
46
50
  end
51
+ uri
52
+ end
47
53
 
54
+ def process(features)
55
+ alerts = []
56
+ features.each do |feature|
57
+ alert = create_instance(feature)
58
+ alerts.push(alert) unless alert.nil?
59
+ errors.push(feature) if alert.nil?
60
+ end
48
61
  alerts
49
62
  end
50
63
 
51
- def create_instance(entry)
52
- return if entry.xpath('cap:event').empty?
64
+ def create_instance(feature)
65
+ properties = feature['properties']
66
+ return if properties.nil? || properties['event'].nil?
53
67
 
54
68
  alert = Alert.new
55
- alert.parse entry
69
+ alert.parse(feature)
56
70
  alert
57
71
  end
58
-
59
- def namespaces
60
- { 'xmlns' => 'http://www.w3.org/2005/Atom',
61
- 'cap' => 'urn:oasis:names:tc:emergency:cap:1.1',
62
- 'ha' => 'http://www.alerting.net/namespace/index_1.0' }
63
- end
64
72
  end
65
73
  end
data/lib/gull/error.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'English'
2
4
 
3
5
  module Gull
data/lib/gull/geocode.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gull
2
4
  class Geocode
3
5
  attr_accessor :fips6, :ugc