protocol-media 0.0.1
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/lib/protocol/media/type.rb +133 -0
- data/lib/protocol/media/version.rb +12 -0
- data/license.md +21 -0
- data/readme.md +14 -0
- metadata +43 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f2b4e5ba22b3b99614f42ca660be8745ea4d8b16a83dc8b97728461a5b4601d6
|
|
4
|
+
data.tar.gz: d9eea7f70012140ce42dee2501b48281b17476a5207e017ecd3a44891fac74fa
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: bb8adf6b0a4aa0df12f48cac05123671dc00bbdb53ee46825cd8e26676020fb4685302c99e4c1967e68ca6b2ab36d706b7f0b884a3e48c6d80d124ed48e43810
|
|
7
|
+
data.tar.gz: '0961e8287d2d249e37ffdf576fe17d27da6727070cacaa4694b8c84b6c0ef3f8b98a4f88b8cfca5f93758b8058b1522cc4cc728653d085985d5355fad9106df1'
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
require_relative "version"
|
|
7
|
+
|
|
8
|
+
require "strscan"
|
|
9
|
+
|
|
10
|
+
module Protocol
|
|
11
|
+
module Media
|
|
12
|
+
# A concrete media type and its parameters.
|
|
13
|
+
class Type
|
|
14
|
+
TOKEN = /[!#$%&'*+\-.^_`|~0-9A-Z]+/i
|
|
15
|
+
QUOTED_STRING = /"(?:.(?!(?<!\\)"))*.?"/
|
|
16
|
+
MEDIA_TYPE = /(?<type>#{TOKEN})\/(?<subtype>#{TOKEN})/
|
|
17
|
+
PARAMETER = /\s*;\s*(?<key>#{TOKEN})=((?<value>#{TOKEN})|(?<quoted_value>#{QUOTED_STRING}))/
|
|
18
|
+
|
|
19
|
+
# Parse a concrete media type.
|
|
20
|
+
#
|
|
21
|
+
# @parameter text [String] The media type, including any parameters.
|
|
22
|
+
# @parameter normalize_whitespace [Boolean] Whether to normalize whitespace in quoted parameter values.
|
|
23
|
+
# @returns [Type] The parsed media type.
|
|
24
|
+
def self.parse(text, normalize_whitespace = true)
|
|
25
|
+
scanner = StringScanner.new(text)
|
|
26
|
+
|
|
27
|
+
unless scanner.scan(MEDIA_TYPE)
|
|
28
|
+
raise ArgumentError, "Invalid media type: #{text.inspect}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
type = scanner[:type]
|
|
32
|
+
subtype = scanner[:subtype]
|
|
33
|
+
parameters = parse_parameters(scanner, normalize_whitespace)
|
|
34
|
+
|
|
35
|
+
unless scanner.eos?
|
|
36
|
+
raise ArgumentError, "Invalid media type: #{text.inspect}"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
new(type, subtype, parameters)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Parse media type parameters from the scanner.
|
|
43
|
+
#
|
|
44
|
+
# @parameter scanner [StringScanner] The scanner positioned after the type and subtype.
|
|
45
|
+
# @parameter normalize_whitespace [Boolean] Whether to normalize whitespace in quoted values.
|
|
46
|
+
# @returns [Hash] The parsed parameters.
|
|
47
|
+
def self.parse_parameters(scanner, normalize_whitespace = true)
|
|
48
|
+
parameters = {}
|
|
49
|
+
|
|
50
|
+
while scanner.scan(PARAMETER)
|
|
51
|
+
key = scanner[:key]
|
|
52
|
+
|
|
53
|
+
if value = scanner[:value]
|
|
54
|
+
parameters[key] = value
|
|
55
|
+
elsif quoted_value = scanner[:quoted_value]
|
|
56
|
+
parameters[key] = unquote(quoted_value, normalize_whitespace)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
parameters
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# @attribute [String] The top-level type, e.g. `text`.
|
|
64
|
+
attr_reader :type
|
|
65
|
+
|
|
66
|
+
# @attribute [String] The subtype, e.g. `plain`.
|
|
67
|
+
attr_reader :subtype
|
|
68
|
+
|
|
69
|
+
# @attribute [Hash] The media type parameters.
|
|
70
|
+
attr_reader :parameters
|
|
71
|
+
|
|
72
|
+
# @parameter type [String] The top-level type.
|
|
73
|
+
# @parameter subtype [String] The subtype.
|
|
74
|
+
# @parameter parameters [Hash] The media type parameters.
|
|
75
|
+
def initialize(type, subtype, parameters = {})
|
|
76
|
+
if type.include?("*") || subtype.include?("*")
|
|
77
|
+
raise ArgumentError, "Media types cannot contain wildcards: #{type}/#{subtype}"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
@type = type.downcase
|
|
81
|
+
@subtype = subtype.downcase
|
|
82
|
+
@parameters = parameters
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# The complete media type name.
|
|
86
|
+
#
|
|
87
|
+
# @returns [String]
|
|
88
|
+
def name
|
|
89
|
+
"#{@type}/#{@subtype}"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
alias mime_type name
|
|
93
|
+
|
|
94
|
+
# Convert the media type and parameters to a string.
|
|
95
|
+
def to_s
|
|
96
|
+
name + @parameters.collect do |key, value|
|
|
97
|
+
"; #{key}=#{quote(value.to_s)}"
|
|
98
|
+
end.join
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
alias to_str to_s
|
|
102
|
+
|
|
103
|
+
# Compare this media type with another media type.
|
|
104
|
+
def ==(other)
|
|
105
|
+
other.is_a?(Type) && @type == other.type && @subtype == other.subtype && @parameters == other.parameters
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
alias eql? ==
|
|
109
|
+
|
|
110
|
+
# Generate a hash key consistent with {#eql?}.
|
|
111
|
+
def hash
|
|
112
|
+
[@type, @subtype, @parameters].hash
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
private
|
|
116
|
+
|
|
117
|
+
def self.unquote(value, normalize_whitespace)
|
|
118
|
+
value = value[1...-1]
|
|
119
|
+
value.gsub!(/\\(.)/, '\\1')
|
|
120
|
+
value.gsub!(/[\r\n]+\s+/, " ") if normalize_whitespace
|
|
121
|
+
value
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def quote(value)
|
|
125
|
+
if value.match?(/\A#{TOKEN}\z/)
|
|
126
|
+
value
|
|
127
|
+
else
|
|
128
|
+
"\"#{value.gsub(/["\\]/, "\\\\\\0")}\""
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
# @namespace
|
|
7
|
+
module Protocol
|
|
8
|
+
# Models media types used by internet protocols and data formats.
|
|
9
|
+
module Media
|
|
10
|
+
VERSION = "0.0.1"
|
|
11
|
+
end
|
|
12
|
+
end
|
data/license.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# MIT License
|
|
2
|
+
|
|
3
|
+
Copyright, 2016-2026, by Samuel Williams.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/readme.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Protocol::Media
|
|
2
|
+
|
|
3
|
+
Provides a small representation of media types which can be shared by protocol implementations and registry backends.
|
|
4
|
+
|
|
5
|
+
``` ruby
|
|
6
|
+
require "protocol/media/type"
|
|
7
|
+
|
|
8
|
+
type = Protocol::Media::Type.parse("text/plain; charset=utf-8")
|
|
9
|
+
type.type # => "text"
|
|
10
|
+
type.subtype # => "plain"
|
|
11
|
+
type.parameters # => {"charset" => "utf-8"}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Registry data and indexed lookup are provided separately by `protocol-media-data`.
|
metadata
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: protocol-media
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Samuel Williams
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
executables: []
|
|
13
|
+
extensions: []
|
|
14
|
+
extra_rdoc_files: []
|
|
15
|
+
files:
|
|
16
|
+
- lib/protocol/media/type.rb
|
|
17
|
+
- lib/protocol/media/version.rb
|
|
18
|
+
- license.md
|
|
19
|
+
- readme.md
|
|
20
|
+
homepage: https://github.com/socketry/protocol-media
|
|
21
|
+
licenses:
|
|
22
|
+
- MIT
|
|
23
|
+
metadata:
|
|
24
|
+
documentation_uri: https://socketry.github.io/protocol-media/
|
|
25
|
+
source_code_uri: https://github.com/socketry/protocol-media.git
|
|
26
|
+
rdoc_options: []
|
|
27
|
+
require_paths:
|
|
28
|
+
- lib
|
|
29
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - ">="
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '3.3'
|
|
34
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '0'
|
|
39
|
+
requirements: []
|
|
40
|
+
rubygems_version: 4.0.10
|
|
41
|
+
specification_version: 4
|
|
42
|
+
summary: Provides abstractions for working with media types.
|
|
43
|
+
test_files: []
|