gull 0.4.0 → 1.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.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +23 -0
  3. data/.gitignore +5 -21
  4. data/.rubocop.yml +34 -1
  5. data/CHANGELOG.md +9 -1
  6. data/Gemfile +2 -0
  7. data/Guardfile +2 -0
  8. data/LICENSE.txt +1 -1
  9. data/README.md +41 -25
  10. data/Rakefile +2 -0
  11. data/gull.gemspec +19 -11
  12. data/lib/gull/alert.rb +79 -45
  13. data/lib/gull/client.rb +51 -36
  14. data/lib/gull/error.rb +5 -0
  15. data/lib/gull/geocode.rb +5 -0
  16. data/lib/gull/polygon.rb +11 -27
  17. data/lib/gull/version.rb +3 -1
  18. data/lib/gull.rb +10 -3
  19. data/spec/alert_spec.rb +130 -72
  20. data/spec/client_spec.rb +46 -63
  21. data/spec/error_spec.rb +4 -2
  22. data/spec/fixtures/alerts.json +4881 -0
  23. data/spec/fixtures/empty.json +4 -0
  24. data/spec/fixtures/features/blizzard_warning.json +93 -0
  25. data/spec/fixtures/features/empty_geocode.json +34 -0
  26. data/spec/fixtures/features/flood_advisory.json +156 -0
  27. data/spec/fixtures/features/flood_warning.json +108 -0
  28. data/spec/fixtures/features/missing_times.json +36 -0
  29. data/spec/fixtures/features/multipolygon.json +69 -0
  30. data/spec/fixtures/features/null_geometry.json +145 -0
  31. data/spec/fixtures/features/polygon_no_vtec.json +165 -0
  32. data/spec/fixtures/features/polygon_with_vtec.json +128 -0
  33. data/spec/fixtures/missing_event.json +21 -0
  34. data/spec/polygon_spec.rb +22 -34
  35. data/spec/spec_helper.rb +5 -88
  36. metadata +42 -42
  37. data/.hound.yml +0 -3
  38. data/.ruby-version +0 -1
  39. data/.travis.yml +0 -7
  40. data/spec/fixtures/alerts.xml +0 -118
  41. data/spec/fixtures/bad.xml +0 -1
  42. data/spec/fixtures/empty.xml +0 -30
  43. data/spec/fixtures/missing_cap.xml +0 -46
data/lib/gull/polygon.rb CHANGED
@@ -1,44 +1,28 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gull
4
+ # Represents the geographic boundary of an alert as a series of
5
+ # lat/lon coordinate pairs. Coordinates are stored in [lat, lon]
6
+ # order.
2
7
  class Polygon
3
8
  attr_accessor :coordinates
4
9
 
5
- def initialize(polygon)
6
- self.coordinates = polygon.split(' ')
7
- .map { |point| point.split(',').map(&:to_f) }
8
- end
9
-
10
- def image_url(api_key, options = {})
11
- options = {
12
- width: 640,
13
- height: 640,
14
- color: '0xff0000',
15
- weight: 3,
16
- fillcolor: '0xff000060',
17
- maptype: 'roadmap'
18
- }.merge(options)
19
-
20
- url_base = 'http://maps.googleapis.com/maps/api/staticmap'
21
- "#{url_base}?size=#{options[:width]}x#{options[:height]}" \
22
- "&maptype=#{options[:maptype]}&path=color:#{options[:color]}" \
23
- "|weight:#{options[:weight]}|fillcolor:#{options[:fillcolor]}" \
24
- "|#{coordinates_piped}&key=#{api_key}"
10
+ # Accepts GeoJSON coordinates ([lon, lat]) and stores them as
11
+ # [lat, lon].
12
+ def initialize(coords)
13
+ self.coordinates = coords.map { |point| [point[1], point[0]] }
25
14
  end
26
15
 
16
+ # Returns coordinates as "lat,lon lat,lon ..." string.
27
17
  def to_s
28
18
  coordinates.map { |pair| pair.join(',') }.join(' ')
29
19
  end
30
20
 
31
- # Returns well-known text (WKT) formatted polygon
21
+ # Returns coordinates in Well-Known Text format.
32
22
  def to_wkt
