Class: Utopia::Path
- Inherits:
-
Object
- Object
- Utopia::Path
- Includes:
- Comparable
- Defined in:
- lib/utopia/path.rb,
lib/utopia/path/matcher.rb
Overview
Represents a path as an array of path components. Useful for efficient URL manipulation.
Defined Under Namespace
Classes: Matcher
Constant Summary collapse
- SEPARATOR =
'/'
Instance Attribute Summary collapse
-
#components ⇒ Object
Returns the value of attribute components.
Class Method Summary collapse
- .[](path) ⇒ Object
- .create(path) ⇒ Object
- .dump(instance) ⇒ Object
-
.from_string(string) ⇒ Object
This constructor takes a string and generates a relative path as efficiently as possible.
- .load(value) ⇒ Object
-
.prefix_length(a, b) ⇒ Object
Returns the length of the prefix which is shared by two strings.
- .root ⇒ Object
-
.shortest_path(path, root) ⇒ Object
Return the shortest relative path to get to path from root:.
- .split(path) ⇒ Object
-
.unescape(string) ⇒ Object
Converts ‘+’ into whitespace and hex encoded characters into their equivalent characters.
Instance Method Summary collapse
- #+(other) ⇒ Object
-
#-(other) ⇒ Object
Computes the difference of the path.
- #<=>(other) ⇒ Object
- #==(other) ⇒ Object
- #[](index) ⇒ Object
-
#[]=(index, value) ⇒ Object
Replaces a named component, indexing as per.
- #absolute? ⇒ Boolean
- #ascend(&block) ⇒ Object
-
#basename ⇒ String
The last path component without any file extension.
- #delete_at(index) ⇒ Object
- #descend(&block) ⇒ Object
- #directory? ⇒ Boolean
- #dirname(count = 1) ⇒ Object
- #dup ⇒ Object
- #empty? ⇒ Boolean
- #eql?(other) ⇒ Boolean
- #expand(root) ⇒ Object
-
#extension ⇒ String
The last path component’s file extension.
- #file? ⇒ Boolean (also: #last?)
-
#first ⇒ Object
Returns the first path component.
- #freeze ⇒ Object
- #hash ⇒ Object
- #include?(*arguments) ⇒ Boolean
-
#initialize(components = []) ⇒ Path
constructor
A new instance of Path.
- #join(other) ⇒ Object
-
#last ⇒ Object
Returns the last path component.
- #local_path(separator = File::SEPARATOR) ⇒ Object
-
#pop ⇒ Object
Pops the last path component.
- #relative? ⇒ Boolean
- #replace(other_path) ⇒ Object
- #shortest_path(root) ⇒ Object
- #simplify ⇒ Object
- #split(at) ⇒ Object
- #start_with?(other) ⇒ Boolean
- #to_a ⇒ Object
- #to_absolute ⇒ Object
- #to_directory ⇒ Object
- #to_relative! ⇒ Object
- #to_str ⇒ Object (also: #to_s)
- #with_prefix(*arguments) ⇒ Object
Constructor Details
#initialize(components = []) ⇒ Path
Returns a new instance of Path.
13 14 15 |
# File 'lib/utopia/path.rb', line 13 def initialize(components = []) @components = components end |
Instance Attribute Details
#components ⇒ Object
Returns the value of attribute components.
17 18 19 |
# File 'lib/utopia/path.rb', line 17 def components @components end |
Class Method Details
.[](path) ⇒ Object
65 66 67 |
# File 'lib/utopia/path.rb', line 65 def self.[] path self.create(path) end |
.create(path) ⇒ Object
95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/utopia/path.rb', line 95 def self.create(path) case path when Path return path when Array return self.new(path) when String return self.new(unescape(path).split(SEPARATOR, -1)) when nil return nil else return self.new([path]) end end |
.dump(instance) ⇒ Object
91 92 93 |
# File 'lib/utopia/path.rb', line 91 def self.dump(instance) instance.to_s if instance end |
.from_string(string) ⇒ Object
This constructor takes a string and generates a relative path as efficiently as possible. This is a direct entry point for all controller invocations so it’s designed to suit the requirements of that function.
83 84 85 |
# File 'lib/utopia/path.rb', line 83 def self.from_string(string) self.new(unescape(string).split(SEPARATOR, -1)) end |
.load(value) ⇒ Object
87 88 89 |
# File 'lib/utopia/path.rb', line 87 def self.load(value) from_string(value) if value end |
.prefix_length(a, b) ⇒ Object
Returns the length of the prefix which is shared by two strings.
36 37 38 |
# File 'lib/utopia/path.rb', line 36 def self.prefix_length(a, b) [a.size, b.size].min.times{|i| return i if a[i] != b[i]} end |
.root ⇒ Object
31 32 33 |
# File 'lib/utopia/path.rb', line 31 def self.root self.new(['']) end |
.shortest_path(path, root) ⇒ Object
Return the shortest relative path to get to path from root:
41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/utopia/path.rb', line 41 def self.shortest_path(path, root) path = self.create(path) root = self.create(root).dirname # Find the common prefix: i = prefix_length(path.components, root.components) || 0 # The difference between the root path and the required path, taking into account the common prefix: up = root.components.size - i return self.create([".."] * up + path.components[i..-1]) end |
.split(path) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/utopia/path.rb', line 69 def self.split(path) case path when Path return path.to_a when Array return path when String create(path).to_a else [path] end end |
.unescape(string) ⇒ Object
Converts ‘+’ into whitespace and hex encoded characters into their equivalent characters.
59 60 61 62 63 |
# File 'lib/utopia/path.rb', line 59 def self.unescape(string) string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) { [$1.delete('%')].pack('H*') } end |
Instance Method Details
#+(other) ⇒ Object
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/utopia/path.rb', line 182 def +(other) if other.kind_of? Path if other.absolute? return other else return join(other.components) end elsif other.kind_of? Array return join(other) elsif other.kind_of? String return join(other.split(SEPARATOR, -1)) else return join([other.to_s]) end end |
#-(other) ⇒ Object
Computes the difference of the path. /a/b/c - /a/b -> c a/b/c - a/b -> c
205 206 207 208 209 210 211 212 213 214 215 |
# File 'lib/utopia/path.rb', line 205 def -(other) i = 0 while i < other.components.size break if @components[i] != other.components[i] i += 1 end return self.class.new(@components[i,@components.size]) end |
#<=>(other) ⇒ Object
323 324 325 |
# File 'lib/utopia/path.rb', line 323 def <=> other @components <=> other.components end |
#==(other) ⇒ Object
335 336 337 338 339 340 341 342 343 |
# File 'lib/utopia/path.rb', line 335 def == other return false unless other case other when String then self.to_s == other when Array then self.to_a == other else other.is_a?(self.class) && @components == other.components end end |
#[](index) ⇒ Object
353 354 355 |
# File 'lib/utopia/path.rb', line 353 def [] index return @components[component_offset(index)] end |
#[]=(index, value) ⇒ Object
Replaces a named component, indexing as per
358 359 360 |
# File 'lib/utopia/path.rb', line 358 def []= index, value return @components[component_offset(index)] = value end |
#absolute? ⇒ Boolean
138 139 140 |
# File 'lib/utopia/path.rb', line 138 def absolute? @components.first == '' end |
#ascend(&block) ⇒ Object
295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/utopia/path.rb', line 295 def ascend(&block) return to_enum(:ascend) unless block_given? components = self.components.dup while components.any? yield self.class.new(components.dup) components.pop end end |
#basename ⇒ String
Returns the last path component without any file extension.
260 261 262 263 264 |
# File 'lib/utopia/path.rb', line 260 def basename basename, _ = @components.last.split('.', 2) return basename || '' end |
#delete_at(index) ⇒ Object
362 363 364 |
# File 'lib/utopia/path.rb', line 362 def delete_at(index) @components.delete_at(component_offset(index)) end |
#descend(&block) ⇒ Object
283 284 285 286 287 288 289 290 291 292 293 |
# File 'lib/utopia/path.rb', line 283 def descend(&block) return to_enum(:descend) unless block_given? components = [] @components.each do |component| components << component yield self.class.new(components.dup) end end |
#directory? ⇒ Boolean
118 119 120 |
# File 'lib/utopia/path.rb', line 118 def directory? return @components.last == '' end |
#dirname(count = 1) ⇒ Object
273 274 275 276 277 |
# File 'lib/utopia/path.rb', line 273 def dirname(count = 1) path = self.class.new(@components[0...-count]) return absolute? ? path.to_absolute : path end |
#dup ⇒ Object
319 320 321 |
# File 'lib/utopia/path.rb', line 319 def dup return Path.new(components.dup) end |
#empty? ⇒ Boolean
27 28 29 |
# File 'lib/utopia/path.rb', line 27 def empty? @components.empty? end |
#eql?(other) ⇒ Boolean
327 328 329 |
# File 'lib/utopia/path.rb', line 327 def eql? other self.class.eql?(other.class) and @components.eql?(other.components) end |
#extension ⇒ String
Returns the last path component’s file extension.
267 268 269 270 271 |
# File 'lib/utopia/path.rb', line 267 def extension _, extension = @components.last.split('.', 2) return extension end |
#file? ⇒ Boolean Also known as: last?
122 123 124 |
# File 'lib/utopia/path.rb', line 122 def file? return @components.last != '' end |
#first ⇒ Object
Returns the first path component.
234 235 236 237 238 239 240 |
# File 'lib/utopia/path.rb', line 234 def first if absolute? @components[1] else @components[0] end end |
#freeze ⇒ Object
19 20 21 22 23 24 25 |
# File 'lib/utopia/path.rb', line 19 def freeze return self if frozen? @components.freeze super end |
#hash ⇒ Object
331 332 333 |
# File 'lib/utopia/path.rb', line 331 def hash @components.hash end |
#include?(*arguments) ⇒ Boolean
114 115 116 |
# File 'lib/utopia/path.rb', line 114 def include?(*arguments) @components.include?(*arguments) end |
#join(other) ⇒ Object
169 170 171 172 173 174 175 176 |
# File 'lib/utopia/path.rb', line 169 def join(other) # Check whether other is an absolute path: if other.first == '' self.class.new(other) else self.class.new(@components + other).simplify end end |
#last ⇒ Object
Returns the last path component.
243 244 245 246 247 |
# File 'lib/utopia/path.rb', line 243 def last if @components != [''] @components.last end end |
#local_path(separator = File::SEPARATOR) ⇒ Object
279 280 281 |
# File 'lib/utopia/path.rb', line 279 def local_path(separator = File::SEPARATOR) @components.join(separator) end |
#pop ⇒ Object
Pops the last path component.
252 253 254 255 256 257 |
# File 'lib/utopia/path.rb', line 252 def pop # We don't want to convert an absolute path to a relative path. if @components != [''] @components.pop end end |
#relative? ⇒ Boolean
134 135 136 |
# File 'lib/utopia/path.rb', line 134 def relative? @components.first != '' end |
#replace(other_path) ⇒ Object
110 111 112 |
# File 'lib/utopia/path.rb', line 110 def replace(other_path) @components = other_path.components.dup end |
#shortest_path(root) ⇒ Object
54 55 56 |
# File 'lib/utopia/path.rb', line 54 def shortest_path(root) self.class.shortest_path(self, root) end |
#simplify ⇒ Object
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/utopia/path.rb', line 217 def simplify result = absolute? ? [''] : [] @components.each do |bit| if bit == ".." result.pop elsif bit != "." && bit != '' result << bit end end result << '' if directory? return self.class.new(result) end |
#split(at) ⇒ Object
307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/utopia/path.rb', line 307 def split(at) if at.kind_of?(String) at = @components.index(at) end if at return [self.class.new(@components[0...at]), self.class.new(@components[at+1..-1])] else return nil end end |
#start_with?(other) ⇒ Boolean
345 346 347 348 349 350 351 |
# File 'lib/utopia/path.rb', line 345 def start_with? other other.components.each_with_index do |part, index| return false if @components[index] != part end return true end |
#to_a ⇒ Object
164 165 166 |
# File 'lib/utopia/path.rb', line 164 def to_a @components end |
#to_absolute ⇒ Object
142 143 144 145 146 147 148 |
# File 'lib/utopia/path.rb', line 142 def to_absolute if absolute? return self else return self.class.new([''] + @components) end end |
#to_directory ⇒ Object
126 127 128 129 130 131 132 |
# File 'lib/utopia/path.rb', line 126 def to_directory if directory? return self else return self.class.new(@components + ['']) end end |
#to_relative! ⇒ Object
150 151 152 |
# File 'lib/utopia/path.rb', line 150 def to_relative! @components.shift if relative? end |
#to_str ⇒ Object Also known as: to_s
154 155 156 157 158 159 160 |
# File 'lib/utopia/path.rb', line 154 def to_str if @components == [''] SEPARATOR else @components.join(SEPARATOR) end end |
#with_prefix(*arguments) ⇒ Object
198 199 200 |
# File 'lib/utopia/path.rb', line 198 def with_prefix(*arguments) self.class.create(*arguments) + self end |