protocol-url 0.10.0 → 0.12.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/protocol/url/absolute.rb +28 -15
- data/lib/protocol/url/encoding.rb +56 -49
- data/lib/protocol/url/path.rb +389 -139
- data/lib/protocol/url/reference.rb +25 -22
- data/lib/protocol/url/relative.rb +50 -26
- data/lib/protocol/url/version.rb +2 -2
- data/lib/protocol/url.rb +1 -1
- data/license.md +1 -1
- data/notes.md +17 -0
- data/readme.md +113 -3
- data/releases.md +4 -0
- data.tar.gz.sig +0 -0
- metadata +6 -3
- metadata.gz.sig +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "pattern"
|
|
7
7
|
require_relative "encoding"
|
|
@@ -21,8 +21,8 @@ module Protocol
|
|
|
21
21
|
#
|
|
22
22
|
# This method provides flexible conversion from various types into a {Reference}.
|
|
23
23
|
# When given a {String}, it parses the URL-encoded path, query, and fragment components
|
|
24
|
-
# and
|
|
25
|
-
#
|
|
24
|
+
# and preserves the path as a {Path}. When given a {Relative}, it preserves the
|
|
25
|
+
# existing path and its component boundaries.
|
|
26
26
|
#
|
|
27
27
|
# @parameter value [String | Relative | Nil] The value to coerce.
|
|
28
28
|
# @parameter parameters [Hash | Nil] Optional user-supplied parameters to append to the query string.
|
|
@@ -34,7 +34,7 @@ module Protocol
|
|
|
34
34
|
#
|
|
35
35
|
# @example Coerce a string with path, query, and fragment.
|
|
36
36
|
# reference = Reference["/search?q=ruby#results"]
|
|
37
|
-
# reference.path
|
|
37
|
+
# reference.path.to_s # => "/search"
|
|
38
38
|
# reference.query # => "q=ruby"
|
|
39
39
|
# reference.fragment # => "results"
|
|
40
40
|
#
|
|
@@ -45,7 +45,7 @@ module Protocol
|
|
|
45
45
|
# @example Coerce a Relative instance.
|
|
46
46
|
# relative = Relative.new("/path%20with%20spaces", nil, "top")
|
|
47
47
|
# reference = Reference[relative]
|
|
48
|
-
# reference.path # => "
|
|
48
|
+
# reference.path.components # => ["", "path with spaces"]
|
|
49
49
|
def self.[](value, parameters = nil)
|
|
50
50
|
case value
|
|
51
51
|
when String
|
|
@@ -54,9 +54,8 @@ module Protocol
|
|
|
54
54
|
query = match[:query]
|
|
55
55
|
fragment = match[:fragment]
|
|
56
56
|
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
path = Encoding.unescape(path) if path && !path.empty?
|
|
57
|
+
# Paths retain their encoded structure while exposing decoded components.
|
|
58
|
+
path = Path[path]
|
|
60
59
|
fragment = Encoding.unescape(fragment) if fragment
|
|
61
60
|
|
|
62
61
|
self.new(path, query, fragment, parameters)
|
|
@@ -64,11 +63,9 @@ module Protocol
|
|
|
64
63
|
raise ArgumentError, "Invalid URL (contains whitespace or control characters): #{value.inspect}"
|
|
65
64
|
end
|
|
66
65
|
when Relative
|
|
67
|
-
# Relative stores encoded
|
|
66
|
+
# Relative stores an encoded path; preserve its component boundaries.
|
|
68
67
|
path = value.path
|
|
69
68
|
fragment = value.fragment
|
|
70
|
-
|
|
71
|
-
path = Encoding.unescape(path) if path && !path.empty?
|
|
72
69
|
fragment = Encoding.unescape(fragment) if fragment
|
|
73
70
|
|
|
74
71
|
self.new(path, value.query, fragment, parameters)
|
|
@@ -77,20 +74,22 @@ module Protocol
|
|
|
77
74
|
else
|
|
78
75
|
raise ArgumentError, "Cannot coerce #{value.inspect} to Reference!"
|
|
79
76
|
end
|
|
80
|
-
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Generate a reference from a path and user parameters. The path may contain a `#fragment` or `?query=parameters`.
|
|
81
80
|
#
|
|
82
81
|
# @example Parse a path with query and fragment.
|
|
83
82
|
# reference = Reference.parse("/search?query=ruby#results")
|
|
84
|
-
# reference.path
|
|
83
|
+
# reference.path.to_s # => "/search"
|
|
85
84
|
# reference.query # => "query=ruby"
|
|
86
85
|
# reference.fragment # => "results"
|
|
87
86
|
def self.parse(value = "/", parameters = nil)
|
|
88
87
|
self.[](value, parameters)
|
|
89
88
|
end
|
|
90
89
|
|
|
91
|
-
# Initialize the reference
|
|
90
|
+
# Initialize the reference from an encoded path and reference values.
|
|
92
91
|
#
|
|
93
|
-
# @parameter path [String] The
|
|
92
|
+
# @parameter path [String | Path] The encoded path string, or an existing path.
|
|
94
93
|
# @parameter query [String | Nil] An already-formatted query string.
|
|
95
94
|
# @parameter fragment [String | Nil] The unescaped fragment.
|
|
96
95
|
# @parameter parameters [Hash | Nil] User supplied parameters that will be safely encoded.
|
|
@@ -103,8 +102,8 @@ module Protocol
|
|
|
103
102
|
@parameters = parameters
|
|
104
103
|
end
|
|
105
104
|
|
|
106
|
-
# @attribute [Hash] User supplied parameters that will be appended to the query part.
|
|
107
|
-
|
|
105
|
+
# @attribute [Hash | Nil] User supplied parameters that will be appended to the query part.
|
|
106
|
+
attr_accessor :parameters
|
|
108
107
|
|
|
109
108
|
# Freeze the reference.
|
|
110
109
|
#
|
|
@@ -161,10 +160,10 @@ module Protocol
|
|
|
161
160
|
end
|
|
162
161
|
|
|
163
162
|
# Append the reference to the given buffer.
|
|
164
|
-
# Encodes the
|
|
163
|
+
# Encodes the fragment; the path already retains its encoded structure.
|
|
165
164
|
# Query strings are passed through as-is (they contain = and & which are valid syntax).
|
|
166
165
|
def append(buffer = String.new)
|
|
167
|
-
buffer <<
|
|
166
|
+
buffer << @path.encoded
|
|
168
167
|
|
|
169
168
|
if @query and !@query.empty?
|
|
170
169
|
buffer << "?" << @query
|
|
@@ -185,7 +184,7 @@ module Protocol
|
|
|
185
184
|
other = self.class[other]
|
|
186
185
|
|
|
187
186
|
self.class.new(
|
|
188
|
-
|
|
187
|
+
@path.join(other.path),
|
|
189
188
|
other.query,
|
|
190
189
|
other.fragment,
|
|
191
190
|
other.parameters,
|
|
@@ -199,7 +198,7 @@ module Protocol
|
|
|
199
198
|
|
|
200
199
|
# Update the reference with the given path, query, fragment, and parameters.
|
|
201
200
|
#
|
|
202
|
-
# @parameter path [String] Append the
|
|
201
|
+
# @parameter path [String | Path] Append the encoded path to this reference similar to `File.join`.
|
|
203
202
|
# @parameter query [String | Nil] Replace the query string. Defaults to keeping the existing query if not specified.
|
|
204
203
|
# @parameter fragment [String | Nil] Replace the fragment. Defaults to keeping the existing fragment if not specified.
|
|
205
204
|
# @parameter parameters [Hash | false] Parameters to merge or replace. Pass `false` (default) to keep existing parameters.
|
|
@@ -251,7 +250,11 @@ module Protocol
|
|
|
251
250
|
end
|
|
252
251
|
end
|
|
253
252
|
|
|
254
|
-
path
|
|
253
|
+
if path.nil?
|
|
254
|
+
path = @path
|
|
255
|
+
else
|
|
256
|
+
path = @path.join(path, pop: pop)
|
|
257
|
+
end
|
|
255
258
|
|
|
256
259
|
self.class.new(path, query, fragment, parameters)
|
|
257
260
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "encoding"
|
|
7
7
|
require_relative "path"
|
|
@@ -14,31 +14,54 @@ module Protocol
|
|
|
14
14
|
|
|
15
15
|
# Initialize a new relative URL.
|
|
16
16
|
#
|
|
17
|
-
# @parameter path [String] The path component.
|
|
18
|
-
# @parameter query [String
|
|
19
|
-
# @parameter fragment [String
|
|
17
|
+
# @parameter path [String | Path] The encoded path component.
|
|
18
|
+
# @parameter query [String | Nil] The query string.
|
|
19
|
+
# @parameter fragment [String | Nil] The fragment identifier.
|
|
20
20
|
def initialize(path, query = nil, fragment = nil)
|
|
21
|
-
@path = path
|
|
21
|
+
@path = Path[path]
|
|
22
22
|
@query = query
|
|
23
23
|
@fragment = fragment
|
|
24
24
|
end
|
|
25
25
|
|
|
26
|
-
#
|
|
26
|
+
# Freeze the URL and its direct components.
|
|
27
|
+
# @returns [Relative] The frozen URL.
|
|
28
|
+
def freeze
|
|
29
|
+
return self if frozen?
|
|
30
|
+
|
|
31
|
+
@path.freeze
|
|
32
|
+
@query.freeze
|
|
33
|
+
@fragment.freeze
|
|
34
|
+
|
|
35
|
+
return super
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @attribute [Path] The path component of the URL.
|
|
27
39
|
attr :path
|
|
28
40
|
|
|
29
|
-
#
|
|
30
|
-
|
|
41
|
+
# Replace the path component of this URL.
|
|
42
|
+
# @parameter path [String | Path] The encoded path component.
|
|
43
|
+
# @returns [Path] The assigned path component.
|
|
44
|
+
def path=(path)
|
|
45
|
+
@path = Path[path]
|
|
46
|
+
end
|
|
31
47
|
|
|
32
|
-
# @attribute [String
|
|
33
|
-
|
|
48
|
+
# @attribute [String | Nil] The query string component.
|
|
49
|
+
attr_accessor :query
|
|
34
50
|
|
|
35
|
-
#
|
|
51
|
+
# @attribute [String | Nil] The fragment identifier.
|
|
52
|
+
attr_accessor :fragment
|
|
53
|
+
|
|
54
|
+
# Resolve the URL path beneath a local filesystem root.
|
|
36
55
|
#
|
|
37
|
-
# @
|
|
38
|
-
|
|
39
|
-
|
|
56
|
+
# @parameter root [String] The filesystem root beneath which to resolve the URL path.
|
|
57
|
+
# @returns [String] The expanded local filesystem path.
|
|
58
|
+
# @raises [ArgumentError] If a URL segment is invalid or the path escapes the specified root.
|
|
59
|
+
def local_path(root)
|
|
60
|
+
@path.local_path(root)
|
|
40
61
|
end
|
|
41
62
|
|
|
63
|
+
alias to_local_path local_path
|
|
64
|
+
|
|
42
65
|
# @returns [Boolean] If there is a query string.
|
|
43
66
|
def query?
|
|
44
67
|
@query and !@query.empty?
|
|
@@ -58,13 +81,13 @@ module Protocol
|
|
|
58
81
|
# base = Relative.new("/documents/reports/")
|
|
59
82
|
# other = Relative.new("invoices/2024.pdf")
|
|
60
83
|
# result = base + other
|
|
61
|
-
# result.path # => "/documents/reports/invoices/2024.pdf"
|
|
84
|
+
# result.path.to_s # => "/documents/reports/invoices/2024.pdf"
|
|
62
85
|
#
|
|
63
86
|
# @example Navigate to parent directory.
|
|
64
87
|
# base = Relative.new("/documents/reports/archive/")
|
|
65
88
|
# other = Relative.new("../../summary.pdf")
|
|
66
89
|
# result = base + other
|
|
67
|
-
# result.path # => "/documents/summary.pdf"
|
|
90
|
+
# result.path.to_s # => "/documents/summary.pdf"
|
|
68
91
|
def +(other)
|
|
69
92
|
case other
|
|
70
93
|
when Absolute
|
|
@@ -74,7 +97,7 @@ module Protocol
|
|
|
74
97
|
when Relative
|
|
75
98
|
# Relative + Relative: merge paths directly
|
|
76
99
|
self.class.new(
|
|
77
|
-
|
|
100
|
+
@path.join(other.path),
|
|
78
101
|
other.query,
|
|
79
102
|
other.fragment
|
|
80
103
|
)
|
|
@@ -88,9 +111,9 @@ module Protocol
|
|
|
88
111
|
|
|
89
112
|
# Create a new Relative URL with modified components.
|
|
90
113
|
#
|
|
91
|
-
# @parameter path [String
|
|
92
|
-
# @parameter query [String
|
|
93
|
-
# @parameter fragment [String
|
|
114
|
+
# @parameter path [String | Nil] The path to merge with the current path.
|
|
115
|
+
# @parameter query [String | Nil] The query string to use.
|
|
116
|
+
# @parameter fragment [String | Nil] The fragment to use.
|
|
94
117
|
# @parameter pop [Boolean] Whether to pop the last path component before merging.
|
|
95
118
|
# @returns [Relative] A new Relative URL with the modified components.
|
|
96
119
|
#
|
|
@@ -104,7 +127,9 @@ module Protocol
|
|
|
104
127
|
# updated = url.with(path: "report.pdf", pop: false)
|
|
105
128
|
# updated.to_s # => "/documents/report.pdf"
|
|
106
129
|
def with(path: nil, query: @query, fragment: @fragment, pop: true)
|
|
107
|
-
|
|
130
|
+
path = @path.join(path, pop: pop) unless path.nil?
|
|
131
|
+
|
|
132
|
+
self.class.new(path || @path, query, fragment)
|
|
108
133
|
end
|
|
109
134
|
|
|
110
135
|
# Normalize the path by resolving "." and ".." segments and removing duplicate slashes.
|
|
@@ -119,11 +144,9 @@ module Protocol
|
|
|
119
144
|
# @example Basic normalization
|
|
120
145
|
# url = Relative.new("/foo//bar/./baz/../qux")
|
|
121
146
|
# url.normalize!
|
|
122
|
-
# url.path # => "/foo/bar/qux"
|
|
147
|
+
# url.path.to_s # => "/foo/bar/qux"
|
|
123
148
|
def normalize!
|
|
124
|
-
|
|
125
|
-
normalized = Path.simplify(components)
|
|
126
|
-
@path = Path.join(normalized)
|
|
149
|
+
@path = @path.simplify
|
|
127
150
|
|
|
128
151
|
return self
|
|
129
152
|
end
|
|
@@ -131,7 +154,7 @@ module Protocol
|
|
|
131
154
|
# Append the relative URL to the given buffer.
|
|
132
155
|
# The path, query, and fragment are expected to already be properly encoded.
|
|
133
156
|
def append(buffer = String.new)
|
|
134
|
-
buffer << @path
|
|
157
|
+
buffer << @path.encoded
|
|
135
158
|
|
|
136
159
|
if @query and !@query.empty?
|
|
137
160
|
buffer << "?" << @query
|
|
@@ -217,6 +240,7 @@ module Protocol
|
|
|
217
240
|
def inspect
|
|
218
241
|
"#<#{self.class} #{to_s}>"
|
|
219
242
|
end
|
|
243
|
+
|
|
220
244
|
end
|
|
221
245
|
end
|
|
222
246
|
end
|
data/lib/protocol/url/version.rb
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
# @namespace
|
|
7
7
|
module Protocol
|
|
8
8
|
# @namespace
|
|
9
9
|
module URL
|
|
10
|
-
VERSION = "0.
|
|
10
|
+
VERSION = "0.12.0"
|
|
11
11
|
end
|
|
12
12
|
end
|
data/lib/protocol/url.rb
CHANGED
data/license.md
CHANGED
data/notes.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Follow-up Notes
|
|
2
|
+
|
|
3
|
+
## Update `low-rb/low_loop`
|
|
4
|
+
|
|
5
|
+
File a follow-up PR against [`low-rb/low_loop`](https://github.com/low-rb/low_loop). Its file server currently uses the removed `Protocol::URL::Path.to_local_path` API in `lib/servers/file_server.rb`:
|
|
6
|
+
|
|
7
|
+
```ruby
|
|
8
|
+
filepath = Protocol::URL::Path.to_local_path(Protocol::URL[event.request.path].path)
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Update it to use the `Path` instance returned by `URL#path`:
|
|
12
|
+
|
|
13
|
+
```ruby
|
|
14
|
+
filepath = Protocol::URL[event.request.path].path.local_path(web_root)
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This call is security-sensitive because it converts an untrusted request path into a filesystem path. Confirm that the updated code passes `web_root` directly to `local_path`, handles traversal errors, and has an explicit policy for symlinks beneath the served root.
|
data/readme.md
CHANGED
|
@@ -16,11 +16,121 @@ Please see the [project documentation](https://socketry.github.io/protocol-url/)
|
|
|
16
16
|
|
|
17
17
|
We welcome contributions to this project.
|
|
18
18
|
|
|
19
|
-
1. Fork
|
|
19
|
+
1. Fork the repository.
|
|
20
20
|
2. Create your feature branch (`git checkout -b my-new-feature`).
|
|
21
|
-
3. Commit your changes (`git commit -am 'Add some feature'`).
|
|
21
|
+
3. Commit your changes (`git commit -am 'Add some feature.'`).
|
|
22
22
|
4. Push to the branch (`git push origin my-new-feature`).
|
|
23
|
-
5. Create new
|
|
23
|
+
5. Create a new pull request.
|
|
24
|
+
|
|
25
|
+
### Running Tests
|
|
26
|
+
|
|
27
|
+
To run the test suite:
|
|
28
|
+
|
|
29
|
+
``` shell
|
|
30
|
+
bundle exec sus
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Making Releases
|
|
34
|
+
|
|
35
|
+
Please see the [project releases](https://socketry.github.io/protocol-url/releases/index) for all releases.
|
|
36
|
+
|
|
37
|
+
### v0.12.0
|
|
38
|
+
|
|
39
|
+
- Allow unfrozen relative and absolute URLs to replace their components.
|
|
40
|
+
|
|
41
|
+
### v0.10.0
|
|
42
|
+
|
|
43
|
+
- Rename `Protocol::URL::FormData::Parser::CONTENT_TYPE` to `MEDIA_TYPE`.
|
|
44
|
+
|
|
45
|
+
### v0.9.0
|
|
46
|
+
|
|
47
|
+
- Add `Protocol::URL::LimitError` for configured processing limits.
|
|
48
|
+
|
|
49
|
+
### v0.8.0
|
|
50
|
+
|
|
51
|
+
- Use consistent limit naming for form data parser constraints.
|
|
52
|
+
|
|
53
|
+
### v0.7.0
|
|
54
|
+
|
|
55
|
+
- Allow `Protocol::URL::FormData::Parser#parse` to populate a supplied result object.
|
|
56
|
+
|
|
57
|
+
### v0.6.0
|
|
58
|
+
|
|
59
|
+
- Add `Protocol::URL::FormData::Parser` for incremental, limited parsing of `application/x-www-form-urlencoded` form data.
|
|
60
|
+
- Add `Protocol::URL::FormData::Nested` for consistently building nested form data while preserving absent and empty values.
|
|
61
|
+
|
|
62
|
+
### v0.5.0
|
|
63
|
+
|
|
64
|
+
- Add `Protocol::URL::Encoding.decode_www_form` for decoding HTML form data where `+` represents a space.
|
|
65
|
+
|
|
66
|
+
### v0.4.0
|
|
67
|
+
|
|
68
|
+
- Add comparison methods to `Protocol::URL::Relative` (and by inheritance to `Protocol::URL::Absolute`):
|
|
69
|
+
- `#==` for structural equality comparison (compares path, query, fragment components).
|
|
70
|
+
- `#===` for string equality comparison (enables case statement matching).
|
|
71
|
+
- `#<=>` for ordering and sorting.
|
|
72
|
+
- `#hash` for hash key support.
|
|
73
|
+
- `#equal?` for component-based equality checking.
|
|
74
|
+
- Add JSON serialization support to `Protocol::URL::Relative`:
|
|
75
|
+
- `#as_json` returns the string representation.
|
|
76
|
+
- `#to_json` returns a JSON-encoded string.
|
|
77
|
+
|
|
78
|
+
### v0.3.0
|
|
79
|
+
|
|
80
|
+
- Add `relative(target, from)` for computing relative paths between URLs.
|
|
81
|
+
|
|
82
|
+
### v0.2.0
|
|
83
|
+
|
|
84
|
+
- Move `Protocol::URL::PATTERN` to `protocol/url/pattern.rb` so it can be shared more easily.
|
|
85
|
+
|
|
86
|
+
### v0.10.0
|
|
87
|
+
|
|
88
|
+
- Rename `Protocol::URL::FormData::Parser::CONTENT_TYPE` to `MEDIA_TYPE`.
|
|
89
|
+
|
|
90
|
+
### v0.9.0
|
|
91
|
+
|
|
92
|
+
- Add `Protocol::URL::LimitError` for configured processing limits.
|
|
93
|
+
|
|
94
|
+
### v0.8.0
|
|
95
|
+
|
|
96
|
+
- Use consistent limit naming for form data parser constraints.
|
|
97
|
+
|
|
98
|
+
### v0.7.0
|
|
99
|
+
|
|
100
|
+
- Allow `Protocol::URL::FormData::Parser#parse` to populate a supplied result object.
|
|
101
|
+
|
|
102
|
+
### v0.6.0
|
|
103
|
+
|
|
104
|
+
- Add `Protocol::URL::FormData::Parser` for incremental, limited parsing of `application/x-www-form-urlencoded` form data.
|
|
105
|
+
- Add `Protocol::URL::FormData::Nested` for consistently building nested form data while preserving absent and empty values.
|
|
106
|
+
|
|
107
|
+
### v0.5.0
|
|
108
|
+
|
|
109
|
+
- Add `Protocol::URL::Encoding.decode_www_form` for decoding HTML form data where `+` represents a space.
|
|
110
|
+
|
|
111
|
+
### v0.4.0
|
|
112
|
+
|
|
113
|
+
- Add comparison methods to `Protocol::URL::Relative` (and by inheritance to `Protocol::URL::Absolute`):
|
|
114
|
+
- `#==` for structural equality comparison (compares path, query, fragment components).
|
|
115
|
+
- `#===` for string equality comparison (enables case statement matching).
|
|
116
|
+
- `#<=>` for ordering and sorting.
|
|
117
|
+
- `#hash` for hash key support.
|
|
118
|
+
- `#equal?` for component-based equality checking.
|
|
119
|
+
- Add JSON serialization support to `Protocol::URL::Relative`:
|
|
120
|
+
- `#as_json` returns the string representation.
|
|
121
|
+
- `#to_json` returns a JSON-encoded string.
|
|
122
|
+
|
|
123
|
+
### v0.3.0
|
|
124
|
+
|
|
125
|
+
- Add `relative(target, from)` for computing relative paths between URLs.
|
|
126
|
+
|
|
127
|
+
### v0.2.0
|
|
128
|
+
|
|
129
|
+
- Move `Protocol::URL::PATTERN` to `protocol/url/pattern.rb` so it can be shared more easily.
|
|
130
|
+
|
|
131
|
+
### v0.1.0
|
|
132
|
+
|
|
133
|
+
- Initial implementation.
|
|
24
134
|
|
|
25
135
|
### Developer Certificate of Origin
|
|
26
136
|
|
data/releases.md
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: protocol-url
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -54,14 +54,17 @@ files:
|
|
|
54
54
|
- lib/protocol/url/relative.rb
|
|
55
55
|
- lib/protocol/url/version.rb
|
|
56
56
|
- license.md
|
|
57
|
+
- notes.md
|
|
57
58
|
- readme.md
|
|
58
59
|
- releases.md
|
|
59
60
|
homepage: https://github.com/socketry/protocol-url
|
|
60
61
|
licenses:
|
|
61
62
|
- MIT
|
|
62
63
|
metadata:
|
|
63
|
-
|
|
64
|
+
bug_tracker_uri: https://github.com/socketry/protocol-url/issues
|
|
65
|
+
changelog_uri: https://github.com/socketry/protocol-url/blob/main/releases.md
|
|
64
66
|
documentation_uri: https://socketry.github.io/protocol-url/
|
|
67
|
+
source_code_uri: https://github.com/socketry/protocol-url.git
|
|
65
68
|
rdoc_options: []
|
|
66
69
|
require_paths:
|
|
67
70
|
- lib
|
|
@@ -69,7 +72,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
69
72
|
requirements:
|
|
70
73
|
- - ">="
|
|
71
74
|
- !ruby/object:Gem::Version
|
|
72
|
-
version: '3.
|
|
75
|
+
version: '3.3'
|
|
73
76
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
74
77
|
requirements:
|
|
75
78
|
- - ">="
|
metadata.gz.sig
CHANGED
|
Binary file
|