accept_headers 0.0.1 → 0.0.2
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 +4 -4
- data/CHANGELOG.md +5 -1
- data/Gemfile +2 -2
- data/README.md +86 -31
- data/accept_headers.gemspec +2 -2
- data/lib/accept_headers.rb +4 -0
- data/lib/accept_headers/acceptable.rb +4 -28
- data/lib/accept_headers/charset.rb +7 -15
- data/lib/accept_headers/charset/negotiator.rb +27 -0
- data/lib/accept_headers/encoding.rb +7 -15
- data/lib/accept_headers/encoding/negotiator.rb +27 -0
- data/lib/accept_headers/language.rb +9 -25
- data/lib/accept_headers/language/negotiator.rb +37 -0
- data/lib/accept_headers/media_type.rb +9 -38
- data/lib/accept_headers/media_type/negotiator.rb +50 -0
- data/lib/accept_headers/negotiatable.rb +54 -0
- data/lib/accept_headers/version.rb +1 -1
- data/spec/charset/negotiator_spec.rb +73 -0
- data/spec/charset_spec.rb +4 -58
- data/spec/encoding/negotiator_spec.rb +73 -0
- data/spec/encoding_spec.rb +4 -58
- data/spec/language/negotiator_spec.rb +78 -0
- data/spec/language_spec.rb +4 -63
- data/spec/media_type/negotiator_spec.rb +92 -0
- data/spec/media_type_spec.rb +4 -78
- data/spec/spec_helper.rb +10 -12
- metadata +19 -5
@@ -0,0 +1,78 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
module AcceptHeaders
|
4
|
+
class Language
|
5
|
+
describe Negotiator do
|
6
|
+
subject do
|
7
|
+
AcceptHeaders::Language::Negotiator
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "parsing an accept header" do
|
11
|
+
it "returns a sorted array of media primary tags" do
|
12
|
+
subject.new("en-*;q=0.2, en-us").list.must_equal [
|
13
|
+
Language.new('en', 'us'),
|
14
|
+
Language.new('en', '*', q: 0.2)
|
15
|
+
]
|
16
|
+
|
17
|
+
subject.new("en-*, en-us, *;q=0.8").list.must_equal [
|
18
|
+
Language.new('en', 'us'),
|
19
|
+
Language.new('en', '*'),
|
20
|
+
Language.new('*', '*', q: 0.8)
|
21
|
+
]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "sets media primary tag to */* when the accept header is empty" do
|
25
|
+
subject.new('').list.must_equal [
|
26
|
+
Language.new('*', '*')
|
27
|
+
]
|
28
|
+
end
|
29
|
+
|
30
|
+
it "sets media primary tag to */* when the primary tag is only *" do
|
31
|
+
subject.new('*').list.must_equal [
|
32
|
+
Language.new('*', '*')
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "defaults q to 1 if it's not explicitly specified" do
|
37
|
+
subject.new("en-us").list.must_equal [
|
38
|
+
Language.new('en', 'plain', q: 1.0)
|
39
|
+
]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "strips whitespace from between media primary tags" do
|
43
|
+
subject.new("\ten-us\r,\nen-gb\s").list.must_equal [
|
44
|
+
Language.new('en', 'us'),
|
45
|
+
Language.new('en', 'gb')
|
46
|
+
]
|
47
|
+
end
|
48
|
+
|
49
|
+
it "strips whitespace around q" do
|
50
|
+
subject.new("en-us;\tq\r=\n1, en-gb").list.must_equal [
|
51
|
+
Language.new('en', 'us'),
|
52
|
+
Language.new('en', 'gb')
|
53
|
+
]
|
54
|
+
end
|
55
|
+
|
56
|
+
it "has a q value of 0.001 when parsed q is invalid" do
|
57
|
+
subject.new("en-us;q=x").list.must_equal [
|
58
|
+
Language.new('en', 'plain', q: 0.001)
|
59
|
+
]
|
60
|
+
end
|
61
|
+
|
62
|
+
it "skips invalid media primary tags" do
|
63
|
+
subject.new("en-us, en-us-omg;q=0.9").list.must_equal [
|
64
|
+
Language.new('en', 'us', q: 1)
|
65
|
+
]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe "negotiate supported languages" do
|
70
|
+
it "returns a best matching language" do
|
71
|
+
match = Language.new('en', 'us')
|
72
|
+
n = subject.new('en-*, en-us, *;q=0.8')
|
73
|
+
n.negotiate('en-us').must_equal match
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/spec/language_spec.rb
CHANGED
@@ -51,11 +51,11 @@ module AcceptHeaders
|
|
51
51
|
subject.new('en', 'us', q: '1')
|
52
52
|
end
|
53
53
|
|
54
|
-
it "raises an
|
54
|
+
it "raises an InvalidQError unless q value is between 0 and 1" do
|
55
55
|
[-1.0, -0.1, 1.1].each do |q|
|
56
56
|
e = -> do
|
57
57
|
subject.new('en', 'us', q: q)
|
58
|
-
end.must_raise Language::
|
58
|
+
end.must_raise Language::InvalidQError
|
59
59
|
|
60
60
|
e.message.must_equal "q must be between 0 and 1"
|
61
61
|
end
|
@@ -64,10 +64,10 @@ module AcceptHeaders
|
|
64
64
|
subject.new('en', 'gb', q: 0)
|
65
65
|
end
|
66
66
|
|
67
|
-
it "raises an
|
67
|
+
it "raises an InvalidQError if q has more than a precision of 3" do
|
68
68
|
e = -> do
|
69
69
|
subject.new('en', 'us', q: 0.1234)
|
70
|
-
end.must_raise Language::
|
70
|
+
end.must_raise Language::InvalidQError
|
71
71
|
|
72
72
|
e.message.must_equal "q must be at most 3 decimal places"
|
73
73
|
|
@@ -86,64 +86,5 @@ module AcceptHeaders
|
|
86
86
|
s = subject.new('en', 'us', q: 0.9).to_s
|
87
87
|
s.must_equal "en-us;q=0.9"
|
88
88
|
end
|
89
|
-
|
90
|
-
describe "parsing an accept header" do
|
91
|
-
it "returns a sorted array of media primary tags" do
|
92
|
-
subject.parse("en-*;q=0.2, en-us").must_equal [
|
93
|
-
Language.new('en', 'us'),
|
94
|
-
Language.new('en', '*', q: 0.2)
|
95
|
-
]
|
96
|
-
|
97
|
-
subject.parse("en-*, en-us, *;q=0.8").must_equal [
|
98
|
-
Language.new('en', 'us'),
|
99
|
-
Language.new('en', '*'),
|
100
|
-
Language.new('*', '*', q: 0.8)
|
101
|
-
]
|
102
|
-
end
|
103
|
-
|
104
|
-
it "sets media primary tag to */* when the accept header is empty" do
|
105
|
-
subject.parse('').must_equal [
|
106
|
-
Language.new('*', '*')
|
107
|
-
]
|
108
|
-
end
|
109
|
-
|
110
|
-
it "sets media primary tag to */* when the primary tag is only *" do
|
111
|
-
subject.parse('*').must_equal [
|
112
|
-
Language.new('*', '*')
|
113
|
-
]
|
114
|
-
end
|
115
|
-
|
116
|
-
it "defaults q to 1 if it's not explicitly specified" do
|
117
|
-
subject.parse("en-us").must_equal [
|
118
|
-
Language.new('en', 'plain', q: 1.0)
|
119
|
-
]
|
120
|
-
end
|
121
|
-
|
122
|
-
it "strips whitespace from between media primary tags" do
|
123
|
-
subject.parse("\ten-us\r,\nen-gb\s").must_equal [
|
124
|
-
Language.new('en', 'us'),
|
125
|
-
Language.new('en', 'gb')
|
126
|
-
]
|
127
|
-
end
|
128
|
-
|
129
|
-
it "strips whitespace around q" do
|
130
|
-
subject.parse("en-us;\tq\r=\n1, en-gb").must_equal [
|
131
|
-
Language.new('en', 'us'),
|
132
|
-
Language.new('en', 'gb')
|
133
|
-
]
|
134
|
-
end
|
135
|
-
|
136
|
-
it "has a q value of 0.001 when parsed q is invalid" do
|
137
|
-
subject.parse("en-us;q=x").must_equal [
|
138
|
-
Language.new('en', 'plain', q: 0.001)
|
139
|
-
]
|
140
|
-
end
|
141
|
-
|
142
|
-
it "skips invalid media primary tags" do
|
143
|
-
subject.parse("en-us, en-us-omg;q=0.9").must_equal [
|
144
|
-
Language.new('en', 'us', q: 1)
|
145
|
-
]
|
146
|
-
end
|
147
|
-
end
|
148
89
|
end
|
149
90
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require_relative "../spec_helper"
|
2
|
+
|
3
|
+
module AcceptHeaders
|
4
|
+
class MediaType
|
5
|
+
describe Negotiator do
|
6
|
+
subject do
|
7
|
+
AcceptHeaders::MediaType::Negotiator
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "parsing an accept header" do
|
11
|
+
it "returns a sorted array of media types" do
|
12
|
+
subject.new("audio/*; q=0.2, audio/basic").list.must_equal [
|
13
|
+
MediaType.new('audio', 'basic'),
|
14
|
+
MediaType.new('audio', '*', q: 0.2)
|
15
|
+
]
|
16
|
+
subject.new("text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c").list.must_equal [
|
17
|
+
MediaType.new('text', 'html'),
|
18
|
+
MediaType.new('text', 'x-c'),
|
19
|
+
MediaType.new('text', 'x-dvi', q: 0.8),
|
20
|
+
MediaType.new('text', 'plain', q: 0.5)
|
21
|
+
]
|
22
|
+
|
23
|
+
subject.new("text/*, text/html, text/html;level=1, */*").list.must_equal [
|
24
|
+
MediaType.new('text', 'html', params: { 'level' => '1' }),
|
25
|
+
MediaType.new('text', 'html'),
|
26
|
+
MediaType.new('text', '*'),
|
27
|
+
MediaType.new('*', '*')
|
28
|
+
]
|
29
|
+
|
30
|
+
subject.new("text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5").list.must_equal [
|
31
|
+
MediaType.new('text', 'html', params: { 'level' => '1' }),
|
32
|
+
MediaType.new('text', 'html', q: 0.7),
|
33
|
+
MediaType.new('*', '*', q: 0.5),
|
34
|
+
MediaType.new('text', 'html', q: 0.4, params: { 'level' => '2' }),
|
35
|
+
MediaType.new('text', '*', q: 0.3)
|
36
|
+
]
|
37
|
+
end
|
38
|
+
|
39
|
+
it "sets media type to */* when the accept header is empty" do
|
40
|
+
subject.new('').list.must_equal [
|
41
|
+
MediaType.new('*', '*')
|
42
|
+
]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "sets media type to */* when the type is only *" do
|
46
|
+
subject.new('*').list.must_equal [
|
47
|
+
MediaType.new('*', '*')
|
48
|
+
]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "defaults q to 1 if it's not explicitly specified" do
|
52
|
+
subject.new("text/plain").list.must_equal [
|
53
|
+
MediaType.new('text', 'plain', q: 1.0)
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
it "strips whitespace from between media types" do
|
58
|
+
subject.new("\ttext/plain\r,\napplication/json\s").list.must_equal [
|
59
|
+
MediaType.new('text', 'plain'),
|
60
|
+
MediaType.new('application', 'json')
|
61
|
+
]
|
62
|
+
end
|
63
|
+
|
64
|
+
it "strips whitespace around q and params" do
|
65
|
+
subject.new("text/plain;\tq\r=\n1, application/json;q=0.8;\slevel\t\t=\r\n1\n").list.must_equal [
|
66
|
+
MediaType.new('text', 'plain'),
|
67
|
+
MediaType.new('application', 'json', q: 0.8, params: { "level" => "1" })
|
68
|
+
]
|
69
|
+
end
|
70
|
+
|
71
|
+
it "has a q value of 0.001 when parsed q is invalid" do
|
72
|
+
subject.new("text/plain;q=x").list.must_equal [
|
73
|
+
MediaType.new('text', 'plain', q: 0.001)
|
74
|
+
]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "skips invalid media types" do
|
78
|
+
subject.new("text/html, text/plain/omg;q=0.9").list.must_equal [
|
79
|
+
MediaType.new('text', 'html', q: 1)
|
80
|
+
]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "negotiate supported media types" do
|
85
|
+
it "returns a best matching media type" do
|
86
|
+
n = subject.new("text/*, text/html, text/html;level=1, */*")
|
87
|
+
n.negotiate("text/html").must_equal MediaType.new('text', 'html', params: { 'level' => '1' })
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/spec/media_type_spec.rb
CHANGED
@@ -59,11 +59,11 @@ module AcceptHeaders
|
|
59
59
|
subject.new('text', 'html', q: '1')
|
60
60
|
end
|
61
61
|
|
62
|
-
it "raises an
|
62
|
+
it "raises an InvalidQError unless q value is between 0 and 1" do
|
63
63
|
[-1.0, -0.1, 1.1].each do |q|
|
64
64
|
e = -> do
|
65
65
|
subject.new('text', 'html', q: q)
|
66
|
-
end.must_raise MediaType::
|
66
|
+
end.must_raise MediaType::InvalidQError
|
67
67
|
|
68
68
|
e.message.must_equal "q must be between 0 and 1"
|
69
69
|
end
|
@@ -72,10 +72,10 @@ module AcceptHeaders
|
|
72
72
|
subject.new('text', 'html', q: 0)
|
73
73
|
end
|
74
74
|
|
75
|
-
it "raises an
|
75
|
+
it "raises an InvalidQError if q has more than a precision of 3" do
|
76
76
|
e = -> do
|
77
77
|
subject.new('text', 'html', q: 0.1234)
|
78
|
-
end.must_raise MediaType::
|
78
|
+
end.must_raise MediaType::InvalidQError
|
79
79
|
|
80
80
|
e.message.must_equal "q must be at most 3 decimal places"
|
81
81
|
|
@@ -95,79 +95,5 @@ module AcceptHeaders
|
|
95
95
|
s = subject.new('text', 'html', q: 0.9, params: { 'level' => '1' }).to_s
|
96
96
|
s.must_equal "text/html;q=0.9;level=1"
|
97
97
|
end
|
98
|
-
|
99
|
-
describe "parsing an accept header" do
|
100
|
-
it "returns a sorted array of media types" do
|
101
|
-
subject.parse("audio/*; q=0.2, audio/basic").must_equal [
|
102
|
-
MediaType.new('audio', 'basic'),
|
103
|
-
MediaType.new('audio', '*', q: 0.2)
|
104
|
-
]
|
105
|
-
subject.parse("text/plain; q=0.5, text/html, text/x-dvi; q=0.8, text/x-c").must_equal [
|
106
|
-
MediaType.new('text', 'html'),
|
107
|
-
MediaType.new('text', 'x-c'),
|
108
|
-
MediaType.new('text', 'x-dvi', q: 0.8),
|
109
|
-
MediaType.new('text', 'plain', q: 0.5)
|
110
|
-
]
|
111
|
-
|
112
|
-
subject.parse("text/*, text/html, text/html;level=1, */*").must_equal [
|
113
|
-
MediaType.new('text', 'html', params: { 'level' => '1' }),
|
114
|
-
MediaType.new('text', 'html'),
|
115
|
-
MediaType.new('text', '*'),
|
116
|
-
MediaType.new('*', '*')
|
117
|
-
]
|
118
|
-
|
119
|
-
subject.parse("text/*;q=0.3, text/html;q=0.7, text/html;level=1, text/html;level=2;q=0.4, */*;q=0.5").must_equal [
|
120
|
-
MediaType.new('text', 'html', params: { 'level' => '1' }),
|
121
|
-
MediaType.new('text', 'html', q: 0.7),
|
122
|
-
MediaType.new('*', '*', q: 0.5),
|
123
|
-
MediaType.new('text', 'html', q: 0.4, params: { 'level' => '2' }),
|
124
|
-
MediaType.new('text', '*', q: 0.3)
|
125
|
-
]
|
126
|
-
end
|
127
|
-
|
128
|
-
it "sets media type to */* when the accept header is empty" do
|
129
|
-
subject.parse('').must_equal [
|
130
|
-
MediaType.new('*', '*')
|
131
|
-
]
|
132
|
-
end
|
133
|
-
|
134
|
-
it "sets media type to */* when the type is only *" do
|
135
|
-
subject.parse('*').must_equal [
|
136
|
-
MediaType.new('*', '*')
|
137
|
-
]
|
138
|
-
end
|
139
|
-
|
140
|
-
it "defaults q to 1 if it's not explicitly specified" do
|
141
|
-
subject.parse("text/plain").must_equal [
|
142
|
-
MediaType.new('text', 'plain', q: 1.0)
|
143
|
-
]
|
144
|
-
end
|
145
|
-
|
146
|
-
it "strips whitespace from between media types" do
|
147
|
-
subject.parse("\ttext/plain\r,\napplication/json\s").must_equal [
|
148
|
-
MediaType.new('text', 'plain'),
|
149
|
-
MediaType.new('application', 'json')
|
150
|
-
]
|
151
|
-
end
|
152
|
-
|
153
|
-
it "strips whitespace around q and params" do
|
154
|
-
subject.parse("text/plain;\tq\r=\n1, application/json;q=0.8;\slevel\t\t=\r\n1\n").must_equal [
|
155
|
-
MediaType.new('text', 'plain'),
|
156
|
-
MediaType.new('application', 'json', q: 0.8, params: { "level" => "1" })
|
157
|
-
]
|
158
|
-
end
|
159
|
-
|
160
|
-
it "has a q value of 0.001 when parsed q is invalid" do
|
161
|
-
subject.parse("text/plain;q=x").must_equal [
|
162
|
-
MediaType.new('text', 'plain', q: 0.001)
|
163
|
-
]
|
164
|
-
end
|
165
|
-
|
166
|
-
it "skips invalid media types" do
|
167
|
-
subject.parse("text/html, text/plain/omg;q=0.9").must_equal [
|
168
|
-
MediaType.new('text', 'html', q: 1)
|
169
|
-
]
|
170
|
-
end
|
171
|
-
end
|
172
98
|
end
|
173
99
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,21 +1,19 @@
|
|
1
1
|
require "minitest/autorun"
|
2
2
|
require "minitest/focus"
|
3
|
+
require "codeclimate-test-reporter"
|
4
|
+
require "simplecov"
|
3
5
|
require "awesome_print"
|
4
6
|
require "pry"
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
end
|
8
|
+
CodeClimate::TestReporter.configure do |config|
|
9
|
+
config.logger.level = Logger::WARN
|
10
|
+
end
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
elsif defined?(SimpleCov)
|
18
|
-
SimpleCov.start
|
12
|
+
SimpleCov.start do
|
13
|
+
formatter SimpleCov::Formatter::MultiFormatter[
|
14
|
+
SimpleCov::Formatter::HTMLFormatter,
|
15
|
+
CodeClimate::TestReporter::Formatter
|
16
|
+
]
|
19
17
|
end
|
20
18
|
|
21
19
|
require_relative "../lib/accept_headers"
|
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
|
+
version: 0.0.2
|
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-
|
11
|
+
date: 2014-11-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -80,8 +80,8 @@ dependencies:
|
|
80
80
|
- - '>='
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
-
description:
|
84
|
-
RFC 2616.
|
83
|
+
description: a ruby library that does content negotiation and parses and sorts http
|
84
|
+
accept headers. Adheres to RFC 2616.
|
85
85
|
email:
|
86
86
|
- kamuigt@gmail.com
|
87
87
|
executables: []
|
@@ -100,13 +100,22 @@ files:
|
|
100
100
|
- lib/accept_headers.rb
|
101
101
|
- lib/accept_headers/acceptable.rb
|
102
102
|
- lib/accept_headers/charset.rb
|
103
|
+
- lib/accept_headers/charset/negotiator.rb
|
103
104
|
- lib/accept_headers/encoding.rb
|
105
|
+
- lib/accept_headers/encoding/negotiator.rb
|
104
106
|
- lib/accept_headers/language.rb
|
107
|
+
- lib/accept_headers/language/negotiator.rb
|
105
108
|
- lib/accept_headers/media_type.rb
|
109
|
+
- lib/accept_headers/media_type/negotiator.rb
|
110
|
+
- lib/accept_headers/negotiatable.rb
|
106
111
|
- lib/accept_headers/version.rb
|
112
|
+
- spec/charset/negotiator_spec.rb
|
107
113
|
- spec/charset_spec.rb
|
114
|
+
- spec/encoding/negotiator_spec.rb
|
108
115
|
- spec/encoding_spec.rb
|
116
|
+
- spec/language/negotiator_spec.rb
|
109
117
|
- spec/language_spec.rb
|
118
|
+
- spec/media_type/negotiator_spec.rb
|
110
119
|
- spec/media_type_spec.rb
|
111
120
|
- spec/spec_helper.rb
|
112
121
|
- wercker.yml
|
@@ -133,10 +142,15 @@ rubyforge_project:
|
|
133
142
|
rubygems_version: 2.4.3
|
134
143
|
signing_key:
|
135
144
|
specification_version: 4
|
136
|
-
summary: A ruby library that parses and sorts http accept
|
145
|
+
summary: A ruby library that does content negotiation and parses and sorts http accept
|
146
|
+
headers.
|
137
147
|
test_files:
|
148
|
+
- spec/charset/negotiator_spec.rb
|
138
149
|
- spec/charset_spec.rb
|
150
|
+
- spec/encoding/negotiator_spec.rb
|
139
151
|
- spec/encoding_spec.rb
|
152
|
+
- spec/language/negotiator_spec.rb
|
140
153
|
- spec/language_spec.rb
|
154
|
+
- spec/media_type/negotiator_spec.rb
|
141
155
|
- spec/media_type_spec.rb
|
142
156
|
- spec/spec_helper.rb
|