33
23
  pairs = coordinates.map { |pair| "#{pair.last} #{pair.first}" }
34
24
  .join(', ')
35
25
  "POLYGON((#{pairs}))"
36
26
  end
37
-
38
- private
39
-
40
- def coordinates_piped
41
- coordinates.map { |pair| pair.join ',' }.join '|'
42
- end
43
27
  end
44
28
  end
data/lib/gull/version.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Gull
2
- VERSION = '0.4.0'
4
+ VERSION = '1.0.1'
3
5
  end
data/lib/gull.rb CHANGED
@@ -1,9 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'time'
6
+ require 'uri'
7
+
1
8
  require 'gull/version'
2
9
  require 'gull/error'
3
- require 'gull/client'
4
- require 'gull/alert'
5
- require 'gull/polygon'
6
10
  require 'gull/geocode'
11
+ require 'gull/polygon'
12
+ require 'gull/alert'
13
+ require 'gull/client'
7
14
 
8
15
  module Gull
9
16
  end
data/spec/alert_spec.rb CHANGED
@@ -1,116 +1,174 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Gull::Alert do
6
+ def load_feature(name)
7
+ JSON.parse(File.read("spec/fixtures/features/#{name}"))
8
+ end
9
+
10
+ def wrap_features(*features)
11
+ { 'type' => 'FeatureCollection', 'features' => features }.to_json
12
+ end
13
+
14
+ def stub_alerts(json)
15
+ stub_request(:get, 'https://api.weather.gov/alerts/active')
16
+ .to_return(status: 200, body: json, headers: {})
17
+ end
18
+
4
19
  it 'should initialize with geocode' do
5
20
  alert = Gull::Alert.new
6
21
  expect(alert.geocode).not_to be_nil
7
22
  end
8
23
 
9
- it 'should fetch parsed alerts' do
10
- xml = File.read 'spec/fixtures/alerts.xml'
11
-
12
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
13
- .with(headers: { 'Accept' => '*/*' })
14
- .to_return(status: 200, body: xml, headers: {})
24
+ it 'should fetch and parse all alerts' do
25
+ json = File.read 'spec/fixtures/alerts.json'
26
+ stub_alerts(json)
15
27
 
16
28
  alerts = Gull::Alert.fetch
17
- expect(alerts.size).to eq(3)
29
+ expect(alerts.size).to eq(44)
30
+ end
31
+
32
+ it 'should parse alert with polygon and no VTEC' do
33
+ feature = load_feature('polygon_no_vtec.json')
34
+ stub_alerts(wrap_features(feature))
18
35
 
19
- first = alerts.first
20
- expect(first.id).to eq 'http://alerts.weather.gov/cap/wwacapget.php?x=CA125171381DD0.HeatAdvisory'
21
- expect(first.link).to eq 'http://alerts.weather.gov/cap/wwacapget.php?x=CA125171381DD0.HeatAdvisory'
22
- expect(first.alert_type).to eq 'Heat Advisory'
23
- expect(first.title).to eq 'Heat Advisory issued October 01 at 8:40AM PDT' \
24
- ' until October 03 at 9:00PM PDT by NWS'
25
- expect(first.summary).to eq 'SUMMARY TEXT'
36
+ alert = Gull::Alert.fetch.first
26
37
 
27
- coordinates = [[27.35, -81.79], [27.14, -81.89], [27.04, -81.97],
28
- [27.04, -82.02], [27.14, -81.97], [27.35, -81.86],
29
- [27.35, -81.79]]
30
- expect(first.polygon.coordinates).to eq coordinates
38
+ expect(alert.id).to eq feature['properties']['id']
39
+ expect(alert.link).to eq feature['properties']['@id']
40
+ expect(alert.alert_type).to eq 'Special Weather Statement'
41
+ expect(alert.title).to start_with 'Special Weather Statement'
42
+ expect(alert.summary).to start_with 'At 748 AM CST'
43
+ expect(alert.area).to eq 'Sevier; Howard; Hempstead'
31
44
 
