accept_headers 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a061f83d7dbd285a45d4bbdbc9be56ebdca2ccc
4
- data.tar.gz: 1a5a1496f0f771138858e9b09f0ed128c9ebe7c6
3
+ metadata.gz: 4df1427bbf8cc170c8d3eb303c6978f4c03d4b3e
4
+ data.tar.gz: 7efc9d1f82cfd666507f72fae4b09e7020516970
5
5
  SHA512:
6
- metadata.gz: c6c86cb2c4470f793c309cd5cf742a90da0cba728551f7df3f0561f4a259d5427338e674b07069137063025c86e7503afca878428018f4afd165968675e0a10c
7
- data.tar.gz: 3cb9ce5bdc3863a37126e6bde2e89997c05db3696bf28ad64e6ed330234464bc4c56ff57c5bef2a25ef8abb56174add04e755ff402dc0184986c003e06ddc868
6
+ metadata.gz: 339ce5ee8e97554e7d890179f6362e279d1933deec79f351c617ada281415d1f30e80f92080cb4eebe20e56a5436b2b5cd5ecc663940a65b77ee9697252dd165
7
+ data.tar.gz: 899d66e7efd0d9479adbc800de51d6abc3f3cb8d4c7950bf0ce1de344f7218757b5936d0d7814bbbdeb640daaa4faaf068b3a7fa39b879e1a4a6c0770040563c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,16 @@
1
+ ## HEAD
2
+
3
+ ## 0.0.5 / November 16, 2014
4
+
5
+ * Add `#accept?` and `#reject?` methods to all negotiators.
6
+ * Add `#accept?` method to all negotiators.
7
+ * Return nil if no matches on `#negotiate`.
8
+ * Fix matching logic in `MediaType`, `Encoding`, and `Language`.
9
+ * Test all IANA registered encodings against the parser.
10
+ * Fix `simplecov` loading.
11
+ * Update `audio.csv` media type file with typo fix.
12
+ * More specs.
13
+
1
14
  ## 0.0.4 / November 15, 2014
2
15
 
3
16
  * Add MediaType#media_range which is the type/subtype as a string.
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source "https://rubygems.org"
2
2
 
3
- # Specify your gem's dependencies in retriable.gemspec
3
+ # Specify your gem's dependencies in accept_headers.gemspec
4
4
  gemspec
5
5
 
6
6
  group :test do
data/README.md CHANGED
@@ -63,16 +63,22 @@ media_types.list
63
63
  ]
64
64
  ```
65
65
 
66
- `#negotiate` takes a string of media types supported (by your API or route/controller) and returns the best match as a `MediaType`. This will first check the available list for any matching media types with a `q` of 0 and return `nil` if there is a match. Then it'll look to the highest `q` values and look for matches in descending `q` value order and return the first match account for wildcards.
66
+ `#negotiate` takes a string of media types supported (by your API or route/controller) and returns the best match as a `MediaType`. This will first check the available list for any matching media types with a `q` of 0 and return `nil` if there is a match. Then it'll look to the highest `q` values and look for matches in descending `q` value order and return the first match (accounting for wildcards). Finally, if there are no matches, it returns `nil`.
67
67
 
68
68
  ```ruby
69
- media_type.negotiate('text/html')
69
+ media_types.negotiate('text/html')
70
70
 
71
71
  # Returns:
72
72
 
73
73
  AcceptHeaders::MediaType.new('text', 'html', params: { 'level' => '1' })
74
74
  ```
75
75
 
76
+ `#accept?`:
77
+
78
+ ```ruby
79
+ media_types.accept?('text/html') # true
80
+ ```
81
+
76
82
  ### Accept-Encoding
77
83
 
78
84
  `AcceptHeader::Charset::Encoding`:
@@ -86,7 +92,6 @@ encodings.list
86
92
 
87
93
  [
88
94
  AcceptHeaders::Encoding.new('gzip'),
89
- AcceptHeaders::Encoding.new('identity'),
90
95
  AcceptHeaders::Encoding.new('compress', q: 0.8),
91
96
  AcceptHeaders::Encoding.new('deflate', q: 0.5)
92
97
  ]
@@ -95,11 +100,21 @@ encodings.list
95
100
  `#negotiate`:
96
101
 
