Skip to content

Commit d0d9385

Browse files
committed
100% documentation coverage.
1 parent 623d8d9 commit d0d9385

File tree

3 files changed

+149
-44
lines changed

3 files changed

+149
-44
lines changed

lib/protocol/url/absolute.rb

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@ module URL
1010
# Represents an absolute URL with scheme and/or authority.
1111
# Examples: "https://example.com/path", "//cdn.example.com/lib.js", "http://localhost/"
1212
class Absolute < Relative
13+
# Initialize a new absolute URL.
14+
#
15+
# @parameter scheme [String] The URL scheme (e.g., "https", "http").
16+
# @parameter authority [String] The authority component (e.g., "example.com", "user@host:port").
17+
# @parameter path [String] The path component (defaults to "/").
18+
# @parameter query [String, nil] The query string.
19+
# @parameter fragment [String, nil] The fragment identifier.
1320
def initialize(scheme, authority, path = "/", query = nil, fragment = nil)
1421
@scheme = scheme
1522
@authority = authority
@@ -18,18 +25,25 @@ def initialize(scheme, authority, path = "/", query = nil, fragment = nil)
1825
super(path, query, fragment)
1926
end
2027

28+
# @attribute [String] The URL scheme.
2129
attr :scheme
30+
31+
# @attribute [String] The authority component.
2232
attr :authority
2333

34+
# Check if the URL has a non-empty scheme.
35+
#
36+
# @returns [Boolean] True if a scheme is present and non-empty.
2437
def scheme?
2538
@scheme and !@scheme.empty?
2639
end
2740

