Class: Protocol::URL::Relative

Inherits:
Object
  • Object
show all
Includes:
Comparable
Defined in:
lib/protocol/url/relative.rb

Overview

Represents a relative URL, which does not include a scheme or authority.

Direct Known Subclasses

Absolute, Reference

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, query = nil, fragment = nil) ⇒ Relative

Initialize a new relative URL.



20
21
22
23
24
# File 'lib/protocol/url/relative.rb', line 20

def initialize(path, query = nil, fragment = nil)
	@path = Path[path]
	@query = query
	@fragment = fragment
end

Instance Attribute Details

#fragmentObject

Returns the value of attribute fragment.



52
53
54
# File 'lib/protocol/url/relative.rb', line 52

def fragment
  @fragment
end

#pathObject

Returns the value of attribute path.



39
40
41
# File 'lib/protocol/url/relative.rb', line 39

def path
  @path
end

#queryObject

Returns the value of attribute query.



49
50
51
# File 'lib/protocol/url/relative.rb', line 49

def query
  @query
end

#The fragment identifier.(fragmentidentifier.) ⇒ Object (readonly)



52
# File 'lib/protocol/url/relative.rb', line 52

attr_accessor :fragment

#The query string component.(querystringcomponent.) ⇒ Object (readonly)



49
# File 'lib/protocol/url/relative.rb', line 49

attr_accessor :query

Instance Method Details

#+(other) ⇒ Object

Combine this relative URL with another URL or path.

Examples:

Combine two relative paths.

base = Relative.new("/documents/reports/")
other = Relative.new("invoices/2024.pdf")
result = base + other
result.path.to_s  # => "/documents/reports/invoices/2024.pdf"

Navigate to parent directory.

base = Relative.new("/documents/reports/archive/")
other = Relative.new("../../summary.pdf")
result = base + other
result.path.to_s  # => "/documents/summary.pdf"


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/protocol/url/relative.rb', line 91

def +(other)
	case other
	when Absolute
		# Relative + Absolute: the absolute URL takes precedence
		# You can't apply relative navigation to an absolute URL
		other
	when Relative
		# Relative + Relative: merge paths directly
		self.class.new(
			@path.join(other.path),
			other.query,
			other.fragment
		)
	when String
		# Relative + String: parse and combine
		self + URL[other]
	else
		raise ArgumentError, "Cannot combine Relative URL with #{other.class}"
	end
end

#<=>(other) ⇒ Object

Compare this URL with another for sorting purposes.



196
197
198
# File 'lib/protocol/url/relative.rb', line 196

def <=>(other)
	to_ary <=> other.to_ary
end

#==(other) ⇒ Object

Check structural equality by comparing components.



204
205
206
# File 'lib/protocol/url/relative.rb', line 204

def ==(other)
	to_ary == other.to_ary
end

#===(other) ⇒ Object

Check string equality, useful for case statements.



212
213
214
# File 'lib/protocol/url/relative.rb', line 212

def ===(other)
	to_s === other
end

#append(buffer = String.new) ⇒ Object

Append the relative URL to the given buffer. The path, query, and fragment are expected to already be properly encoded.



156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/protocol/url/relative.rb', line 156

def append(buffer = String.new)
	buffer << @path.encoded
	
	if @query and !@query.empty?
		buffer << "?" << @query
	end
	
	if @fragment and !@fragment.empty?
		buffer << "#" << @fragment
	end
	
	return buffer
end

#as_jsonObject

Convert the URL to a JSON-compatible representation.



226
227
228
# File 'lib/protocol/url/relative.rb', line 226

def as_json(...)
	to_s
end

#equal?(other) ⇒ Boolean

Check if this URL is equal to another URL by comparing components.

Returns:

  • (Boolean)


188
189
190
# File 'lib/protocol/url/relative.rb', line 188

def equal?(other)
	to_ary == other.to_ary
end

#fragment?Boolean

Returns:

  • (Boolean)


71
72
73
# File 'lib/protocol/url/relative.rb', line 71

def fragment?
	@fragment and !@fragment.empty?
end

#freezeObject

Freeze the URL and its direct components.



28
29
30
31
32
33
34
35
36
# File 'lib/protocol/url/relative.rb', line 28

def freeze
	return self if frozen?
	
	@path.freeze
	@query.freeze
	@fragment.freeze
	
	return super
end

#hashObject

Compute a hash value for the URL based on its components.



180
181
182
# File 'lib/protocol/url/relative.rb', line 180

def hash
	to_ary.hash
end

#inspectObject

Generate a human-readable representation for debugging.



240
241
242
# File 'lib/protocol/url/relative.rb', line 240

def inspect
	"#<#{self.class} #{to_s}>"
end

#local_path(root) ⇒ Object Also known as: to_local_path

Resolve the URL path beneath a local filesystem root.



59
60
61
# File 'lib/protocol/url/relative.rb', line 59

def local_path(root)
	@path.local_path(root)
end

#normalize!Object

Normalize the path by resolving "." and ".." segments and removing duplicate slashes.

This modifies the URL in-place by simplifying the path component:

  • Removes "." segments (current directory)
  • Resolves ".." segments (parent directory)
  • Collapses multiple consecutive slashes to single slashes (except at start)

Examples:

Basic normalization

url = Relative.new("/foo//bar/./baz/../qux")
url.normalize!
url.path.to_s  # => "/foo/bar/qux"


148
149
150
151
152
# File 'lib/protocol/url/relative.rb', line 148

def normalize!
	@path = @path.simplify
	
	return self
end

#query?Boolean

Returns:

  • (Boolean)


66
67
68
# File 'lib/protocol/url/relative.rb', line 66

def query?
	@query and !@query.empty?
end

#The path component of the URL.=(pathcomponentoftheURL. = (value)) ⇒ Object



39
# File 'lib/protocol/url/relative.rb', line 39

attr :path

#to_aryObject

Convert the URL to an array representation.



173
174
175
# File 'lib/protocol/url/relative.rb', line 173

def to_ary
	[@path, @query, @fragment]
end

#to_jsonObject

Convert the URL to JSON.



233
234
235
# File 'lib/protocol/url/relative.rb', line 233

def to_json(...)
	as_json.to_json(...)
end

#to_sObject

Convert the URL to its string representation.



219
220
221
# File 'lib/protocol/url/relative.rb', line 219

def to_s
	append
end

#with(path: nil, query: @query, fragment: @fragment, pop: true) ⇒ Object

Create a new Relative URL with modified components.

Examples:

Update the query string.

url = Relative.new("/search", "query=ruby")
updated = url.with(query: "query=python")
updated.to_s  # => "/search?query=python"

Append to the path.

url = Relative.new("/documents/")
updated = url.with(path: "report.pdf", pop: false)
updated.to_s  # => "/documents/report.pdf"


129
130
131
132
133
# File 'lib/protocol/url/relative.rb', line 129

def with(path: nil, query: @query, fragment: @fragment, pop: true)
	path = @path.join(path, pop: pop) unless path.nil?
	
	self.class.new(path || @path, query, fragment)
end