Module: Protocol::URL::Path
- Defined in:
- lib/protocol/url/path.rb
Overview
Represents a relative URL, which does not include a scheme or authority.
Class Method Summary collapse
- .expand(base, relative, pop = true) ⇒ Object
-
.join(components) ⇒ Object
Join the given path components into a single path.
-
.relative(target, from) ⇒ Object
Calculate the relative path from one absolute path to another.
-
.simplify(components) ⇒ Object
Simplify the given path components by resolving "." and "..".
-
.split(path) ⇒ Object
Split the given path into its components.
-
.to_local_path(path) ⇒ Object
Convert a URL path to a local file system path using the platform's file separator.
Class Method Details
.expand(base, relative, pop = true) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/protocol/url/path.rb', line 96 def self.(base, relative, pop = true) # Empty relative path means no change: return base if relative.nil? || relative.empty? components = split(base) # RFC2396 Section 5.2: # 6) a) All but the last segment of the base URI's path component is # copied to the buffer. In other words, any characters after the # last (right-most) slash character, if any, are excluded. if pop and components.last != ".." components.pop elsif components.last == "" components.pop end relative = relative.split("/", -1) if relative.first == "" components = relative else components.concat(relative) end return join(simplify(components)) end |
.join(components) ⇒ Object
Join the given path components into a single path.
45 46 47 |
# File 'lib/protocol/url/path.rb', line 45 def self.join(components) return components.join("/") end |
.relative(target, from) ⇒ Object
Calculate the relative path from one absolute path to another.
This is useful for generating relative URLs from one location to another, such as creating page-specific import maps or relative links.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/protocol/url/path.rb', line 138 def self.relative(target, from) target_components = split(target) from_components = split(from) # Remove the last component from 'from' to get the directory from_components = from_components[0...-1] if from_components.size > 0 # Find the common prefix common_length = 0 [target_components.size, from_components.size].min.times do |i| break if target_components[i] != from_components[i] common_length = i + 1 end # Calculate how many levels to go up up_levels = from_components.size - common_length # Build the relative path components relative_components = [".."] * up_levels + target_components[common_length..-1] return join(relative_components) end |
.simplify(components) ⇒ Object
Simplify the given path components by resolving "." and "..".
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/protocol/url/path.rb', line 61 def self.simplify(components) output = [] components.each_with_index do |component, index| if index == 0 && component == "" # Preserve leading slash: output << "" elsif component == "." # Handle current directory - trailing . means directory, preserve trailing slash: output << "" if index == components.size - 1 elsif component == "" && index != components.size - 1 # Ignore empty segments (multiple slashes) except at end - no-op. elsif component == ".." && output.last && output.last != ".." # Handle parent directory: go up one level if not at root: output.pop if output.last != "" # Trailing .. means directory, preserve trailing slash: output << "" if index == components.size - 1 else # Regular path component: output << component end end return output end |
.split(path) ⇒ Object
Split the given path into its components.
split("")=>[]split("/")=>["", ""]split("/a/b/c")=>["", "a", "b", "c"]split("a/b/c/")=>["a", "b", "c", ""]
29 30 31 |
# File 'lib/protocol/url/path.rb', line 29 def self.split(path) return path.split("/", -1) end |
.to_local_path(path) ⇒ Object
Convert a URL path to a local file system path using the platform's file separator.
This method splits the URL path on / characters, unescapes each component using
Encoding.unescape_path (which preserves encoded separators), then joins the
components using File.join.
Percent-encoded path separators (%2F for / and %5C for \) are NOT decoded,
preventing them from being interpreted as directory boundaries. This ensures that
URL path components map directly to file system path components.
182 183 184 185 186 187 188 189 190 191 |
# File 'lib/protocol/url/path.rb', line 182 def self.to_local_path(path) components = split(path) # Unescape each component, preserving encoded path separators components.map! do |component| Encoding.unescape_path(component) end return File.join(*components) end |