32
- expect(first.effective_at).to eq Time.parse('2014-10-01T08:40:00-07:00')
33
- expect(first.expires_at).to eq Time.parse('2014-10-03T21:00:00-07:00')
34
- expect(first.updated_at).to eq Time.parse('2014-10-01T08:40:00-07:05')
35
- expect(first.published_at).to eq Time.parse('2014-10-01T08:40:00-07:06')
45
+ expect(alert.effective_at).to eq Time.parse('2026-03-07T07:48:00-06:00')
46
+ expect(alert.expires_at).to eq Time.parse('2026-03-07T08:15:00-06:00')
47
+ expect(alert.published_at).to eq Time.parse('2026-03-07T07:48:00-06:00')
48
+ expect(alert.updated_at).to eq Time.parse('2026-03-07T07:48:00-06:00')
36
49
 
37
- expect(first.area).to eq 'Southern Salinas Valley, Arroyo Seco and Lake ' \
38
- 'San Antonio'
39
- expect(first.urgency).to eq :expected
40
- expect(first.severity).to eq :minor
41
- expect(first.certainty).to eq :very_likely
50
+ expect(alert.urgency).to eq :expected
51
+ expect(alert.severity).to eq :moderate
52
+ expect(alert.certainty).to eq :observed
42
53
 
43
- expect(first.geocode.fips6).to be_nil
44
- expect(first.geocode.ugc).to be_nil
54
+ expect(alert.polygon).not_to be_nil
55
+ expect(alert.polygon.coordinates.first).to eq [34.21, -93.93]
56
+ expect(alert.polygon.coordinates.size).to eq 18
45
57
 
46
- expect(first.vtec).to eq '/O.NEW.KMTR.HT.Y.0002.141002T1900Z-141004T0400Z/'
58
+ expect(alert.geocode.fips6).to eq '005133 005061 005057'
59
+ expect(alert.geocode.ugc).to eq 'ARZ050 ARZ051 ARZ060'
47
60
 
48
- second = alerts[1]
49
- expect(second.polygon).to be_nil
61
+ expect(alert.vtec).to be_nil
62
+ end
50
63
 
51
- expect(second.geocode.fips6).to eq '006001 006013 006041 006053 006055 ' \
52
- '006069 006075 006081 006085 006087 006097'
53
- expect(second.geocode.ugc).to eq 'CAZ006 CAZ505 CAZ506 CAZ507 CAZ508 ' \
54
- 'CAZ509 CAZ510 CAZ511 CAZ512 CAZ513 CAZ516 CAZ517 CAZ518 CAZ528 ' \
55
- 'CAZ529 CAZ530'
64
+ it 'should parse alert with polygon and VTEC' do
65
+ feature = load_feature('polygon_with_vtec.json')
66
+ stub_alerts(wrap_features(feature))
56
67
 
57
- expect(second.vtec).to be_nil
68
+ alert = Gull::Alert.fetch.first
58
69
 
59
- third = alerts[2]
60
- expect(third.vtec).to be_nil
61
- expect(third.link).to be_nil
70
+ expect(alert.alert_type).to eq 'Severe Thunderstorm Warning'
71
+ expect(alert.urgency).to eq :immediate
72
+ expect(alert.severity).to eq :severe
73
+ expect(alert.certainty).to eq :observed
74
+ expect(alert.polygon).not_to be_nil
75
+ expect(alert.polygon.coordinates.size).to eq 5
76
+ expect(alert.vtec).to eq '/O.NEW.KLZK.SV.W.0013.260307T1328Z-260307T1415Z/'
62
77
  end
63
78
 
64
- it 'should fetch from url in options' do
65
- xml = File.read 'spec/fixtures/alerts.xml'
79
+ it 'should parse alert with null geometry' do
80
+ feature = load_feature('null_geometry.json')
81
+ stub_alerts(wrap_features(feature))
66
82
 
67
- stub_request(:get, 'http://test.url')
68
- .with(headers: { 'Accept' => '*/*' })
69
- .to_return(status: 200, body: xml, headers: {})
83
+ alert = Gull::Alert.fetch.first
70
84
 
71
- alerts = Gull::Alert.fetch(url: 'http://test.url')
72
- expect(alerts.size).to eq(3)
85
+ expect(alert.alert_type).to eq 'Tornado Watch'
86
+ expect(alert.urgency).to eq :future
87
+ expect(alert.severity).to eq :extreme
88
+ expect(alert.certainty).to eq :possible
89
+ expect(alert.polygon).to be_nil
90
+ expect(alert.geocode.ugc).not_to be_nil
91
+ expect(alert.geocode.fips6).not_to be_nil
92
+ expect(alert.vtec).to eq '/O.CON.KLZK.TO.A.0022.000000T0000Z-260307T1400Z/'
73
93
  end
