accept_headers 0.0.4 → 0.0.5

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
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