41+
# Check if the URL has a non-empty authority.
42+
#
43+
# @returns [Boolean] True if an authority is present and non-empty.
2844
def authority?
2945
@authority and !@authority.empty?
30-
end
31-
32-
# Combine this absolute URL with a relative reference according to RFC 3986 Section 5.
46+
end # Combine this absolute URL with a relative reference according to RFC 3986 Section 5.
3347
#
3448
# @parameter other [String, Relative, Reference, Absolute] The reference to resolve.
3549
# @returns [Absolute, String] The resolved absolute URL.
@@ -118,14 +132,24 @@ def with(scheme: @scheme, authority: @authority, path: nil, query: @query, fragm
118132
self.class.new(scheme, authority, Path.expand(@path, path, pop), query, fragment)
119133
end
120134

135+
# Convert the URL to an array representation.
136+
#
137+
# @returns [Array] An array of `[scheme, authority, path, query, fragment]`.
121138
def to_ary
122139
[@scheme, @authority, @path, @query, @fragment]
123140
end
124141

142+
# Compare this URL with another for sorting purposes.
143+
#
144+
# @parameter other [Absolute] The URL to compare with.
145+
# @returns [Integer] -1, 0, or 1 based on component-wise comparison.
125146
def <=>(other)
126147
to_ary <=> other.to_ary
127148
end
128149

150+
# Convert the URL to its string representation.
151+
#
152+
# @returns [String] The formatted absolute URL string.
129153
def to_s
130154
append
131155
end

lib/protocol/url/reference.rb

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,35 @@ module URL
1717
class Reference < Relative
1818
include Comparable
1919

20+
# Coerce a value into a {Reference} instance.
21+
#
22+
# This method provides flexible conversion from various types into a {Reference}.
23+
# When given a {String}, it parses the URL-encoded path, query, and fragment components
24+
# and unescapes them for internal storage. When given a {Relative}, it converts the
25+
# encoded values to unescaped form suitable for {Reference} instances.
26+
#
27+
# @parameter value [String | Relative | Nil] The value to coerce.
28+
# @parameter parameters [Hash | Nil] Optional user-supplied parameters to append to the query string.
29+
#
30+
# @returns [Reference | Nil] A new reference instance, or `nil` if the input is `nil`.
31+
#
32+
# @raises [ArgumentError] If the string contains whitespace or control characters.
33+
# @raises [ArgumentError] If the value cannot be coerced to a {Reference}.
34+
#
35+
# @example Coerce a string with path, query, and fragment.
36+
# reference = Reference["/search?q=ruby#results"]
37+
# reference.path # => "/search"
38+
# reference.query # => "q=ruby"
39+
# reference.fragment # => "results"
40+
#
41+
# @example Coerce with additional parameters.
42+
# reference = Reference["/search", {"limit" => "10"}]
43+
# reference.to_s # => "/search?limit=10"
44+
#
45+
# @example Coerce a Relative instance.
46+
# relative = Relative.new("/path%20with%20spaces", nil, "top")
47+
# reference = Reference[relative]
48+
# reference.path # => "/path with spaces"
2049
def self.[](value, parameters = nil)
2150
case value
2251
when String
@@ -25,7 +54,7 @@ def self.[](value, parameters = nil)
2554
query = match[:query]
2655
fragment = match[:fragment]
2756

28-
# Unescape path and fragment for user-friendly internal storage
57+
# Unescape path and fragment for user-friendly internal storage:
2958
# Query strings are kept as-is since they contain = and & syntax
3059
path = Encoding.unescape(path) if path && !path.empty?
3160
fragment = Encoding.unescape(fragment) if fragment
@@ -35,7 +64,7 @@ def self.[](value, parameters = nil)
3564
raise ArgumentError, "Invalid URL (contains whitespace or control characters): #{value.inspect}"
3665
end
3766
when Relative
38-
# Relative stores encoded values, so we need to unescape them for Reference
67+
# Relative stores encoded values, so we need to unescape them for Reference:
3968
path = value.path
4069
fragment = value.fragment
4170

lib/protocol/url/relative.rb

Lines changed: 91 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,29 @@ module URL
1212
class Relative
1313
include Comparable
1414

15+
# Initialize a new relative URL.
16+
#
17+
# @parameter path [String] The path component.
18+
# @parameter query [String, nil] The query string.
19+
# @parameter fragment [String, nil] The fragment identifier.
1520
def initialize(path, query = nil, fragment = nil)
1621
@path = path.to_s
1722
@query = query
1823
@fragment = fragment
1924
end
2025

26+
# @attribute [String] The path component of the URL.
2127
attr :path
28+
29+
# @attribute [String, nil] The query string component.
2230
attr :query
31+
32+
# @attribute [String, nil] The fragment identifier.
2333
attr :fragment
2434

35+
# Convert the URL path to a local filesystem path.
36+
#
37+
# @returns [String] The local filesystem path.
2538
def to_local_path
2639
Path.to_local_path(@path)
2740
end
@@ -131,45 +144,84 @@ def append(buffer = String.new)
131144
return buffer
132145
end
133146

134-
def to_ary
135-
[@path, @query, @fragment]
136-
end
137-
138-
def hash
139-
to_ary.hash
140-
end
141-
142-
def equal?(other)
143-
to_ary == other.to_ary
144-
end
145-
146-
def <=>(other)
147-
to_ary <=> other.to_ary
148-
end
149-
150-
def ==(other)
151-
to_ary == other.to_ary
152-
end
153-
154-
def ===(other)
155-
to_s === other
156-
end
157-
158-
def to_s
159-
append
160-
end
161-
162-
def as_json(...)
163-
to_s
164-
end
165-
166-
def to_json(...)
167-
as_json.to_json(...)
168-
end
169-
170-
def inspect
171-
"#<#{self.class} #{to_s}>"
172-
end
147+
return buffer
148+
end
149+
150+
# Convert the URL to an array representation.
151+
#
152+
# @returns [Array] An array of `[path, query, fragment]`.
153+
def to_ary
154+
[@path, @query, @fragment]
155+
end
156+
157+
# Compute a hash value for the URL based on its components.
158+
#
159+
# @returns [Integer] The hash value.
160+
def hash
161+
to_ary.hash
162+
end
163+
164+
# Check if this URL is equal to another URL by comparing components.
165+
#
166+
# @parameter other [Relative] The URL to compare with.
167+
# @returns [Boolean] True if the URLs have identical components.
168+
def equal?(other)
169+
to_ary == other.to_ary
170+
end
171+
172+
# Compare this URL with another for sorting purposes.
173+
#
174+
# @parameter other [Relative] The URL to compare with.
175+
# @returns [Integer] -1, 0, or 1 based on component-wise comparison.
176+
def <=>(other)
177+
to_ary <=> other.to_ary
178+
end
179+
180+
# Check structural equality by comparing components.
181+
#
182+
# @parameter other [Relative] The URL to compare with.
183+
# @returns [Boolean] True if the URLs have identical components.
184+
def ==(other)
185+
to_ary == other.to_ary
186+
end
187+
188+
# Check string equality, useful for case statements.
189+
#
190+
# @parameter other [String, Relative] The value to compare with.
191+
# @returns [Boolean] True if the string representations match.
192+
def ===(other)
193+
to_s === other
194+
end
195+
196+
# Convert the URL to its string representation.
197+
#
198+
# @returns [String] The formatted URL string.
199+
def to_s
200+
append
201+
end
202+
203+
# Convert the URL to a JSON-compatible representation.
204+
#
205+
# @returns [String] The URL as a string.
206+
def as_json(...)
207+
to_s
208+
end
209+
210+
# Convert the URL to JSON.
211+
#
212+
# @returns [String] The JSON-encoded URL.
213+
def to_json(...)
214+
as_json.to_json(...)
215+
end
216+
217+
# Generate a human-readable representation for debugging.
218+
#
219+
# @returns [String] A string like `#<Protocol::URL::Relative /path?query#fragment>`.
220+
def inspect
221+
"#<#{self.class} #{to_s}>"
222+
end
223+
end
224+
end
173225
end
174226
end
175227
end

0 commit comments

Comments
 (0)