74
94
 
75
- it 'should enable strict xml parsing via option' do
76
- xml = File.read 'spec/fixtures/bad.xml'
95
+ it 'should parse flood advisory with minor severity' do
96
+ feature = load_feature('flood_advisory.json')
97
+ stub_alerts(wrap_features(feature))
77
98
 
78
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
79
- .with(headers: { 'Accept' => '*/*' })
80
- .to_return(status: 200, body: xml, headers: {})
99
+ alert = Gull::Alert.fetch.first
81
100
 
82
- expect { Gull::Alert.fetch(strict: true) }
83
- .to raise_error(Nokogiri::XML::SyntaxError)
101
+ expect(alert.alert_type).to eq 'Flood Advisory'
102
+ expect(alert.severity).to eq :minor
103
+ expect(alert.polygon).not_to be_nil
104
+ expect(alert.vtec).not_to be_nil
84
105
  end
85
106
 
86
- it 'should handle empty alerts' do
87
- xml = File.read 'spec/fixtures/empty.xml'
107
+ it 'should parse blizzard warning with extreme severity' do
108
+ feature = load_feature('blizzard_warning.json')
109
+ stub_alerts(wrap_features(feature))
88
110
 
89
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
90
- .with(headers: { 'Accept' => '*/*' })
91
- .to_return(status: 200, body: xml, headers: {})
111
+ alert = Gull::Alert.fetch.first
92
112
 
93
- alerts = Gull::Alert.fetch
94
- expect(alerts.size).to eq(0)
113
+ expect(alert.alert_type).to eq 'Blizzard Warning'
114
+ expect(alert.severity).to eq :extreme
115
+ expect(alert.polygon).to be_nil
95
116
  end
96
117
 
97
- it 'should handle bad response' do
98
- xml = File.read 'spec/fixtures/bad.xml'
118
+ it 'should parse MultiPolygon geometry' do
119
+ feature = load_feature('multipolygon.json')
120
+ stub_alerts(wrap_features(feature))
99
121
 
100
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
101
- .with(headers: { 'Accept' => '*/*' })
102
- .to_return(status: 200, body: xml, headers: {})
122
+ alert = Gull::Alert.fetch.first
123
+
124
+ coordinates = [[34.57, -97.56], [34.77, -97.38],
125
+ [34.75, -97.17], [34.57, -97.56]]
126
+ expect(alert.polygon.coordinates).to eq coordinates
127
+ end
128
+
129
+ it 'should handle empty geocode' do
130
+ feature = load_feature('empty_geocode.json')
131
+ stub_alerts(wrap_features(feature))
132
+
133
+ alert = Gull::Alert.fetch.first
134
+
135
+ expect(alert.geocode.fips6).to be_nil
136
+ expect(alert.geocode.ugc).to be_nil
137
+ end
138
+
139
+ it 'should fetch with area option' do
140
+ json = File.read 'spec/fixtures/alerts.json'
141
+
142
+ stub_request(:get, 'https://api.weather.gov/alerts/active?area=OK')
143
+ .to_return(status: 200, body: json, headers: {})
144
+
145
+ alerts = Gull::Alert.fetch(area: 'OK')
146
+ expect(alerts.size).to eq(44)
147
+ end
148
+
149
+ it 'should handle empty alerts' do
150
+ json = File.read 'spec/fixtures/empty.json'
151
+ stub_alerts(json)
103
152
 
104
153
  alerts = Gull::Alert.fetch
105
154
  expect(alerts.size).to eq(0)
106
155
  end
107
156
 
