rack-accept_headers 0.5.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.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +15 -0
- data/CHANGELOG.md +35 -0
- data/Gemfile +4 -0
- data/Guardfile +14 -0
- data/LICENSE.txt +22 -0
- data/README.md +198 -0
- data/Rakefile +10 -0
- data/lib/rack/accept_headers/charset.rb +36 -0
- data/lib/rack/accept_headers/context.rb +67 -0
- data/lib/rack/accept_headers/encoding.rb +36 -0
- data/lib/rack/accept_headers/header.rb +149 -0
- data/lib/rack/accept_headers/language.rb +36 -0
- data/lib/rack/accept_headers/media_type.rb +73 -0
- data/lib/rack/accept_headers/request.rb +90 -0
- data/lib/rack/accept_headers/response.rb +18 -0
- data/lib/rack/accept_headers/version.rb +5 -0
- data/lib/rack/accept_headers.rb +16 -0
- data/rack-accept_headers.gemspec +27 -0
- data/test/charset_test.rb +43 -0
- data/test/context_test.rb +57 -0
- data/test/encoding_test.rb +29 -0
- data/test/header_test.rb +69 -0
- data/test/language_test.rb +47 -0
- data/test/media_type_test.rb +80 -0
- data/test/request_test.rb +60 -0
- data/test/test_helper.rb +26 -0
- metadata +166 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
module Rack::AcceptHeaders
|
2
|
+
# Represents an HTTP Accept header according to the HTTP 1.1 specification,
|
3
|
+
# and provides several convenience methods for determining acceptable media
|
4
|
+
# types.
|
5
|
+
#
|
6
|
+
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
|
7
|
+
class MediaType
|
8
|
+
include Header
|
9
|
+
|
10
|
+
attr_accessor :extensions
|
11
|
+
|
12
|
+
# The name of this header.
|
13
|
+
def name
|
14
|
+
'Accept'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Determines the quality factor (qvalue) of the given +media_type+.
|
18
|
+
def qvalue(media_type)
|
19
|
+
return 1 if @qvalues.empty?
|
20
|
+
m = matches(media_type)
|
21
|
+
return 0 if m.empty?
|
22
|
+
normalize_qvalue(@qvalues[m.first])
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns an array of media types from this header that match the given
|
26
|
+
# +media_type+, ordered by precedence.
|
27
|
+
def matches(media_type)
|
28
|
+
type, subtype, params = parse_media_type(media_type)
|
29
|
+
values.select {|v|
|
30
|
+
if v == media_type || v == '*/*'
|
31
|
+
true
|
32
|
+
else
|
33
|
+
t, s, p = parse_media_type(v)
|
34
|
+
t == type && (s == '*' || s == subtype) && (p == '' || params_match?(params, p))
|
35
|
+
end
|
36
|
+
}.sort_by {|v|
|
37
|
+
# Most specific gets precedence.
|
38
|
+
v.length
|
39
|
+
}.reverse
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns a params hash for the media type that matches
|
43
|
+
def params(media_type)
|
44
|
+
return {} unless media_type
|
45
|
+
key = matches(media_type).first
|
46
|
+
@extensions[key] || {}
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def initialize(header)
|
52
|
+
@extensions = {}
|
53
|
+
@qvalues = {}
|
54
|
+
|
55
|
+
header.to_s.split(',').each do |part|
|
56
|
+
type, subtype, raw_params = parse_media_type(part)
|
57
|
+
raise InvalidHeader, "Invalid header value: #{part.inspect}" if !type || !subtype
|
58
|
+
media_type = "#{type}/#{subtype}"
|
59
|
+
params = parse_range_params(raw_params)
|
60
|
+
@extensions[media_type] = params
|
61
|
+
@qvalues[media_type] = normalize_qvalue(params['q']).to_f
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns true if all parameters and values in +match+ are also present in
|
66
|
+
# +params+.
|
67
|
+
def params_match?(params, match)
|
68
|
+
return true if params == match
|
69
|
+
parsed = parse_range_params(params)
|
70
|
+
parsed == parsed.merge(parse_range_params(match))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'rack/request'
|
2
|
+
|
3
|
+
module Rack::AcceptHeaders
|
4
|
+
# A container class for convenience methods when Rack::AcceptHeaders is used on the
|
5
|
+
# request level as Rack middleware. Instances of this class also manage a
|
6
|
+
# lightweight cache of various header instances to speed up execution.
|
7
|
+
class Request < Rack::Request
|
8
|
+
attr_reader :env
|
9
|
+
|
10
|
+
def initialize(env)
|
11
|
+
@env = env
|
12
|
+
end
|
13
|
+
|
14
|
+
# Provides access to the Rack::AcceptHeaders::MediaType instance for this request.
|
15
|
+
def media_type
|
16
|
+
@media_type ||= MediaType.new(env['HTTP_ACCEPT'])
|
17
|
+
end
|
18
|
+
|
19
|
+
# Provides access to the Rack::AcceptHeaders::Charset instance for this request.
|
20
|
+
def charset
|
21
|
+
@charset ||= Charset.new(env['HTTP_ACCEPT_CHARSET'])
|
22
|
+
end
|
23
|
+
|
24
|
+
# Provides access to the Rack::AcceptHeaders::Encoding instance for this request.
|
25
|
+
def encoding
|
26
|
+
@encoding ||= Encoding.new(env['HTTP_ACCEPT_ENCODING'])
|
27
|
+
end
|
28
|
+
|
29
|
+
# Provides access to the Rack::AcceptHeaders::Language instance for this request.
|
30
|
+
def language
|
31
|
+
@language ||= Language.new(env['HTTP_ACCEPT_LANGUAGE'])
|
32
|
+
end
|
33
|
+
|
34
|
+
# Returns true if the +Accept+ request header indicates the given media
|
35
|
+
# type is acceptable, false otherwise.
|
36
|
+
def media_type?(value)
|
37
|
+
media_type.accept?(value)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns true if the +Accept-Charset+ request header indicates the given
|
41
|
+
# character set is acceptable, false otherwise.
|
42
|
+
def charset?(value)
|
43
|
+
charset.accept?(value)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns true if the +Accept-Encoding+ request header indicates the given
|
47
|
+
# encoding is acceptable, false otherwise.
|
48
|
+
def encoding?(value)
|
49
|
+
encoding.accept?(value)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns true if the +Accept-Language+ request header indicates the given
|
53
|
+
# language is acceptable, false otherwise.
|
54
|
+
def language?(value)
|
55
|
+
language.accept?(value)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Determines the best media type to use in a response from the given media
|
59
|
+
# types, if any is acceptable. For more information on how this value is
|
60
|
+
# determined, see the documentation for
|
61
|
+
# Rack::AcceptHeaders::Header::PublicInstanceMethods#sort.
|
62
|
+
def best_media_type(values)
|
63
|
+
media_type.best_of(values)
|
64
|
+
end
|
65
|
+
|
66
|
+
# Determines the best character set to use in a response from the given
|
67
|
+
# character sets, if any is acceptable. For more information on how this
|
68
|
+
# value is determined, see the documentation for
|
69
|
+
# Rack::AcceptHeaders::Header::PublicInstanceMethods#sort.
|
70
|
+
def best_charset(values)
|
71
|
+
charset.best_of(values)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Determines the best encoding to use in a response from the given
|
75
|
+
# encodings, if any is acceptable. For more information on how this value
|
76
|
+
# is determined, see the documentation for
|
77
|
+
# Rack::AcceptHeaders::Header::PublicInstanceMethods#sort.
|
78
|
+
def best_encoding(values)
|
79
|
+
encoding.best_of(values)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Determines the best language to use in a response from the given
|
83
|
+
# languages, if any is acceptable. For more information on how this value
|
84
|
+
# is determined, see the documentation for
|
85
|
+
# Rack::AcceptHeaders::Header::PublicInstanceMethods#sort.
|
86
|
+
def best_language(values)
|
87
|
+
language.best_of(values)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rack/response'
|
2
|
+
|
3
|
+
module Rack::AcceptHeaders
|
4
|
+
# The base class for responses issued by Rack::AcceptHeaders.
|
5
|
+
class Response < Rack::Response
|
6
|
+
# Marks this response as being unacceptable and clears the response body.
|
7
|
+
#
|
8
|
+
# Note: The HTTP spec advises servers to respond with an "entity" that
|
9
|
+
# describes acceptable parameters, but it fails to go into detail about its
|
10
|
+
# implementation. Thus, it is up to the user of this library to create such
|
11
|
+
# an entity if one is desired.
|
12
|
+
def not_acceptable!
|
13
|
+
self.status = 406
|
14
|
+
self.body = []
|
15
|
+
header['Content-Length'] = '0'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rack'
|
2
|
+
require 'rack/accept_headers/header'
|
3
|
+
require 'rack/accept_headers/charset'
|
4
|
+
require 'rack/accept_headers/context'
|
5
|
+
require 'rack/accept_headers/encoding'
|
6
|
+
require 'rack/accept_headers/language'
|
7
|
+
require 'rack/accept_headers/media_type'
|
8
|
+
require 'rack/accept_headers/request'
|
9
|
+
require 'rack/accept_headers/response'
|
10
|
+
|
11
|
+
module Rack::AcceptHeaders
|
12
|
+
# Enables Rack::AcceptHeaders to be used as a Rack middleware.
|
13
|
+
def self.new(app, &block)
|
14
|
+
Context.new(app, &block)
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
lib = File.expand_path('../lib', __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require 'rack/accept_headers/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "rack-accept_headers"
|
7
|
+
spec.version = Rack::AcceptHeaders::VERSION
|
8
|
+
spec.authors = ["Jack Chu", "Michael Jackson"]
|
9
|
+
spec.email = ["kamuigt@gmail.com", "mjijackson@gmail.com"]
|
10
|
+
spec.summary = %q{HTTP Accept* for Ruby/Rack}
|
11
|
+
spec.description = %q{HTTP Accept, Accept-Charset, Accept-Encoding, and Accept-Language for Ruby/Rack}
|
12
|
+
spec.homepage = "https://github.com/kamui/rack-accept_headers"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency 'rack'
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler'
|
23
|
+
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'minitest'
|
25
|
+
spec.add_development_dependency 'guard'
|
26
|
+
spec.add_development_dependency 'guard-minitest'
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class CharsetTest < Minitest::Test
|
4
|
+
C = Rack::AcceptHeaders::Charset
|
5
|
+
|
6
|
+
def test_qvalue
|
7
|
+
c = C.new('')
|
8
|
+
assert_equal(0, c.qvalue('unicode-1-1'))
|
9
|
+
assert_equal(1, c.qvalue('iso-8859-1'))
|
10
|
+
|
11
|
+
c = C.new('unicode-1-1')
|
12
|
+
assert_equal(1, c.qvalue('unicode-1-1'))
|
13
|
+
assert_equal(0, c.qvalue('iso-8859-5'))
|
14
|
+
assert_equal(1, c.qvalue('iso-8859-1'))
|
15
|
+
|
16
|
+
c = C.new('unicode-1-1, *;q=0.5')
|
17
|
+
assert_equal(1, c.qvalue('unicode-1-1'))
|
18
|
+
assert_equal(0.5, c.qvalue('iso-8859-5'))
|
19
|
+
assert_equal(0.5, c.qvalue('iso-8859-1'))
|
20
|
+
|
21
|
+
c = C.new('iso-8859-1;q=0, *;q=0.5')
|
22
|
+
assert_equal(0.5, c.qvalue('iso-8859-5'))
|
23
|
+
assert_equal(0, c.qvalue('iso-8859-1'))
|
24
|
+
|
25
|
+
c = C.new('*;q=0')
|
26
|
+
assert_equal(0, c.qvalue('iso-8859-1'))
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_matches
|
30
|
+
c = C.new('iso-8859-1, iso-8859-5, *')
|
31
|
+
assert_equal(%w{*}, c.matches(''))
|
32
|
+
assert_equal(%w{iso-8859-1 *}, c.matches('iso-8859-1'))
|
33
|
+
assert_equal(%w{*}, c.matches('unicode-1-1'))
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_best_of
|
37
|
+
c = C.new('iso-8859-5, unicode-1-1;q=0.8')
|
38
|
+
assert_equal('iso-8859-5', c.best_of(%w< iso-8859-5 unicode-1-1 >))
|
39
|
+
assert_equal('iso-8859-5', c.best_of(%w< iso-8859-5 utf-8 >))
|
40
|
+
assert_equal('iso-8859-1', c.best_of(%w< iso-8859-1 utf-8 >))
|
41
|
+
assert_equal(nil, c.best_of(%w< utf-8 >))
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class ContextTest < Minitest::Test
|
4
|
+
def media_types; Proc.new {|c| c.media_types = %w< text/html > } end
|
5
|
+
def charsets; Proc.new {|c| c.charsets = %w< iso-8859-5 > } end
|
6
|
+
def encodings; Proc.new {|c| c.encodings = %w< gzip > } end
|
7
|
+
def languages; Proc.new {|c| c.languages = %w< en > } end
|
8
|
+
|
9
|
+
def test_empty
|
10
|
+
request
|
11
|
+
assert_equal(200, status)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_media_types
|
15
|
+
request('HTTP_ACCEPT' => 'text/html')
|
16
|
+
assert_equal(200, status)
|
17
|
+
|
18
|
+
request('HTTP_ACCEPT' => 'text/html', &media_types)
|
19
|
+
assert_equal(200, status)
|
20
|
+
|
21
|
+
request('HTTP_ACCEPT' => 'text/plain', &media_types)
|
22
|
+
assert_equal(406, status)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_charsets
|
26
|
+
request('HTTP_ACCEPT_CHARSET' => 'iso-8859-5')
|
27
|
+
assert_equal(200, status)
|
28
|
+
|
29
|
+
request('HTTP_ACCEPT_CHARSET' => 'iso-8859-5', &charsets)
|
30
|
+
assert_equal(200, status)
|
31
|
+
|
32
|
+
request('HTTP_ACCEPT_CHARSET' => 'unicode-1-1', &charsets)
|
33
|
+
assert_equal(406, status)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_encodings
|
37
|
+
request('HTTP_ACCEPT_ENCODING' => 'gzip')
|
38
|
+
assert_equal(200, status)
|
39
|
+
|
40
|
+
request('HTTP_ACCEPT_ENCODING' => 'gzip', &encodings)
|
41
|
+
assert_equal(200, status)
|
42
|
+
|
43
|
+
request('HTTP_ACCEPT_ENCODING' => 'compress', &encodings)
|
44
|
+
assert_equal(406, status)
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_languages
|
48
|
+
request('HTTP_ACCEPT_LANGUAGE' => 'en')
|
49
|
+
assert_equal(200, status)
|
50
|
+
|
51
|
+
request('HTTP_ACCEPT_LANGUAGE' => 'en', &languages)
|
52
|
+
assert_equal(200, status)
|
53
|
+
|
54
|
+
request('HTTP_ACCEPT_LANGUAGE' => 'jp', &languages)
|
55
|
+
assert_equal(406, status)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class EncodingTest < Minitest::Test
|
4
|
+
E = Rack::AcceptHeaders::Encoding
|
5
|
+
|
6
|
+
def test_qvalue
|
7
|
+
e = E.new('')
|
8
|
+
assert_equal(0, e.qvalue('gzip'))
|
9
|
+
assert_equal(1, e.qvalue('identity'))
|
10
|
+
|
11
|
+
e = E.new('gzip, *;q=0.5')
|
12
|
+
assert_equal(1, e.qvalue('gzip'))
|
13
|
+
assert_equal(0.5, e.qvalue('identity'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_matches
|
17
|
+
e = E.new('gzip, identity, *')
|
18
|
+
assert_equal(%w{*}, e.matches(''))
|
19
|
+
assert_equal(%w{gzip *}, e.matches('gzip'))
|
20
|
+
assert_equal(%w{*}, e.matches('compress'))
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_best_of
|
24
|
+
e = E.new('gzip, compress')
|
25
|
+
assert_equal('gzip', e.best_of(%w< gzip compress >))
|
26
|
+
assert_equal('identity', e.best_of(%w< identity compress >))
|
27
|
+
assert_equal(nil, e.best_of(%w< zip >))
|
28
|
+
end
|
29
|
+
end
|
data/test/header_test.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class HeaderTest < Minitest::Test
|
4
|
+
H = Rack::AcceptHeaders::Header
|
5
|
+
|
6
|
+
def test_parse_and_join
|
7
|
+
# Accept
|
8
|
+
header = 'text/plain; q=0.5, text/html, text/html;level=2, text/html;level=1;q=0.3, text/x-c, image/*; q=0.2'
|
9
|
+
expect = {
|
10
|
+
'text/plain' => 0.5,
|
11
|
+
'text/html' => 1,
|
12
|
+
'text/html;level=2' => 1,
|
13
|
+
'text/html;level=1' => 0.3,
|
14
|
+
'text/x-c' => 1,
|
15
|
+
'image/*' => 0.2
|
16
|
+
}
|
17
|
+
assert_equal(expect, H.parse(header))
|
18
|
+
assert_equal(expect, H.parse(H.join(expect)))
|
19
|
+
|
20
|
+
# Accept-Charset
|
21
|
+
header = 'iso-8859-5, unicode-1-1;q=0.8'
|
22
|
+
expect = { 'iso-8859-5' => 1, 'unicode-1-1' => 0.8 }
|
23
|
+
assert_equal(expect, H.parse(header))
|
24
|
+
assert_equal(expect, H.parse(H.join(expect)))
|
25
|
+
|
26
|
+
# Accept-Encoding
|
27
|
+
header = 'gzip;q=1.0, identity; q=0.5, *;q=0'
|
28
|
+
expect = { 'gzip' => 1, 'identity' => 0.5, '*' => 0 }
|
29
|
+
assert_equal(expect, H.parse(header))
|
30
|
+
assert_equal(expect, H.parse(H.join(expect)))
|
31
|
+
|
32
|
+
# Accept-Language
|
33
|
+
header = 'da, en-gb;q=0.8, en;q=0.7'
|
34
|
+
expect = { 'da' => 1, 'en-gb' => 0.8, 'en' => 0.7 }
|
35
|
+
assert_equal(expect, H.parse(header))
|
36
|
+
assert_equal(expect, H.parse(H.join(expect)))
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_parse_media_type
|
40
|
+
assert_equal([], H.parse_media_type(''))
|
41
|
+
assert_equal(['*', '*', ''], H.parse_media_type('*/*'))
|
42
|
+
assert_equal(['text', '*', ''], H.parse_media_type('text/*'))
|
43
|
+
assert_equal(['text', 'html', ''], H.parse_media_type('text/html'))
|
44
|
+
assert_equal(['text', 'html', 'level=1'], H.parse_media_type('text/html;level=1'))
|
45
|
+
assert_equal(['text', 'html', 'level=1;answer=42'], H.parse_media_type('text/html;level=1;answer=42'))
|
46
|
+
assert_equal(['text', 'x-dvi', ''], H.parse_media_type('text/x-dvi'))
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_parse_range_params
|
50
|
+
assert_equal({'q' => '1'}, H.parse_range_params(''))
|
51
|
+
assert_equal({'q' => '1'}, H.parse_range_params('a'))
|
52
|
+
assert_equal({'q' => '1', 'a' => 'a'}, H.parse_range_params('a=a'))
|
53
|
+
assert_equal({'q' => '1', 'a' => 'a', 'b' => 'b'}, H.parse_range_params('a=a;b=b'))
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_normalize_qvalue
|
57
|
+
assert_equal(1, H.normalize_qvalue(1.0))
|
58
|
+
assert_equal(0, H.normalize_qvalue(0.0))
|
59
|
+
assert_equal(1, H.normalize_qvalue(1))
|
60
|
+
assert_equal(0, H.normalize_qvalue(0))
|
61
|
+
assert_equal(0.5, H.normalize_qvalue(0.5))
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_invalid_header
|
65
|
+
assert_raises Rack::AcceptHeaders::Header::InvalidHeader do
|
66
|
+
h = H.parse(' / ')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class LanguageTest < Minitest::Test
|
4
|
+
L = Rack::AcceptHeaders::Language
|
5
|
+
|
6
|
+
def test_qvalue
|
7
|
+
l = L.new('')
|
8
|
+
assert_equal(1, l.qvalue('en'))
|
9
|
+
|
10
|
+
l = L.new('en;q=0.5, en-gb')
|
11
|
+
assert_equal(0.5, l.qvalue('en'))
|
12
|
+
assert_equal(1, l.qvalue('en-gb'))
|
13
|
+
assert_equal(0, l.qvalue('da'))
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_matches
|
17
|
+
l = L.new('da, *, en')
|
18
|
+
assert_equal(%w{*}, l.matches(''))
|
19
|
+
assert_equal(%w{da *}, l.matches('da'))
|
20
|
+
assert_equal(%w{en *}, l.matches('en'))
|
21
|
+
assert_equal(%w{en *}, l.matches('en-gb'))
|
22
|
+
assert_equal(%w{*}, l.matches('eng'))
|
23
|
+
|
24
|
+
l = L.new('en, en-gb')
|
25
|
+
assert_equal(%w{en-gb en}, l.matches('en-gb'))
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_best_of
|
29
|
+
l = L.new('en;q=0.5, en-gb')
|
30
|
+
assert_equal('en-gb', l.best_of(%w< en en-gb >))
|
31
|
+
assert_equal('en', l.best_of(%w< en da >))
|
32
|
+
assert_equal('en-us', l.best_of(%w< en-us en-au >))
|
33
|
+
assert_equal(nil, l.best_of(%w< da >))
|
34
|
+
|
35
|
+
l = L.new('en;q=0.5, en-GB, fr-CA')
|
36
|
+
assert_equal('en-gb', l.best_of(%w< en en-gb >))
|
37
|
+
|
38
|
+
l = L.new('en-gb;q=0.5, EN, fr-CA')
|
39
|
+
assert_equal('en', l.best_of(%w< en en-gb >))
|
40
|
+
|
41
|
+
l = L.new('en;q=0.5, fr-ca')
|
42
|
+
assert_equal('en', l.best_of(%w< en fr >))
|
43
|
+
|
44
|
+
l.first_level_match = true
|
45
|
+
assert_equal('fr', l.best_of(%w< en fr >))
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class MediaTypeTest < Minitest::Test
|
4
|
+
M = Rack::AcceptHeaders::MediaType
|
5
|
+
|
6
|
+
def test_qvalue
|
7
|
+
m = M.new('text/html, text/*;q=0.3, */*;q=0.5')
|
8
|
+
assert_equal(0.5, m.qvalue('image/png'))
|
9
|
+
assert_equal(0.3, m.qvalue('text/plain'))
|
10
|
+
assert_equal(1, m.qvalue('text/html'))
|
11
|
+
|
12
|
+
m = M.new('text/html')
|
13
|
+
assert_equal(0, m.qvalue('image/png'))
|
14
|
+
|
15
|
+
m = M.new('')
|
16
|
+
assert_equal(1, m.qvalue('text/html'))
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_invalid_media_type
|
20
|
+
assert_raises Rack::AcceptHeaders::Header::InvalidHeader do
|
21
|
+
m = M.new('')
|
22
|
+
m = M.new('text')
|
23
|
+
m = M.new('text;q=1')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_matches
|
28
|
+
m = M.new('text/*, text/html, text/html;level=1, */*')
|
29
|
+
assert_equal(%w{*/*}, m.matches(''))
|
30
|
+
assert_equal(%w{*/*}, m.matches('image/jpeg'))
|
31
|
+
assert_equal(%w{text/* */*}, m.matches('text/plain'))
|
32
|
+
assert_equal(%w{text/html text/* */*}, m.matches('text/html'))
|
33
|
+
assert_equal(%w{text/html text/* */*}, m.matches('text/html;level=1'))
|
34
|
+
assert_equal(%w{text/html text/* */*}, m.matches('text/html;level=1;answer=42'))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_best_of
|
38
|
+
m = M.new('text/*;q=0.5, text/html')
|
39
|
+
assert_equal('text/html', m.best_of(%w< text/plain text/html >))
|
40
|
+
assert_equal('text/plain', m.best_of(%w< text/plain image/png >))
|
41
|
+
assert_equal('text/plain', m.best_of(%w< text/plain text/javascript >))
|
42
|
+
assert_equal(nil, m.best_of(%w< image/png >))
|
43
|
+
|
44
|
+
m = M.new('text/*')
|
45
|
+
assert_equal('text/html', m.best_of(%w< text/html text/xml >))
|
46
|
+
assert_equal('text/xml', m.best_of(%w< text/xml text/html >))
|
47
|
+
|
48
|
+
m = M.new('TEXT/*')
|
49
|
+
assert_equal('text/html', m.best_of(%w< text/html text/xml >))
|
50
|
+
assert_equal('text/xml', m.best_of(%w< text/xml text/html >))
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_extensions
|
54
|
+
m = M.new('text/plain')
|
55
|
+
assert_equal({'text/plain' => {'q' => '1'}}, m.extensions)
|
56
|
+
m = M.new('text/*;q=0.5;a=42')
|
57
|
+
assert_equal({'text/*' => {'q' => '0.5', 'a' => '42'}}, m.extensions)
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_params
|
61
|
+
m = M.new('text/plain;q=0.7;version=1.0')
|
62
|
+
assert_equal({'q' => '0.7', 'version' => '1.0'}, m.params('text/plain'))
|
63
|
+
m = M.new('text/*;q=0.5;a=42, application/json;b=12')
|
64
|
+
assert_equal({'q' => '0.5', 'a' => '42'}, m.params('text/plain'))
|
65
|
+
assert_equal({'q' => '1', 'b' => '12'}, m.params('application/json'))
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_vendored_types
|
69
|
+
m = M.new("application/vnd.ms-excel")
|
70
|
+
assert_equal(nil, m.best_of(%w< application/vnd.ms-powerpoint >))
|
71
|
+
|
72
|
+
m = M.new("application/vnd.api-v1+json")
|
73
|
+
assert_equal(false, m.accept?("application/vnd.api-v2+json"))
|
74
|
+
|
75
|
+
v1, v2 = "application/vnd.api-v1+json", "application/vnd.api-v2+json"
|
76
|
+
m = M.new("#{v1},#{v2}")
|
77
|
+
assert_equal(v1, m.best_of([v1, v2]))
|
78
|
+
assert_equal(v2, m.best_of([v2, v1]))
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require_relative 'test_helper'
|
2
|
+
|
3
|
+
class RequestTest < Minitest::Test
|
4
|
+
R = Rack::AcceptHeaders::Request
|
5
|
+
|
6
|
+
def test_media_type
|
7
|
+
r = R.new('HTTP_ACCEPT' => 'text/*;q=0, text/html')
|
8
|
+
assert(r.media_type?('text/html'))
|
9
|
+
assert(r.media_type?('text/html;level=1'))
|
10
|
+
assert(!r.media_type?('text/plain'))
|
11
|
+
assert(!r.media_type?('image/png'))
|
12
|
+
|
13
|
+
request = R.new('HTTP_ACCEPT' => '*/*')
|
14
|
+
assert(request.media_type?('image/png'))
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_charset
|
18
|
+
r = R.new('HTTP_ACCEPT_CHARSET' => 'iso-8859-5, unicode-1-1;q=0.8')
|
19
|
+
assert(r.charset?('iso-8859-5'))
|
20
|
+
assert(r.charset?('unicode-1-1'))
|
21
|
+
assert(r.charset?('iso-8859-1'))
|
22
|
+
assert(!r.charset?('utf-8'))
|
23
|
+
|
24
|
+
r = R.new('HTTP_ACCEPT_CHARSET' => 'iso-8859-1;q=0')
|
25
|
+
assert(!r.charset?('iso-8859-1'))
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_encoding
|
29
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => '')
|
30
|
+
assert(r.encoding?('identity'))
|
31
|
+
assert(!r.encoding?('gzip'))
|
32
|
+
|
33
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => 'gzip')
|
34
|
+
assert(r.encoding?('identity'))
|
35
|
+
assert(r.encoding?('gzip'))
|
36
|
+
assert(!r.encoding?('compress'))
|
37
|
+
|
38
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => 'gzip;q=0, *')
|
39
|
+
assert(r.encoding?('compress'))
|
40
|
+
assert(r.encoding?('identity'))
|
41
|
+
assert(!r.encoding?('gzip'))
|
42
|
+
|
43
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => 'identity;q=0')
|
44
|
+
assert(!r.encoding?('identity'))
|
45
|
+
|
46
|
+
r = R.new('HTTP_ACCEPT_ENCODING' => '*;q=0')
|
47
|
+
assert(!r.encoding?('identity'))
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_language
|
51
|
+
request = R.new({})
|
52
|
+
assert(request.language?('en'))
|
53
|
+
assert(request.language?('da'))
|
54
|
+
|
55
|
+
request = R.new('HTTP_ACCEPT_LANGUAGE' => 'en;q=0.5, en-gb')
|
56
|
+
assert(request.language?('en'))
|
57
|
+
assert(request.language?('en-gb'))
|
58
|
+
assert(!request.language?('da'))
|
59
|
+
end
|
60
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
ENV['RACK_ENV'] = 'test'
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'rack/accept_headers'
|
6
|
+
|
7
|
+
class Minitest::Test
|
8
|
+
attr_reader :context
|
9
|
+
attr_reader :response
|
10
|
+
|
11
|
+
def status
|
12
|
+
@response && @response.status
|
13
|
+
end
|
14
|
+
|
15
|
+
def request(env={}, method='GET', uri='/')
|
16
|
+
@context = Rack::AcceptHeaders.new(fake_app)
|
17
|
+
yield @context if block_given?
|
18
|
+
mock_request = Rack::MockRequest.new(@context)
|
19
|
+
@response = mock_request.request(method.to_s.upcase, uri, env)
|
20
|
+
@response
|
21
|
+
end
|
22
|
+
|
23
|
+
def fake_app(status=200, headers={}, body=[])
|
24
|
+
lambda {|env| Rack::Response.new(body, status, headers).finish }
|
25
|
+
end
|
26
|
+
end
|