Skip to content

Commit 30759d7

Browse files
committed
Initial migration of code.
1 parent 3df19c7 commit 30759d7

File tree

2 files changed

+137
-0
lines changed

2 files changed

+137
-0
lines changed

lib/protocol/http/media_types.rb

+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2016-2024, by Samuel Williams.
5+
6+
module Protocol
7+
module HTTP
8+
class MediaTypes
9+
WILDCARD = "*/*".freeze
10+
11+
def initialize
12+
@map = {}
13+
end
14+
15+
def freeze
16+
return self if frozen?
17+
18+
@map.freeze
19+
@map.each_value(&:freeze)
20+
21+
return super
22+
end
23+
24+
# Given a list of content types (e.g. from browser_preferred_content_types), return the best converter. Media types can be an array of MediaRange or String values.
25+
def for(media_ranges)
26+
media_ranges.each do |media_range|
27+
range_string = media_range.range_string
28+
29+
if object = @map[range_string]
30+
return object
31+
end
32+
end
33+
34+
return nil
35+
end
36+
37+
def []= media_range, object
38+
@map[media_range] = object
39+
end
40+
41+
def [] media_range
42+
@map[media_range]
43+
end
44+
45+
# Add a converter to the collection. A converter can be anything that responds to #content_type. Objects will be considered in the order they are added, subsequent objects cannot override previously defined media types. `object` must respond to #split('/', 2) which should give the type and subtype.
46+
def << object
47+
media_range = object.media_range
48+
49+
# We set the default if not specified already:
50+
@map[WILDCARD] = object if @map.empty?
51+
52+
type = media_range.type
53+
if type != "*"
54+
@map["#{type}/*"] ||= object
55+
56+
subtype = media_range.subtype
57+
if subtype != "*"
58+
@map["#{type}/#{subtype}"] ||= object
59+
end
60+
end
61+
62+
return self
63+
end
64+
end
65+
end
66+
end

test/protocol/http/media_types.rb

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# frozen_string_literal: true
2+
3+
# Released under the MIT License.
4+
# Copyright, 2016-2024, by Samuel Williams.
5+
6+
require "protocol/http/accept/media_types"
7+
require "protocol/http/accept/media_types/map"
8+
require "protocol/http/accept/content_type"
9+
10+
describe Protocol::HTTP::MediaTypes do
11+
let(:converter) do
12+
Struct.new(:content_type) do
13+
def split(*args)
14+
self.content_type.split(*args)
15+
end
16+
end
17+
end
18+
19+
let(:text_html_converter) {converter.new("text/html")}
20+
21+
let(:text_plain_content_type) {Protocol::HTTP::Accept::ContentType.new("text", "plain", charset: "utf-8")}
22+
let(:text_plain_converter) {converter.new(text_plain_content_type)}
23+
24+
let(:map) {subject.new}
25+
26+
it "should give the correct converter when specified completely" do
27+
map << text_html_converter
28+
map << text_plain_converter
29+
30+
media_types = Protocol::HTTP::Accept::MediaTypes.parse("text/plain, text/*, */*")
31+
expect(map.for(media_types).first).to be == text_plain_converter
32+
33+
media_types = Protocol::HTTP::Accept::MediaTypes.parse("text/html, text/*, */*")
34+
expect(map.for(media_types).first).to be == text_html_converter
35+
end
36+
37+
it "should match the wildcard subtype converter" do
38+
map << text_html_converter
39+
map << text_plain_converter
40+
41+
media_types = Protocol::HTTP::Accept::MediaTypes.parse("text/*, */*")
42+
expect(map.for(media_types).first).to be == text_html_converter
43+
44+
media_types = Protocol::HTTP::Accept::MediaTypes.parse("*/*")
45+
expect(map.for(media_types).first).to be == text_html_converter
46+
end
47+
48+
it "should fail to match if no media types match" do
49+
map << text_plain_converter
50+
51+
expect(map.for(["application/json"])).to be_nil
52+
end
53+
54+
it "should fail to match if no media types specified" do
55+
expect(map.for(["text/*", "*/*"])).to be_nil
56+
end
57+
58+
it "should freeze converters" do
59+
map << text_html_converter
60+
61+
map.freeze
62+
63+
expect(text_html_converter).to be(:frozen?)
64+
end
65+
66+
it "should assign and retrive media ranges" do
67+
map["*/*"] = :test
68+
69+
expect(map["*/*"]).to be == :test
70+
end
71+
end

0 commit comments

Comments
 (0)