108
- it 'should handle missing cap section' do
109
- xml = File.read 'spec/fixtures/missing_cap.xml'
157
+ it 'should handle missing onset time' do
158
+ feature = load_feature('missing_times.json')
159
+ stub_alerts(wrap_features(feature))
160
+
161
+ alert = Gull::Alert.fetch.first
162
+
163
+ expect(alert.effective_at).to be_nil
164
+ expect(alert.expires_at).to eq Time.parse('2026-03-07T08:15:00-06:00')
165
+ expect(alert.updated_at).to eq Time.parse('2026-03-07T07:48:00-06:00')
166
+ expect(alert.published_at).to eq Time.parse('2026-03-07T07:48:00-06:00')
167
+ end
110
168
 
111
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
112
- .with(headers: { 'Accept' => '*/*' })
113
- .to_return(status: 200, body: xml, headers: {})
169
+ it 'should handle missing event' do
170
+ json = File.read 'spec/fixtures/missing_event.json'
171
+ stub_alerts(json)
114
172
 
115
173
  alerts = Gull::Alert.fetch
116
174
  expect(alerts.size).to eq 0
data/spec/client_spec.rb CHANGED
@@ -1,45 +1,25 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Gull::Client do
4
- it 'should initialize with options' do
5
- xml = File.read 'spec/fixtures/alerts.xml'
6
- stub_request(:get, 'http://test.url')
7
- .with(headers: { 'Accept' => '*/*' })
8
- .to_return(status: 200, body: xml, headers: {})
9
-
10
- options = { url: 'http://test.url', strict: true }
11
- client = Gull::Client.new(options)
12
- alerts = client.fetch
13
- expect(alerts.size).to eq 3
14
-
15
- xml = File.read 'spec/fixtures/bad.xml'
16
- stub_request(:get, 'http://test.url')
17
- .with(headers: { 'Accept' => '*/*' })
18
- .to_return(status: 200, body: xml, headers: {})
6
+ it 'should fetch alerts' do
7
+ json = File.read 'spec/fixtures/alerts.json'
19
8
 
20
- expect { client.fetch }
21
- .to raise_error(Nokogiri::XML::SyntaxError)
22
- end
23
-
24
- it 'should fetch alerts without options' do
25
- xml = File.read 'spec/fixtures/alerts.xml'
26
-
27
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
28
- .with(headers: { 'Accept' => '*/*' })
29
- .to_return(status: 200, body: xml, headers: {})
9
+ stub_request(:get, 'https://api.weather.gov/alerts/active')
10
+ .to_return(status: 200, body: json, headers: {})
30
11
 
31
12
  client = Gull::Client.new
32
13
  alerts = client.fetch
33
- expect(alerts.size).to eq 3
14
+ expect(alerts.size).to eq 44
34
15
  expect(client.errors.size).to eq 0
35
16
  end
36
17
 
37
- it 'should handle incomplete entries in xml' do
38
- xml = File.read 'spec/fixtures/missing_cap.xml'
18
+ it 'should handle features with missing event' do
19
+ json = File.read 'spec/fixtures/missing_event.json'
39
20
 
40
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
41
- .with(headers: { 'Accept' => '*/*' })
42
- .to_return(status: 200, body: xml, headers: {})
21
+ stub_request(:get, 'https://api.weather.gov/alerts/active')
22
+ .to_return(status: 200, body: json, headers: {})
43
23
 
44
24
  client = Gull::Client.new
45
25
  alerts = client.fetch
@@ -47,41 +27,25 @@ describe Gull::Client do
47
27
  expect(client.errors.size).to eq 1
48
28
  end
49
29
 
50
- it 'should raise own error if timeout occurs' do
51
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
52
- .with(headers: { 'Accept' => '*/*' })
53
- .to_timeout
30
+ it 'should raise error on non-success response' do
31
+ stub_request(:get, 'https://api.weather.gov/alerts/active')
32
+ .to_return(status: 503, body: '{"title":"Service Unavailable"}', headers: {})
54
33
 
55
- message = 'Timeout while connecting to NWS web service'
56
34
  client = Gull::Client.new
57
- expect { client.fetch }.to raise_error(Gull::TimeoutError, message)
35
+ expect { client.fetch }.to raise_error(Gull::HttpError, 'NWS API returned 503')
58
36
  end
59
37
 
