Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 24 additions & 9 deletions lib/utopia/path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -215,19 +215,34 @@ def -(other)
end

def simplify
result = absolute? ? [""] : []
components = []

@components.each do |bit|
if bit == ".."
result.pop
elsif bit != "." && bit != ""
result << bit
end
index = 0

if @components[0] == ""
components << ""
index += 1
end

result << "" if directory?
while index < @components.size
bit = @components[index]
if bit == "."
# No-op (ignore current directory)
elsif bit == "" && index != @components.size - 1
# No-op (ignore multiple slashes)
elsif bit == ".." && components.last && components.last != ".."
if components.last != ""
# We can go up one level:
components.pop
end
else
components << bit
end

index += 1
end

return self.class.new(result)
return self.class.new(components)
end

# Returns the first path component.
Expand Down
1 change: 1 addition & 0 deletions releases.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased

- Add agent context.
- Better simplification of relative paths, e.g. `../../foo` is not modified to `foo`.

## v2.30.1

Expand Down
56 changes: 56 additions & 0 deletions test/utopia/path.rb
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
expect(directory.to_directory).to be == directory
end
end

it "should start with the given path" do
path = Utopia::Path["/a/b/c/d/e"]

Expand Down Expand Up @@ -263,4 +264,59 @@

expect((output + short).simplify).to be == input
end

with "#simplify" do
it "doesn't remove leading .. from relative paths" do
path = Utopia::Path["../foo/bar"]
simplified = path.simplify

expect(simplified.components).to be == ["..", "foo", "bar"]
end

it "removes redundant .. from absolute paths" do
path = Utopia::Path["/foo/../../bar"]
simplified = path.simplify

expect(simplified.components).to be == ["", "bar"]
end

it "preserves excess .. for purely relative paths" do
# ../../foo cannot be reduced without a base; keep leading .. components
path = Utopia::Path["../../foo"]
simplified = path.simplify

expect(simplified.components).to be == ["..", "..", "foo"]
end

it "reduces relative paths only as far as components allow" do
# foo/../../bar -> ../bar (pop foo for first .., then keep remaining ..)
path = Utopia::Path["foo/../../bar"]
simplified = path.simplify

expect(simplified.components).to be == ["..", "bar"]
end

it "does not traverse above root for absolute paths" do
# /a/b/../../../c -> /c (ignore .. beyond root)
path = Utopia::Path["/a/b/../../../c"]
simplified = path.simplify

expect(simplified.components).to be == ["", "c"]
end

it "ignores leading .. at absolute root" do
# /../../c -> /c
path = Utopia::Path["/../../c"]
simplified = path.simplify

expect(simplified.components).to be == ["", "c"]
end

it "preserves trailing slash for directories after simplify" do
path = Utopia::Path["/a/./b/../c/"]
simplified = path.simplify

expect(simplified.components).to be == ["", "a", "c", ""]
end
end
end
Loading