97
102
  ```ruby
98
- encodings.negotiate('identity')
103
+ encodings.negotiate('gzip')
99
104
 
100
105
  # Returns:
101
106
 
102
- AcceptHeaders::Encoding.new('identity')
107
+ AcceptHeaders::Encoding.new('gzip')
108
+ ```
109
+
110
+ `#accept?`:
111
+
112
+ ```ruby
113
+ encodings.accept?('gzip') # true
114
+
115
+ # Identity is accepted as long as it's not explicitly rejected 'identity;q=0'
116
+
117
+ encodings.accept?('identity') # true
103
118
  ```
104
119
 
105
120
  ### Accept-Language
@@ -130,7 +145,13 @@ languages.negotiate('en-us')
130
145
  AcceptHeaders::Language.new('en', 'us')
131
146
  ```
132
147
 
133
- ## Todo
148
+ `#accept?`:
149
+
150
+ ```ruby
151
+ languages.accept?('en-gb') # true
152
+ ```
153
+
154
+ ## TODO
134
155
 
135
156
  * Write rack middleware
136
157
  * More edge case tests
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["Jack Chu"]
10
10
  spec.email = ["kamuigt@gmail.com"]
11
11
  spec.summary = %q{A ruby library that does content negotiation and parses and sorts http accept headers.}
12
- spec.description = %q{a ruby library that does content negotiation and parses and sorts http accept headers. Adheres to RFC 2616.}
12
+ spec.description = %q{A ruby library that does content negotiation and parses and sorts http accept headers. Adheres to RFC 2616.}
13
13
  spec.homepage = ""
14
14
  spec.license = "MIT"
15
15
 
@@ -5,8 +5,20 @@ module AcceptHeaders
5
5
 
6
6
  attr_reader :q
7
7
 
8
- def match(other)
9
- raise NotImplementedError.new("#match is not implemented")
8
+ def reject?(other)
9
+ if q != 0.0
10
+ false
11
+ else
12
+ match(other)
13
+ end
14
+ end
15
+
16
+ def accept?(other)
17
+ if q == 0.0
18
+ false
19
+ else
20
+ match(other)
21
+ end
10
22
  end
11
23
 
12
24
  def q=(value)
@@ -23,5 +35,10 @@ module AcceptHeaders
23
35
  end
24
36
  @q = q_float
25
37
  end
38
+
39
+ private
40
+ def match(other)
41
+ raise NotImplementedError.new("#match is not implemented")
42
+ end
26
43
  end
27
44
  end
@@ -7,6 +7,8 @@ module AcceptHeaders
7
7
 
8
8
  attr_reader :encoding
9
9
 
