accept_headers 0.1.0 → 0.3.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.
@@ -25,8 +25,8 @@ describe AcceptHeaders::MediaType do
25
25
  subject.new('*', nil).subtype.must_equal '*'
26
26
  end
27
27
 
28
- it "strips only the keys in the extensions hash" do
29
- subject.new('*', '*', extensions: { "\s\nLEVEL\r\t" => "\t\nX\s\n"}).extensions['LEVEL'].must_equal "\t\nX\s\n"
28
+ it "strips and downcases parameter names while preserving values" do
29
+ subject.new('*', '*', extensions: { "\s\nLEVEL\r\t" => "\t\nX\s\n"}).extensions['level'].must_equal "\t\nX\s\n"
30
30
  end
31
31
 
32
32
  it "optionally supports a q argument" do
@@ -92,14 +92,128 @@ describe AcceptHeaders::MediaType do
92
92
 
93
93
  it "converts to string" do
94
94
  s = subject.new('text', 'html', q: 0.9, extensions: { 'level' => '1' }).to_s
95
- s.must_equal "text/html;q=0.9;level=1"
95
+ s.must_equal "text/html;level=1;q=0.9"
96
+ end
97
+
98
+ it "quotes parameter delimiters and escapes quotes and backslashes" do
99
+ value = subject.new('text', 'html', extensions: { 'note' => 'a,b;c"d\\e', 'empty' => '' })
100
+ value.to_s.must_equal 'text/html;note="a,b;c\\"d\\\\e";empty="";q=1'
96
101
  end
97
102
 
98
103
  it "outputs the media range" do
99
104
  subject.new('text', 'html', extensions: { 'level' => '1' }).media_range.must_equal "text/html"
100
105
  end
101
106
 
107
+ describe "#content_type" do
108
+ it "outputs type, subtype, and parameters without the quality weight" do
109
+ media_type = subject.new('text', 'html', q: 0.9, extensions: { 'level' => '1' })
110
+
111
+ media_type.content_type.must_equal 'text/html;level=1'
112
+ media_type.to_s.must_equal 'text/html;level=1;q=0.9'
113
+ media_type.media_range.must_equal 'text/html'
114
+ end
115
+
116
+ it "does not add a quality parameter when there are no media parameters" do
117
+ subject.new('application', 'json').content_type.must_equal 'application/json'
118
+ end
119
+
120
+ it "uses the same parameter quoting as the Accept representation" do
121
+ {
122
+ 'a,b' => '"a,b"',
123
+ 'a;b' => '"a;b"',
124
+ 'a"b' => '"a\\"b"',
125
+ 'a\\b' => '"a\\\\b"',
126
+ '' => '""',
127
+ "caf\u00e9" => "\"caf\u00e9\"",
128
+ "\x80\xFF".b => "\"\x80\xFF\"".b
129
+ }.each do |parameter, encoded|
130
+ media_type = subject.new('text', 'plain', extensions: { 'note' => parameter })
131
+
132
+ media_type.content_type.must_equal "text/plain;note=#{encoded}"
133
+ media_type.to_s.must_equal "text/plain;note=#{encoded};q=1"
134
+ end
135
+ end
136
+
137
+ it "does not mutate the media type or parameter values" do
138
+ parameter = 'a,b;c"d\\e'.freeze
139
+ extensions = { 'note' => parameter }.freeze
140
+ media_type = subject.new('text', 'plain', q: 0.8, extensions: extensions)
141
+ original = media_type.to_h
142
+ result = media_type.content_type
143
+ result.replace('application/json')
144
+
145
+ media_type.to_h.must_equal original
146
+ media_type.extensions.must_equal extensions
147
+ media_type.content_type.must_equal 'text/plain;note="a,b;c\\"d\\\\e"'
148
+ media_type.to_s.must_equal 'text/plain;note="a,b;c\\"d\\\\e";q=0.8'
149
+ end
150
+ end
151
+
152
+ describe "#match" do
153
+ it "preserves raw comparison for hand-built non-String parameter values" do
154
+ [2, :public, nil].each do |value|
155
+ range = subject.new('application', 'json', extensions: { 'version' => value })
156
+ excluded = subject.new('application', 'json', q: 0, extensions: { 'version' => value })
157
+
158
+ ['application/json;version=2', 'application/json;version=public'].each do |candidate|
159
+ range.match(candidate).must_equal false
160
+ range.accept?(candidate).must_equal false
161
+ excluded.reject?(candidate).must_equal false
162
+ end
163
+
164
+ expected = value.nil?
165
+ range.match('application/json').must_equal expected
166
+ range.accept?('application/json').must_equal expected
167
+ excluded.reject?('application/json').must_equal expected
168
+ end
169
+ end
170
+
171
+ it "folds only ASCII case in charset values" do
172
+ { 'UTF-8' => 'utf-8', 'É' => 'é', 'K' => 'k' }.each do |value, candidate|
173
+ range = subject.new('text', 'plain', extensions: { 'charset' => value })
174
+ excluded = subject.new('text', 'plain', q: 0, extensions: { 'charset' => value })
175
+ header = "text/plain;charset=\"#{candidate}\""
176
+ expected = value == 'UTF-8'
177
+
178
+ range.match(header).must_equal expected
179
+ range.accept?(header).must_equal expected
180
+ excluded.reject?(header).must_equal expected
181
+ end
182
+ end
183
+ end
184
+
102
185
  describe "#accept?" do