60
- it 'should raise own error if http errors occur' do
61
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
62
- .with(headers: { 'Accept' => '*/*' })
63
- .to_raise(HTTPClient::KeepAliveDisconnected)
64
-
65
- message = 'Could not connect to NWS web service'
66
- client = Gull::Client.new
67
- expect { client.fetch }.to raise_error(Gull::HttpError, message) do |error|
68
- expect(error.original).to be_a(HTTPClient::KeepAliveDisconnected)
69
- end
70
-
71
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
72
- .with(headers: { 'Accept' => '*/*' })
73
- .to_raise(HTTPClient::BadResponseError)
38
+ it 'should raise own error if timeout occurs' do
39
+ stub_request(:get, 'https://api.weather.gov/alerts/active')
40
+ .to_timeout
74
41
 
75
- message = 'Could not connect to NWS web service'
42
+ message = 'Timeout while connecting to NWS web service'
76
43
  client = Gull::Client.new
77
- expect { client.fetch }.to raise_error(Gull::HttpError, message) do |error|
78
- expect(error.original).to be_a(HTTPClient::BadResponseError)
79
- end
44
+ expect { client.fetch }.to raise_error(Gull::TimeoutError, message)
80
45
  end
81
46
 
82
47
  it 'should raise own error if connection errors occur' do
83
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
84
- .with(headers: { 'Accept' => '*/*' })
48
+ stub_request(:get, 'https://api.weather.gov/alerts/active')
85
49
  .to_raise(SocketError)
86
50
 
87
51
  message = 'Could not connect to NWS web service'
@@ -90,24 +54,43 @@ describe Gull::Client do
90
54
  expect(error.original).to be_a(SocketError)
91
55
  end
92
56
 
93
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
94
- .with(headers: { 'Accept' => '*/*' })
57
+ stub_request(:get, 'https://api.weather.gov/alerts/active')
95
58
  .to_raise(Errno::ECONNREFUSED)
96
59
 
97
- message = 'Could not connect to NWS web service'
98
60
  client = Gull::Client.new
99
61
  expect { client.fetch }.to raise_error(Gull::HttpError, message) do |error|
100
62
  expect(error.original).to be_a(Errno::ECONNREFUSED)
101
63
  end
102
64
 
103
- stub_request(:get, 'http://alerts.weather.gov/cap/us.php?x=1')
104
- .with(headers: { 'Accept' => '*/*' })
65
+ stub_request(:get, 'https://api.weather.gov/alerts/active')
105
66
  .to_raise(Errno::ECONNRESET)
106
67
 
107
- message = 'Could not connect to NWS web service'
108
68
  client = Gull::Client.new
109
69
  expect { client.fetch }.to raise_error(Gull::HttpError, message) do |error|
110
70
  expect(error.original).to be_a(Errno::ECONNRESET)
111
71
  end
112
72
  end
73
+
74
+ it 'should raise error on malformed JSON response' do
75
+ stub_request(:get, 'https://api.weather.gov/alerts/active')
76
+ .to_return(status: 200, body: '<html>Bad Gateway</html>',
77
+ headers: {})
78
+
79
+ client = Gull::Client.new
80
+ expect { client.fetch }
81
+ .to raise_error(Gull::HttpError, /Unexpected response/) do |e|
82
+ expect(e.original).to be_a(JSON::ParserError)
83
+ end
84
+ end
85
+
86
+ it 'should filter by area' do
87
+ json = File.read 'spec/fixtures/alerts.json'
88
+
89
+ stub_request(:get, 'https://api.weather.gov/alerts/active?area=OK')
90
+ .to_return(status: 200, body: json, headers: {})
91
+
92
+ client = Gull::Client.new(area: 'OK')
93
+ alerts = client.fetch
94
+ expect(alerts.size).to eq 44
95
+ end
113
96
  end
data/spec/error_spec.rb CHANGED
@@ -1,14 +1,16 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'spec_helper'
2
4
 
3
5
  describe Gull::HttpError do
4
6
  it 'should instantiate and set original with current exception' do
5
7
  error = StandardError.new 'inner'
6
8
  begin
7
- fail error
9
+ raise error
8
10
  rescue StandardError
9
11
  http_error = Gull::HttpError.new 'test'
10
12
  expect(http_error.original).to eq error
11
- expect(http_error.original.message). to eq 'inner'
13
+ expect(http_error.original.message).to eq 'inner'
12
14
  end
13
15
  end
14
16
  end