10
+ ENCODING_PATTERN = /^\s*(?<encoding>[\w!#$%^&*\-\+{}\\|'.`~]+)\s*$/
11
+
10
12
  def initialize(encoding = '*', q: 1.0)
11
13
  self.encoding = encoding
12
14
  self.q = q
@@ -32,10 +34,16 @@ module AcceptHeaders
32
34
  "#{encoding};q=#{qvalue}"
33
35
  end
34
36
 
35
- def match(other)
36
- if encoding == other.encoding
37
+ private
38
+ def match(encoding_string)
39
+ match_data = ENCODING_PATTERN.match(encoding_string)
40
+ if !match_data
41
+ false
42
+ elsif encoding == match_data[:encoding]
43
+ true
44
+ elsif match_data[:encoding] == 'identity'
37
45
  true
38
- elsif other.encoding == '*'
46
+ elsif encoding == '*'
39
47
  true
40
48
  else
41
49
  false
@@ -16,9 +16,9 @@ module AcceptHeaders
16
16
  header.split(',').each do |entry|
17
17
  encoding_arr = entry.split(';', 2)
18
18
  next if encoding_arr[0].nil?
19
- encoding = TOKEN_PATTERN.match(encoding_arr[0])
19
+ encoding = Encoding::ENCODING_PATTERN.match(encoding_arr[0])
20
20
  next if encoding.nil?
21
- encodings << Encoding.new(encoding[:token], q: parse_q(encoding_arr[1]))
21
+ encodings << Encoding.new(encoding[:encoding], q: parse_q(encoding_arr[1]))
22
22
  end
23
23
  encodings.sort! { |x,y| y <=> x }
24
24
  end
@@ -7,6 +7,8 @@ module AcceptHeaders
7
7
 
8
8
  attr_reader :primary_tag, :subtag, :params
9
9
 
10
+ LANGUAGE_TAG_PATTERN = /^\s*(?<primary_tag>[\w]{1,8}|\*)(?:\s*\-\s*(?<subtag>[\w]{1,8}|\*))?\s*$/
11
+
10
12
  def initialize(primary_tag = '*', subtag = nil, q: 1.0)
11
13
  self.primary_tag = primary_tag
12
14
  self.subtag = subtag
@@ -53,15 +55,23 @@ module AcceptHeaders
53
55
  end
54
56
 
55
57
  def language_tag
56
- "#{primary_tag}-#{subtag}"
58
+ if primary_tag == '*' && (subtag.nil? || subtag == '*')
59
+ '*'
60
+ else
61
+ "#{primary_tag}-#{subtag}"
62
+ end
57
63
  end
58
64
 
59
- def match(other)
60
- if primary_tag == other.primary_tag && subtag == other.subtag
65
+ private
66
+ def match(language_tag_string)
67
+ match_data = LANGUAGE_TAG_PATTERN.match(language_tag_string)
68
+ if !match_data
69
+ false
70
+ elsif primary_tag == match_data[:primary_tag] && subtag == match_data[:subtag]
61
71
  true
62
- elsif primary_tag == other.primary_tag && subtag == '*'
72
+ elsif primary_tag == match_data[:primary_tag] && subtag == '*'
63
73
  true
64
- elsif other.primary_tag == '*'
74
+ elsif primary_tag == '*'
65
75
  true
66
76
  else
67
77
  false
@@ -6,8 +6,6 @@ module AcceptHeaders
6
6
  class Negotiator
7
7
  include Negotiatable
8
8
 
9
- LANGUAGE_PATTERN = /^\s*(?<primary_tag>[\w]{1,8}|\*)(?:\s*\-\s*(?<subtag>[\w]{1,8}|\*))?\s*$/
10
-
11
9
  private
12
10
  def parse(original_header)
13
11
  header = original_header.dup
@@ -18,7 +16,7 @@ module AcceptHeaders
18
16
  header.split(',').each do |entry|
19
17
  language_arr = entry.split(';', 2)
20
18
  next if language_arr[0].nil?
21
- language_range = LANGUAGE_PATTERN.match(language_arr[0])
19
+ language_range = Language::LANGUAGE_TAG_PATTERN.match(language_arr[0])
22
20
  next if language_range.nil?
23
21
  begin
24
22
  languages << Language.new(
@@ -7,6 +7,8 @@ module AcceptHeaders
7
7
 
8
8
  attr_reader :type, :subtype, :params
9
9
 
10
+ MEDIA_TYPE_PATTERN = /^\s*(?<type>[\w!#$%^&*\-\+{}\\|'.`~]+)(?:\s*\/\s*(?<subtype>[\w!#$%^&*\-\+{}\\|'.`~]+))?\s*$/
11
+
10
12
  def initialize(type = '*', subtype = '*', q: 1.0, params: {})
11
13
  self.type = type
12
14
  self.subtype = subtype
@@ -74,12 +76,16 @@ module AcceptHeaders
74
76
  "#{type}/#{subtype}"
75
77
  end
76
78
 
77
- def match(other)
78
- if type == other.type && subtype == other.subtype
79
+ private
80
+ def match(media_range_string)
81
+ match_data = MEDIA_TYPE_PATTERN.match(media_range_string)
82
+ if !match_data
83
+ false
84
+ elsif type == match_data[:type] && subtype == match_data[:subtype]
79
85
  true
80
- elsif type == other.type && subtype == '*'
86
+ elsif type == match_data[:type] && subtype == '*'
81
87
  true
82
- elsif other.type == '*' && other.subtype == '*'
88
+ elsif type == '*' && subtype == '*'
83
89
  true
84
90
  else
85
91
  false
@@ -7,7 +7,6 @@ module AcceptHeaders
7
7
  include Negotiatable
8
8
 
9
9
  private
10
- MEDIA_TYPE_PATTERN = /^\s*(?<type>[\w!#$%^&*\-\+{}\\|'.`~]+)(?:\s*\/\s*(?<subtype>[\w!#$%^&*\-\+{}\\|'.`~]+))?\s*$/
11
10
  PARAM_PATTERN = /(?<attribute>[\w!#$%^&*\-\+{}\\|'.`~]+)\s*\=\s*(?:\"(?<value>[^"]*)\"|\'(?<value>[^']*)\'|(?<value>[\w!#$%^&*\-\+{}\\|\'.`~]*))/
12
11
 
13
12
  def parse(original_header)
@@ -19,7 +18,7 @@ module AcceptHeaders
19
18
  header.split(',').each do |entry|
20
19
  accept_media_range, accept_params = entry.split(';', 2)
21
20
  next if accept_media_range.nil?
22
- media_range = MEDIA_TYPE_PATTERN.match(accept_media_range)
21
+ media_range = MediaType::MEDIA_TYPE_PATTERN.match(accept_media_range)
23
22
  next if media_range.nil?
24
23
  begin
25
24
  media_types << MediaType.new(
@@ -3,7 +3,6 @@ module AcceptHeaders
3
3
  class Error < StandardError; end
4
4
  class ParseError < Error; end
5
5
 
6
- TOKEN_PATTERN = /^\s*(?<token>[\w!#$%^&*\-\+{}\\|'.`~]+)\s*$/
7
6
  Q_PATTERN = /(?:\A|;)\s*(?<exists>qs*\=)\s*(?:(?<q>0\.\d{1,3}|[01])|(?:[^;]*))\s*(?:\z|;)/
8
7
 
9
8
  attr_reader :list
@@ -12,24 +11,29 @@ module AcceptHeaders
12
11
  @list = parse(header)
13
12
  end
14
13
 
15
- def negotiate(supported_string)
16
- supported = parse(supported_string)
14
+ def negotiate(supported)
17
15
  return nil if @list.empty?
16
+ supported = [*supported]
18
17
  rejects, acceptable = @list.partition { |m| m.q == 0.0 }
19
18
  rejects.each do |reject|
20
19
  supported.each do |support|
21
- if support.match(reject)
20
+ if reject.reject?(support)
22
21
  return nil
23
22
  end
24
23
  end
25
24
  end
26
25
  acceptable.sort { |x,y| y <=> x }.each do |accepted|
27
26
  supported.each do |support|
28
- if support.match(accepted)
27
+ if accepted.accept?(support)
29
28
  return accepted
30
29
  end
31
30
  end
32
31
  end
32
+ nil
33
+ end
34
+
35
+ def accept?(other)
36
+ negotiate(other) ? true : false
33
37
  end
34
38
 
35
39
  private
@@ -1,3 +1,3 @@
1
1
  module AcceptHeaders
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -22,6 +22,19 @@ module AcceptHeaders
22
22
  ]
23
23
  end
24
24
 
25
+ it "supports all registered IANA encodings" do
26
+ require 'csv'
27
+ # https://www.iana.org/assignments/http-parameters/http-parameters.xml#content-coding
28
+ CSV.foreach("spec/support/encodings/content-coding.csv", headers: true) do |row|
29
+ encoding = row['Name']
30
+
31
+ if encoding
32
+ subject.new(encoding).list.size.must_equal 1
33
+ subject.new(encoding).list.first.encoding.must_equal encoding.downcase
34
+ end
35
+ end
36
+ end
37
+
25
38
  it "sets encoding to * when the accept-encoding header is empty" do
26
39
  subject.new('').list.must_equal [
27
40
  Encoding.new('*')
@@ -68,5 +68,73 @@ module AcceptHeaders
68
68
  s = subject.new('gzip', q: 0.9).to_s
69
69
  s.must_equal "gzip;q=0.9"
70
70
  end
71
+
72
+ describe "#accept?" do
73
+ it "accepted if the encoding is the same" do
74
+ a = subject.new('gzip')
75
+ a.accept?('gzip').must_equal true
76
+ b = subject.new('gzip', q: 0.001)
77
+ b.accept?('gzip').must_equal true
78
+ end
79
+
80
+ it "accepted if the encoding is *" do
81
+ a = subject.new('*')
82
+ a.accept?('gzip').must_equal true
83
+ b = subject.new('*', q: 0.1)
84
+ b.accept?('gzip').must_equal true
85
+ end
86
+
87
+ it "not accepted if the encoding doesn't match" do
88
+ a = subject.new('gzip')
89
+ a.accept?('compress').must_equal false
90
+ b = subject.new('gzip', q: 0.4)
91
+ b.accept?('compress').must_equal false
92
+ end
93
+
94
+ it "not accepted if q is 0" do
95
+ a = subject.new('gzip', q: 0)
96
+ a.accept?('gzip').must_equal false
97
+ b = subject.new('*', q: 0)
98
+ b.accept?('gzip').must_equal false
99
+ end
100
+
101
+ # TODO: test *
102
+ # it "not accepted if..." do
103
+ # a = subject.new('gzip')
104
+ # a.accept?('*').must_equal true
105
+ # end
106
+ end
107
+
108
+ describe "#reject?" do
109
+ describe "given q is 0" do
110
+ it "rejected if the encoding is the same" do
111
+ a = subject.new('gzip', q: 0)
112
+ a.reject?('gzip').must_equal true
113
+ end
114
+
115
+ it "rejected if the encoding is *" do
116
+ a = subject.new('*', q: 0)
117
+ a.reject?('gzip').must_equal true
118
+ end
119
+
120
+ it "not rejected if the encoding doesn't match" do
121
+ a = subject.new('gzip', q: 0)
122
+ a.reject?('compress').must_equal false
123
+ end
124
+
125
+ # TODO: test *
126
+ # it "not rejected if..." do
127
+ # a = subject.new('gzip', q: 0)
128
+ # a.reject?('*').must_equal true
129
+ # end
130
+ end
131
+
132
+ it "not rejected if q > 0" do
133
+ a = subject.new('gzip', q: 0.001)
134
+ a.reject?('gzip').must_equal false
135
+ b = subject.new('*', q: 0.9)
136
+ b.reject?('gzip').must_equal false
137
+ end
138
+ end
71
139
  end
72
140
  end
@@ -87,8 +87,127 @@ module AcceptHeaders
87
87
  s.must_equal "en-us;q=0.9"
88
88
  end
89
89
 
90
- it "outputs the language tag" do
91
- subject.new('en', 'us', q: 0.9).language_tag.must_equal "en-us"
90
+ describe "#language_tag" do
91
+ it "outputs the language tag" do
92
+ subject.new('en', 'us', q: 0.9).language_tag.must_equal "en-us"
93
+ end
94
+
95
+ it "if primary tag is * and subtag is * or nil, outputs *" do
96
+ subject.new('*', nil).language_tag.must_equal '*'
97
+ subject.new('*', '*').language_tag.must_equal '*'
98
+ end
99
+ end
100
+
101
+ describe "#accept?" do
102
+ it "accepted if the primary_tag and subtag are the same" do
103
+ a = subject.new('en', 'us')
104
+ a.accept?('en-us').must_equal true
105
+ b = subject.new('en', 'us', q: 0.001)
106
+ b.accept?('en-us').must_equal true
107
+ end
108
+
109
+ it "accepted if the primary_tag is the same and the other subtag is *" do
110
+ a = subject.new('en', '*')
111
+ a.accept?('en-us').must_equal true
112
+ b = subject.new('en', '*', q: 0.9)
113
+ b.accept?('en-us').must_equal true
114
+ end
115
+
116
+ it "accepted if the primary_tag and subtag are *" do
117
+ a = subject.new('*')
118
+ a.accept?('en-us').must_equal true
119
+ b = subject.new('*', q: 0.1)
120
+ b.accept?('en-us').must_equal true
121
+ end
122
+
123
+ it "not accepted if the primary_tag and subtag don't match" do
124
+ a = subject.new('en', 'us')
125
+ a.accept?('en-gb').must_equal false
126
+ b = subject.new('en', 'us', q: 0.2)
127
+ b.accept?('en-gb').must_equal false
128
+ end
129
+
130
+ it "not accepted if the primary_tag doesn't match" do
131
+ a = subject.new('en', 'us')
132
+ a.accept?('zh-us').must_equal false
133
+ b = subject.new('en', 'us', q: 0.4)
134
+ b.accept?('zh-us').must_equal false
135
+ end
136
+
137
+ it "not accepted if the subtag doesn't match" do
138
+ a = subject.new('en', 'us')
139
+ a.accept?('en-gb').must_equal false
140
+ b = subject.new('en', 'us', q: 0.6)
141
+ b.accept?('en-gb').must_equal false
142
+ end
143
+
144
+ it "not accepted if q is 0" do
145
+ a = subject.new('en', 'us', q: 0)
146
+ a.accept?('en-us').must_equal false
147
+ a.accept?('en-gb').must_equal false
148
+ a.accept?('zh-us').must_equal false
149
+ b = subject.new('en', '*', q: 0)
150
+ b.accept?('en-us').must_equal false
151
+ c = subject.new('*', q: 0)
152
+ c.accept?('en-us').must_equal false
153
+ end
154
+
155
+ # TODO: test *
156
+ it "not accepted if..." do
157
+ a = subject.new('en', 'us')
158
+ a.accept?('*').must_equal false
159
+ end
160
+ end
161
+
162
+ describe "#reject?" do
163
+ describe "given q is 0" do
164
+ it "rejected if the primary_tag and subtag are the same" do
165
+ a = subject.new('en', 'us', q: 0)
166
+ a.reject?('en-us').must_equal true
167
+ end
168
+
169
+ it "rejected if the primary_tag is the same and the other subtag is *" do
170
+ a = subject.new('en', '*', q: 0)
171
+ a.reject?('en-us').must_equal true
172
+ end
173
+
174
+ it "rejected if the primary_tag and subtag are *" do
175
+ a = subject.new('*', q: 0)
176
+ a.reject?('en-us').must_equal true
177
+ end
178
+
179
+ it "not rejected if the primary_tag and subtag don't match" do
180
+ a = subject.new('en', 'us', q: 0)
181
+ a.reject?('en-gb').must_equal false
182
+ end
183
+
184
+ it "not rejected if the primary_tag doesn't match" do
185
+ a = subject.new('en', 'us', q: 0)
186
+ a.reject?('zh-us').must_equal false
187
+ end
188
+
189
+ it "not rejected if the subtag doesn't match" do
190
+ a = subject.new('en', 'us', q: 0)
191
+ a.reject?('en-gb').must_equal false
192
+ end
193
+
194
+ # TODO: test *
195
+ it "not rejected if..." do
196
+ a = subject.new('en', 'us', q: 0)
197
+ a.reject?('*').must_equal false
198
+ end
199
+ end
200
+
201
+ it "not rejected if q > 0" do
202
+ a = subject.new('en', 'us', q: 0.001)
203
+ a.reject?('en-us').must_equal false
204
+ a.reject?('en-gb').must_equal false
205
+ a.reject?('zh-us').must_equal false
206
+ b = subject.new('en', '*', q: 0.9)
207
+ b.reject?('en-us').must_equal false
208
+ c = subject.new('*', q: 1)
209
+ c.reject?('en-us').must_equal false
210
+ end
92
211
  end
93
212
  end
94
213
  end
@@ -40,12 +40,9 @@ module AcceptHeaders
40
40
  require 'csv'
41
41
  # https://www.iana.org/assignments/media-types/media-types.xhtml
42
42
  %w[application audio image message model multipart text video].each do |filename|
43
- CSV.foreach("spec/support/#{filename}.csv", headers: true) do |row|
43
+ CSV.foreach("spec/support/media_types/#{filename}.csv", headers: true) do |row|
44
44
  media_type = row['Template']
45
45
 
46
- # audio/amr-wb+ is a typo
47
- media_type = 'audio/amr-wb+' if media_type == 'amr-wb+'
48
-
49
46
  if media_type
50
47
  subject.new(media_type).list.size.must_equal 1
51
48
  subject.new(media_type).list.first.media_range.must_equal media_type.downcase
@@ -99,12 +96,27 @@ module AcceptHeaders
99
96
  end
100
97
  end
101
98
 
102
- describe "negotiate supported media types" do
99
+ describe "#negotiate" do
103
100
  it "returns a best matching media type" do
104
101
  n = subject.new("text/*, text/html, text/html;level=1, */*")
105
102
  n.negotiate("text/html").must_equal MediaType.new('text', 'html', params: { 'level' => '1' })
106
103
  end
107
104
  end
105
+
106
+ describe "#accept?" do
107
+ it "returns whether specific media type is accepted" do
108
+ n = subject.new("video/*, text/html, text/html;level=1;q:0.8")
109
+ n.accept?("text/html").must_equal true
110
+ n.accept?("application/json").must_equal false
111
+ n.accept?("video/ogg").must_equal true
112
+ end
113
+
114
+ it "returns false if accepted but q=0" do
115
+ n = subject.new("video/*, text/html;q=0")
116
+ n.accept?("text/html").must_equal false
117
+ n.accept?("video/ogg").must_equal true
118
+ end
119
+ end
108
120
  end
109
121
  end
110
122
  end
@@ -99,5 +99,117 @@ module AcceptHeaders
99
99
  it "outputs the media range" do
100
100
  subject.new('text', 'html', params: { 'level' => '1' }).media_range.must_equal "text/html"
101
101
  end
102
+
103
+ describe "#accept?" do
104
+ it "accepted if the type and subtype are the same" do
105
+ a = subject.new('text', 'html')
106
+ a.accept?('text/html').must_equal true
107
+ b = subject.new('text', 'html', q: 0.001)
108
+ b.accept?('text/html').must_equal true
109
+ end
110
+
111
+ it "accepted if the type is the same and the other subtype is *" do
112
+ a = subject.new('text', '*')
113
+ a.accept?('text/html').must_equal true
114
+ b = subject.new('text', '*', q: 0.9)
115
+ b.accept?('text/html').must_equal true
116
+ end
117
+
118
+ it "accepted if the type and subtype are *" do
119
+ a = subject.new('*')
120
+ a.accept?('text/html').must_equal true
121
+ b = subject.new('*', q: 0.1)
122
+ b.accept?('text/html').must_equal true
123
+ end
124
+
125
+ it "not accepted if the type and subtype don't match" do
126
+ a = subject.new('text', 'html')
127
+ a.accept?('application/json').must_equal false
128
+ b = subject.new('text', 'html', q: 0.2)
129
+ b.accept?('application/json').must_equal false
130
+ end
131
+
132
+ it "not accepted if the type doesn't match" do
133
+ a = subject.new('text', 'plain')
134
+ a.accept?('application/plain').must_equal false
135
+ b = subject.new('text', 'plain', q: 0.4)
136
+ b.accept?('application/json').must_equal false
137
+ end
138
+
139
+ it "not accepted if the subtype doesn't match" do
140
+ a = subject.new('text', 'html')
141
+ a.accept?('text/plain').must_equal false
142
+ b = subject.new('text', 'html', q: 0.6)
143
+ b.accept?('text/plain').must_equal false
144
+ end
145
+
146
+ it "not accepted if q is 0" do
147
+ a = subject.new('text', 'html', q: 0)
148
+ a.accept?('text/html').must_equal false
149
+ a.accept?('text/plain').must_equal false
150
+ a.accept?('application/plain').must_equal false
151
+ b = subject.new('text', '*', q: 0)
152
+ b.accept?('text/html').must_equal false
153
+ c = subject.new('*', q: 0)
154
+ c.accept?('text/html').must_equal false
155
+ end
156
+
157
+ # TODO: test *
158
+ it "not accepted if..." do
159
+ a = subject.new('text', 'plain')
160
+ a.accept?('*').must_equal false
161
+ end
162
+ end
163
+
164
+ describe "#reject?" do
165
+ describe "given q is 0" do
166
+ it "rejected if the type and subtype are the same" do
167
+ a = subject.new('text', 'html', q: 0)
168
+ a.reject?('text/html').must_equal true
169
+ end
170
+
171
+ it "rejected if the type is the same and the other subtype is *" do
172
+ a = subject.new('text', '*', q: 0)
173
+ a.reject?('text/html').must_equal true
174
+ end
175
+
176
+ it "rejected if the type and subtype are *" do
177
+ a = subject.new('*', q: 0)
178
+ a.reject?('text/html').must_equal true
179
+ end
180
+
181
+ it "not rejected if the type and subtype don't match" do
182
+ a = subject.new('text', 'html', q: 0)
183
+ a.reject?('application/json').must_equal false
184
+ end
185
+
186
+ it "not rejected if the type doesn't match" do
187
+ a = subject.new('text', 'plain', q: 0)
188
+ a.reject?('application/plain').must_equal false
189
+ end
190
+
191
+ it "not rejected if the subtype doesn't match" do
192
+ a = subject.new('text', 'html', q: 0)
193
+ a.reject?('text/plain').must_equal false
194
+ end
195
+
196
+ # TODO: test *
197
+ it "not rejected if..." do
198
+ a = subject.new('text', 'plain', q: 0)
199
+ a.reject?('*').must_equal false
200
+ end
201
+ end
202
+
203
+ it "not rejected if q > 0" do
204
+ a = subject.new('text', 'html', q: 0.001)
205
+ a.reject?('text/html').must_equal false
206
+ a.reject?('text/plain').must_equal false
207
+ a.reject?('application/plain').must_equal false
208
+ b = subject.new('text', '*', q: 0.9)
209
+ b.reject?('text/html').must_equal false
210
+ c = subject.new('*', q: 1)
211
+ c.reject?('text/html').must_equal false
212
+ end
213
+ end
102
214
  end
103
215
  end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,5 @@
1
- require "minitest/autorun"
2
- require "minitest/focus"
3
1
  require "codeclimate-test-reporter"
4
2
  require "simplecov"
5
- require "awesome_print"
6
- require "pry"
7
3
 
8
4
  CodeClimate::TestReporter.configure do |config|
9
5
  config.logger.level = Logger::WARN
@@ -14,6 +10,12 @@ SimpleCov.start do
14
10
  SimpleCov::Formatter::HTMLFormatter,
15
11
  CodeClimate::TestReporter::Formatter
16
12
  ]
13
+ add_filter 'spec/'
17
14
  end
18
15
 
16
+ require "minitest/autorun"
17
+ require "minitest/focus"
18
+ require "awesome_print"
19
+ require "pry"
20
+
19
21
  require_relative "../lib/accept_headers"
@@ -0,0 +1,12 @@
1
+ Name,Description,Reference,Notes
2
+ compress,"UNIX ""compress"" data format [Welch, T., ""A Technique
3
+ for High Performance Data Compression"", IEEE Computer 17(6), June 1984.]",[RFC7230],Section 4.2.1
4
+ deflate,"""deflate"" compressed data ([RFC1951])
5
+ inside the ""zlib"" data format ([RFC1950])",[RFC7230],Section 4.2.2
6
+ exi,W3C Efficient XML Interchange,"[J. Schneider and T. Kamiya, Eds. ""Efficient XML Interchange (EXI) Format 1.0"", W3C
7
+ Working Draft, 19 Sep 2008]",
8
+ gzip,GZIP file format [RFC1952],[RFC7230],Section 4.2.3
9
+ identity,"Reserved (synonym for ""no encoding"" in Accept-Encoding)",[RFC7231],Section 5.3.4
10
+ pack200-gzip,Network Transfer Format for Java Archives,[JSR 200: Network Transfer Format for Java][Kumar_Srinivasan][John_Rose],
11
+ x-compress,Deprecated (alias for compress),[RFC7230],Section 4.2.1
12
+ x-gzip,Deprecated (alias for gzip),[RFC7230],Section 4.2.3
@@ -6,7 +6,7 @@ Name,Template,Reference
6
6
  ac3,audio/ac3,[RFC4184]
7
7
  AMR,audio/AMR,[RFC4867]
8
8
  AMR-WB,audio/AMR-WB,[RFC4867]
9
- amr-wb+,amr-wb+,[RFC4352]
9
+ amr-wb+,audio/amr-wb+,[RFC4352]
10
10
  aptx,audio/aptx,[RFC7310]
11
11
  asc,audio/asc,[RFC6295]
12
12
  ATRAC-ADVANCED-LOSSLESS,audio/ATRAC-ADVANCED-LOSSLESS,[RFC5584]
File without changes
File without changes
File without changes
File without changes
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: accept_headers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jack Chu
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-15 00:00:00.000000000 Z
11
+ date: 2014-11-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -80,7 +80,7 @@ dependencies:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
- description: a ruby library that does content negotiation and parses and sorts http
83
+ description: A ruby library that does content negotiation and parses and sorts http
84
84
  accept headers. Adheres to RFC 2616.
85
85
  email:
86
86
  - kamuigt@gmail.com
@@ -115,14 +115,15 @@ files:
115
115
  - spec/media_type/negotiator_spec.rb
116
116
  - spec/media_type_spec.rb
117
117
  - spec/spec_helper.rb
118
- - spec/support/application.csv
119
- - spec/support/audio.csv
120
- - spec/support/image.csv
121
- - spec/support/message.csv
122
- - spec/support/model.csv
123
- - spec/support/multipart.csv
124
- - spec/support/text.csv
125
- - spec/support/video.csv
118
+ - spec/support/encodings/content-coding.csv
119
+ - spec/support/media_types/application.csv
120
+ - spec/support/media_types/audio.csv
121
+ - spec/support/media_types/image.csv
122
+ - spec/support/media_types/message.csv
123
+ - spec/support/media_types/model.csv
124
+ - spec/support/media_types/multipart.csv
125
+ - spec/support/media_types/text.csv
126
+ - spec/support/media_types/video.csv
126
127
  - wercker.yml
127
128
  homepage: ''
128
129
  licenses:
@@ -157,11 +158,12 @@ test_files:
157
158
  - spec/media_type/negotiator_spec.rb
158
159
  - spec/media_type_spec.rb
159
160
  - spec/spec_helper.rb
160
- - spec/support/application.csv
161
- - spec/support/audio.csv
162
- - spec/support/image.csv
163
- - spec/support/message.csv
164
- - spec/support/model.csv
165
- - spec/support/multipart.csv
166
- - spec/support/text.csv
167
- - spec/support/video.csv
161
+ - spec/support/encodings/content-coding.csv
162
+ - spec/support/media_types/application.csv
163
+ - spec/support/media_types/audio.csv
164
+ - spec/support/media_types/image.csv
165
+ - spec/support/media_types/message.csv
166
+ - spec/support/media_types/model.csv
167
+ - spec/support/media_types/multipart.csv
168
+ - spec/support/media_types/text.csv
169
+ - spec/support/media_types/video.csv