186
+ it "matches type and subtype without case sensitivity" do
187
+ subject.new('text', 'html').accept?('TEXT/HTML').must_equal true
188
+ end
189
+
190
+ it "requires every media range parameter to match the supported representation" do
191
+ range = subject.new('application', 'json', extensions: { 'version' => '2' })
192
+ range.accept?('application/json').must_equal false
193
+ range.accept?('application/json;version=1').must_equal false
194
+ range.accept?('application/json;VERSION=2').must_equal true
195
+ range.accept?('application/json;version=2;profile=public').must_equal true
196
+ end
197
+
198
+ it "matches charset values without case sensitivity" do
199
+ range = subject.new('text', 'plain', extensions: { 'charset' => 'UTF-8' })
200
+ range.accept?('text/plain;charset=utf-8').must_equal true
201
+ range.accept?('text/plain;charset=iso-8859-1').must_equal false
202
+ range.accept?('text/plain').must_equal false
203
+ end
204
+
205
+ it "preserves case sensitivity for other parameter values" do
206
+ range = subject.new('application', 'json', extensions: { 'profile' => 'Public' })
207
+ range.accept?('application/json;profile=Public').must_equal true
208
+ range.accept?('application/json;profile=public').must_equal false
209
+ end
210
+
211
+ it "does not match an empty candidate or a list of candidates" do
212
+ range = subject.new('*')
213
+ range.accept?('').must_equal false
214
+ range.accept?('text/html,application/json').must_equal false
215
+ end
216
+
103
217
  it "accepted if the type and subtype are the same" do
104
218
  a = subject.new('text', 'html')
105
219
  a.accept?('text/html').must_equal true
@@ -1,6 +1,7 @@
1
1
  require_relative "spec_helper"
2
2
  require "accept_headers/middleware"
3
- require "rack/test"
3
+ require "rack/builder"
4
+ require "rack/mock"
4
5
 
5
6
  describe AcceptHeaders::Middleware do
6
7
  subject do
@@ -19,9 +20,9 @@ describe AcceptHeaders::Middleware do
19
20
  matched_encoding = env["accept_headers.encodings"].negotiate(supported_encodings)
20
21
  matched_language = env["accept_headers.languages"].negotiate(supported_languages)
21
22
  headers = {
22
- 'Content-Type' => matched_media_type ? matched_media_type.media_range : '',
23
- 'Content-Encoding' => matched_encoding ? matched_encoding.encoding : '',
24
- 'Content-Language' => matched_language ? matched_language.language_tag : '',
23
+ 'content-type' => matched_media_type ? matched_media_type.media_range : '',
24
+ 'content-encoding' => matched_encoding ? matched_encoding.encoding : '',
25
+ 'content-language' => matched_language ? matched_language.language_tag : '',
25
26
  }
26
27
 
27
28
  [ 200, headers, [ '' ] ]
@@ -0,0 +1,67 @@
1
+ require_relative "spec_helper"
2
+ require "rack/builder"
3
+ require "rack/lint"
4
+ require "rack/mock"
5
+
6
+ class ReadmeSpec < Minitest::Test
7
+ def test_documented_negotiation_results
8
+ context = binding
9
+ examples.each do |example|
10
+ next if example.start_with?("gem ") || example.include?('use AcceptHeaders::Middleware')
11
+ source = +""
12
+ example.each_line do |line|
13
+ if (expectation = /\A# => (.*)/.match(line))
14
+ expected = eval(expectation[1], context, readme_path)
15
+ actual = eval(source, context, readme_path)
16
+ if expected.nil?
17
+ assert_nil actual, source
18
+ else
19
+ assert_equal expected, actual, source
20
+ end
21
+ source.clear
22
+ else
23
+ source << line
24
+ end
25
+ end
26
+ eval(source, context, readme_path) unless source.strip.empty?
27
+ end
28
+ end
29
+
30
+ def test_rack_example_selects_supported_responses_and_honors_rejections
31
+ source = examples.find { |example| example.include?('use AcceptHeaders::Middleware') }
32
+ refute_nil source
33
+ builder = Rack::Builder.new
34
+ builder.instance_eval(source, readme_path)
35
+ request = Rack::MockRequest.new(Rack::Lint.new(builder.to_app))
36
+
37
+ response = request.get('/', 'HTTP_ACCEPT' => 'application/json', 'HTTP_ACCEPT_LANGUAGE' => 'en-GB')
38
+ assert_equal 200, response.status
39
+ assert_equal 'application/json;version=2', response['content-type']
40
+ assert_equal 'en-gb', response['content-language']
41
+ assert_equal '{"message":"Hello"}', response.body
42
+ assert_nil response['content-encoding']
43
+ assert_equal 'Accept, Accept-Encoding, Accept-Language', response['vary']
44
+
45
+ [
46
+ { 'HTTP_ACCEPT' => 'application/xml' },
47
+ { 'HTTP_ACCEPT' => 'application/json;version=1' },
48
+ { 'HTTP_ACCEPT_ENCODING' => 'identity;q=0' },
49
+ { 'HTTP_ACCEPT_LANGUAGE' => 'fr' }
50
+ ].each do |headers|
51
+ rejected = request.get('/', headers)
52
+ assert_equal 406, rejected.status, headers.inspect
53
+ assert_equal 'Not acceptable', rejected.body
54
+ assert_equal 'Accept, Accept-Encoding, Accept-Language', rejected['vary']
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def readme_path
61
+ File.expand_path('../README.md', __dir__)
62
+ end
63
+
64
+ def examples
65
+ File.read(readme_path).scan(/```ruby\n(.*?)```/m).flatten
66
+ end
67
+ end
@@ -0,0 +1,62 @@
1
+ require_relative "spec_helper"
2
+
3
+ describe "Negotiation exclusions" do
4
+ it "rejects an explicitly excluded media type despite an acceptable wildcard" do
5
+ negotiator = AcceptHeaders::MediaType::Negotiator.new('text/html;q=0, */*;q=1')
6
+
7
+ negotiator.negotiate('text/html').must_be_nil
8
+ negotiator.accept?('text/html').must_equal false
9
+ negotiator.negotiate(['text/html', 'application/json']).media_range.must_equal 'application/json'
10
+ end
11
+
12
+ it "allows an explicit media type to override a wildcard exclusion" do
13
+ negotiator = AcceptHeaders::MediaType::Negotiator.new('*/*;q=0, text/html;q=1')
14
+
15
+ negotiator.negotiate('text/html').media_range.must_equal 'text/html'
16
+ negotiator.accept?('application/json').must_equal false
17
+ end
18
+
19
+ it "rejects an explicitly excluded encoding despite an acceptable wildcard" do
20
+ negotiator = AcceptHeaders::Encoding::Negotiator.new('gzip;q=0, *;q=1')
21
+
22
+ negotiator.negotiate('gzip').must_be_nil
23
+ negotiator.accept?('gzip').must_equal false
24
+ negotiator.negotiate(['gzip', 'br']).encoding.must_equal 'br'
25
+ end
26
+
27
+ it "allows an explicit encoding to override a wildcard exclusion" do
28
+ negotiator = AcceptHeaders::Encoding::Negotiator.new('*;q=0, gzip;q=1')
29
+
30
+ negotiator.negotiate('gzip').encoding.must_equal 'gzip'
31
+ negotiator.accept?('br').must_equal false
32
+ end
33
+
34
+ it "rejects an explicitly excluded language despite an acceptable wildcard" do
35
+ negotiator = AcceptHeaders::Language::Negotiator.new('en-us;q=0, *;q=1')
36
+
37
+ negotiator.negotiate('en-us').must_be_nil
38
+ negotiator.accept?('en-us').must_equal false
39
+ negotiator.negotiate(['en-us', 'fr-ca']).language_tag.must_equal 'fr-ca'
40
+ end
41
+
42
+ it "allows an explicit language to override a wildcard exclusion" do
43
+ negotiator = AcceptHeaders::Language::Negotiator.new('*;q=0, en-us;q=1')
44
+
45
+ negotiator.negotiate('en-us').language_tag.must_equal 'en-us'
46
+ negotiator.accept?('fr-ca').must_equal false
47
+ end
48
+
49
+ it "allows a regional language to override a broader language exclusion" do
50
+ negotiator = AcceptHeaders::Language::Negotiator.new('en;q=0, en-us;q=1')
51
+
52
+ negotiator.negotiate('en-us').language_tag.must_equal 'en-us'
53
+ negotiator.accept?('en-gb').must_equal false
54
+ end
55
+
56
+ it "rejects a regional language despite an acceptable broader language" do
57
+ negotiator = AcceptHeaders::Language::Negotiator.new('en-us;q=0, en;q=1')
58
+
59
+ negotiator.negotiate('en-us').must_be_nil
60
+ negotiator.negotiate(['en-us', 'en-gb']).language_tag.must_equal 'en-gb'
61
+ end
62
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,7 @@
1
1
  require "simplecov"
2
2
 
3
3
  SimpleCov.start do
4
- formatter SimpleCov::Formatter::MultiFormatter[
5
- SimpleCov::Formatter::HTMLFormatter,
6
- ]
4
+ formatter SimpleCov::Formatter::HTMLFormatter
7
5
  add_filter 'spec/'
8
6
  end
9
7
 
@@ -0,0 +1,158 @@
1
+ require_relative "spec_helper"
2
+ require "open3"
3
+ require "rbconfig"
4
+
5
+ describe "supported representation validation" do
6
+ [
7
+ [AcceptHeaders::MediaType::Negotiator, 'text/plain', '*/*', 'Accept: text/plain'],
8
+ [AcceptHeaders::Encoding::Negotiator, 'gzip', '*', 'Accept-Encoding: gzip'],
9
+ [AcceptHeaders::Language::Negotiator, 'en-US', '*', 'Accept-Language: en-US']
10
+ ].each do |negotiator_class, valid, wildcard, prefixed|
11
+ describe negotiator_class.name do
12
+ it "rejects invalid offers before considering any header or other offer" do
13
+ invalid = [nil, false, 42, Object.new, '', ' ', wildcard, prefixed,
14
+ "#{valid},#{valid}", "#{valid};q=1", "#{valid};Q=1",
15
+ "#{valid};q=0.5", "#{valid};q=0", "#{valid}\r\n",
16
+ "#{valid}\0", "#{valid}\x7f", "#{valid}\v",
17
+ "\xff".b.force_encoding('UTF-8'), valid.encode('UTF-16LE')]
18
+ [nil, '', "#{wildcard};q=0", wildcard].each do |header|
19
+ negotiator = negotiator_class.new(header)
20
+ invalid.each do |value|
21
+ [:negotiate, :accept?].each do |method|
22
+ assert_raises(AcceptHeaders::InvalidSupportedValue, "#{method}: #{value.inspect}") do
23
+ negotiator.public_send(method, [valid, value])
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ it "raises ArgumentError for an invalid standalone offer" do
31
+ [false, {}, Object.new].each do |offer|
32
+ assert_raises(AcceptHeaders::InvalidSupportedValue) do
33
+ negotiator_class.new(wildcard).negotiate(offer)
34
+ end
35
+ end
36
+ end
37
+
38
+ it "retains nil and empty arrays as no offers" do
39
+ [nil, []].each do |supported|
40
+ negotiator = negotiator_class.new(nil)
41
+ assert_nil negotiator.negotiate(supported)
42
+ assert_equal false, negotiator.accept?(supported)
43
+ end
44
+ end
45
+
46
+ it "rejects objects that convert themselves to offer arrays" do
47
+ supported = Object.new
48
+ supported.define_singleton_method(:to_a) { [valid] }
49
+ assert_raises(AcceptHeaders::InvalidSupportedValue) do
50
+ negotiator_class.new(nil).negotiate(supported)
51
+ end
52
+ end
53
+
54
+ it "accepts case and optional whitespace without mutating frozen offers" do
55
+ offer = " \t#{valid.upcase}\t ".freeze
56
+ negotiator = negotiator_class.new(wildcard)
57
+ assert_equal true, negotiator.accept?(offer)
58
+ assert_equal " \t#{valid.upcase}\t ", offer
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "media type syntax" do
64
+ let(:negotiator) { AcceptHeaders::MediaType::Negotiator.new('*/*') }
65
+
66
+ it "rejects incomplete types and malformed parameters throughout the offer" do
67
+ ['text', 'text/*', '*/plain', 'text/plain/', 'text /plain',
68
+ 'text/plain;note', 'text/plain;note=', 'text/plain;=value',
69
+ 'text/plain;note=two words', 'text/plain;note="unclosed',
70
+ 'text/plain;note="closed"junk', 'text/plain;note="trailing' + "\\",
71
+ 'text/plain;note="valid";broken', 'text/plain; Q = "1"',
72
+ 'text/plain;note="a,b" , application/json', 'text/plain,garbage',
73
+ "text/plain;note=\"line\nbreak\"", "text/plain;note=\"escaped\\\nbreak\""].each do |offer|
74
+ assert_raises(AcceptHeaders::InvalidSupportedValue, offer) { negotiator.negotiate(offer) }
75
+ end
76
+ end
77
+
78
+ it "preserves quoted delimiters, escapes, quality text, and non-ASCII values" do
79
+ offer = 'Text/Plain;note="a,b;c\\"d\\\\e;q=1";label="café"'.freeze
80
+ result = negotiator.negotiate(offer)
81
+ assert_equal 'text/plain', result.media_range
82
+ assert_equal({'note' => 'a,b;c"d\\e;q=1', 'label' => "caf\u00e9"}, result.extensions)
83
+ end
84
+
85
+ it "preserves quoted obs-text bytes" do
86
+ offer = "text/plain;note=\"\x80\xff\"".b.freeze
87
+ result = negotiator.negotiate(offer)
88
+ assert_equal "\x80\xff".b, result.extensions['note']
89
+ end
90
+
91
+ it "uses HTTP bytes for multibyte offers, quoted pairs, and response escaping" do
92
+ {
93
+ [0x95, 0x5c, 0x5c] => [0x95, 0x5c],
94
+ [0x95, 0x5c, 0x5c, 0x61] => [0x95, 0x5c, 0x61],
95
+ [0x95, 0x5c, 0x61] => [0x95, 0x61]
96
+ }.each do |bytes, expected|
97
+ wire = 'text/plain;note="'.b + bytes.pack('C*') + '"'
98
+ offer = wire.dup.force_encoding('Shift_JIS').freeze
99
+ original = offer.dup
100
+ [nil, '*/*', wire, offer].each do |header|
101
+ matcher = AcceptHeaders::MediaType::Negotiator.new(header)
102
+ assert matcher.accept?(offer)
103
+ result = matcher.negotiate(offer)
104
+ assert_equal expected, result.extensions['note'].bytes
105
+ binary_result = negotiator.negotiate(wire)
106
+ assert_equal binary_result.content_type.bytes, result.content_type.bytes
107
+ assert_equal binary_result.to_s.bytes, result.to_s.bytes
108
+ [result.content_type, result.to_s].each do |serialized|
109
+ reparsed = AcceptHeaders::MediaType::Negotiator.new(serialized.b).list.first
110
+ assert_equal expected, reparsed.extensions['note'].bytes
111
+ end
112
+ end
113
+ assert_equal original, offer
114
+ assert_equal original.encoding, offer.encoding
115
+ end
116
+ end
117
+
118
+ it "compares parameter bytes across encodings without transcoding or Unicode case folding" do
119
+ offer = 'text/plain;note="café";charset="K"'.freeze
120
+ labelled_offer = offer.dup.force_encoding('ISO-8859-1').freeze
121
+ [offer, offer.b, labelled_offer].each do |header|
122
+ matcher = AcceptHeaders::MediaType::Negotiator.new(header)
123
+ [offer, offer.b, labelled_offer].each do |supported|
124
+ result = matcher.negotiate(supported)
125
+ assert_equal offer.bytes, result.content_type.bytes
126
+ end
127
+ refute matcher.accept?('text/plain;note="café";charset=k')
128
+ refute matcher.accept?(offer.encode('Windows-1252', undef: :replace))
129
+ end
130
+ result = negotiator.negotiate(offer)
131
+ assert_equal Encoding::UTF_8, result.extensions['note'].encoding
132
+ assert_equal Encoding::UTF_8, result.content_type.encoding
133
+
134
+ utf8_offer = 'text/plain;note="café"'.freeze
135
+ latin1_offer = utf8_offer.encode('ISO-8859-1').freeze
136
+ [utf8_offer, latin1_offer].each do |header|
137
+ matcher = AcceptHeaders::MediaType::Negotiator.new(header)
138
+ other_offer = header.equal?(utf8_offer) ? latin1_offer : utf8_offer
139
+ assert_nil matcher.negotiate(other_offer)
140
+ refute matcher.accept?(other_offer)
141
+ end
142
+ end
143
+
144
+ it "accepts empty parameter segments and empty quoted values" do
145
+ result = negotiator.negotiate('text/plain; ; note="";;')
146
+ assert_equal({'note' => ''}, result.extensions)
147
+ end
148
+ end
149
+
150
+ it "exposes the shared exception through each direct negotiator require" do
151
+ %w[media_type encoding language].each do |kind|
152
+ script = "require 'accept_headers/#{kind}/negotiator'; " \
153
+ "abort unless AcceptHeaders::InvalidSupportedValue < ArgumentError"
154
+ output, status = Open3.capture2e(RbConfig.ruby, '-Ilib', '-e', script)
155
+ assert status.success?, output
156
+ end
157
+ end
158
+ end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: accept_headers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jack Chu
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2019-04-19 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rake
@@ -16,14 +15,14 @@ dependencies:
16
15
  requirements:
17
16
  - - "~>"
18
17
  - !ruby/object:Gem::Version
19
- version: '12.0'
18
+ version: '13.0'
20
19
  type: :development
21
20
  prerelease: false
22
21
  version_requirements: !ruby/object:Gem::Requirement
23
22
  requirements:
24
23
  - - "~>"
25
24
  - !ruby/object:Gem::Version
26
- version: '12.0'
25
+ version: '13.0'
27
26
  - !ruby/object:Gem::Dependency
28
27
  name: minitest
29
28
  requirement: !ruby/object:Gem::Requirement
@@ -66,16 +65,17 @@ dependencies:
66
65
  - - ">="
67
66
  - !ruby/object:Gem::Version
68
67
  version: '0'
69
- description: A ruby library that does content negotiation and parses and sorts http
70
- accept headers. Adheres to RFC 2616.
68
+ description: A ruby library that parses HTTP accept headers and negotiates media types,
69
+ content codings, and languages using RFC 9110 and RFC 4647 Basic Filtering.
71
70
  email:
72
71
  - kamuigt@gmail.com
73
72
  executables: []
74
73
  extensions: []
75
74
  extra_rdoc_files: []
76
75
  files:
76
+ - ".github/dependabot.yml"
77
+ - ".github/workflows/ci.yml"
77
78
  - ".gitignore"
78
- - ".travis.yml"
79
79
  - CHANGELOG.md
80
80
  - Gemfile
81
81
  - Guardfile
@@ -87,6 +87,7 @@ files:
87
87
  - lib/accept_headers/acceptable.rb
88
88
  - lib/accept_headers/encoding.rb
89
89
  - lib/accept_headers/encoding/negotiator.rb
90
+ - lib/accept_headers/invalid_supported_value.rb
90
91
  - lib/accept_headers/language.rb
91
92
  - lib/accept_headers/language/negotiator.rb
92
93
  - lib/accept_headers/media_type.rb
@@ -96,11 +97,15 @@ files:
96
97
  - lib/accept_headers/version.rb
97
98
  - spec/encoding/negotiator_spec.rb
98
99
  - spec/encoding_spec.rb
100
+ - spec/equality_spec.rb
99
101
  - spec/language/negotiator_spec.rb
100
102
  - spec/language_spec.rb
103
+ - spec/malformed_spec.rb
101
104
  - spec/media_type/negotiator_spec.rb
102
105
  - spec/media_type_spec.rb
103
106
  - spec/middleware_spec.rb
107
+ - spec/readme_spec.rb
108
+ - spec/rejection_spec.rb
104
109
  - spec/spec_helper.rb
105
110
  - spec/support/encodings/content-coding.csv
106
111
  - spec/support/media_types/application.csv
@@ -111,11 +116,11 @@ files:
111
116
  - spec/support/media_types/multipart.csv
112
117
  - spec/support/media_types/text.csv
113
118
  - spec/support/media_types/video.csv
119
+ - spec/supported_values_spec.rb
114
120
  homepage: ''
115
121
  licenses:
116
122
  - MIT
117
123
  metadata: {}
118
- post_install_message:
119
124
  rdoc_options: []
120
125
  require_paths:
121
126
  - lib
@@ -130,19 +135,22 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
135
  - !ruby/object:Gem::Version
131
136
  version: '0'
132
137
  requirements: []
133
- rubygems_version: 3.0.3
134
- signing_key:
138
+ rubygems_version: 4.0.16
135
139
  specification_version: 4
136
140
  summary: A ruby library that does content negotiation and parses and sorts http accept
137
141
  headers.
138
142
  test_files:
139
143
  - spec/encoding/negotiator_spec.rb
140
144
  - spec/encoding_spec.rb
145
+ - spec/equality_spec.rb
141
146
  - spec/language/negotiator_spec.rb
142
147
  - spec/language_spec.rb
148
+ - spec/malformed_spec.rb
143
149
  - spec/media_type/negotiator_spec.rb
144
150
  - spec/media_type_spec.rb
145
151
  - spec/middleware_spec.rb
152
+ - spec/readme_spec.rb
153
+ - spec/rejection_spec.rb
146
154
  - spec/spec_helper.rb
147
155
  - spec/support/encodings/content-coding.csv
148
156
  - spec/support/media_types/application.csv
@@ -153,3 +161,4 @@ test_files:
153
161
  - spec/support/media_types/multipart.csv
154
162
  - spec/support/media_types/text.csv
155
163
  - spec/support/media_types/video.csv
164
+ - spec/supported_values_spec.rb
data/.travis.yml DELETED
@@ -1,14 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.4.6
4
- - 2.5.5
5
- - 2.6.3
6
- - ruby-head
7
- - jruby-9.2.7.0
8
- - jruby-head
9
- - rbx-3.107
10
- matrix:
11
- allow_failures:
12
- - rvm: ruby-head
13
- - rvm: jruby-head
14
- - rvm: rbx-3.107