Skip to content

Commit

Permalink
Fix double slashes bug (#15)
Browse files Browse the repository at this point in the history
**Background**:
Parsing a URL with a trailing slash and then joining paths onto it
resulted in double slashes.
Example:
```rb
URL.parse("https://example.com/").join("path").to_s 
# => "https://example.com//path
```

Parsing `nil` would throw a `NoMethodError` for `to_str`.
Example:
```rb
URL.parse(nil)
# qasa-url/lib/url.rb:63:in `parse': undefined method `to_str' for nil (NoMethodError)
```

**Notable changes:**
- Refactor `#join` so that double slashes don't occur when parsing a URL
with a trailing slash
- Refactor `::parse` to return `nil` when given `nil`
  • Loading branch information
ingemar authored Jan 10, 2025
1 parent b9a0cc5 commit 5f337e5
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## [0.1.1]
- Fixed a bug where a parsed URL ending with a slash would result in double slashes after the hostname when joined with additional paths.
- Fixed bug when `URL.parse` with `nil` was rasing an arrer. Now it returns `nil`.

## [0.1.0]
- Initial release

Expand Down
2 changes: 1 addition & 1 deletion lib/qasa/url/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

module Qasa
module Url
VERSION = "0.1.0"
VERSION = "0.1.1"
end
end
28 changes: 23 additions & 5 deletions lib/url.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class << self
# URL.parse("https://www.example.com:3000/path?query=string")
# # => #<URL:0x00007f9b9c0b3b20 https://www.example.com:3000/path?query=string>
def parse(string)
return nil if string.nil?

string
.to_str
.dup
Expand Down Expand Up @@ -141,12 +143,21 @@ def path=(path)
# url = URL.parse("https://www.example.com")
# url.join("path").path("to", "nowhere")
# url.to_s # => "https://www.example.com/path/to/nowhere"
# @example
# url = URL.parse("https://www.example.com/")
# url.join("/path", "/to/", "nowhere/")
# url.to_s # => "https://www.example.com/path/to/nowhere/"
def join(*paths)
paths.map do |path|
path.start_with?(SLASH) ? path.sub(SLASH, NOTHING) : path.dup
end.then do |paths|
self.path = Array(path).concat(paths).join(SLASH)
end
parts = Array(path).concat(paths)
size = parts.size

parts
.map
.with_index(1) { |part, index| sanitize_path(part, last: index == size) }
.compact
.then do |parts|
self.path = Array(NOTHING).concat(parts).join(SLASH)
end

self
end
Expand Down Expand Up @@ -293,4 +304,11 @@ def deep_transform_keys(hash)
def domain_parts
host.split(DOT)
end

def sanitize_path(path, last:)
path = path.start_with?(SLASH) ? path[1..] : path.dup
path = path.end_with?(SLASH) ? path[..-2] : path unless last

path.empty? ? nil : path
end
end
30 changes: 30 additions & 0 deletions test/url_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ class URLTest < Minitest::Test

assert_nil result
end

it "returns nil if given nil" do
result = URL.parse(nil)

assert_nil result
end
end

describe "#join" do
Expand Down Expand Up @@ -65,6 +71,30 @@ class URLTest < Minitest::Test
assert_equal "/path/to/nowhere", url.path
end

it "does not double slash the path if the parsed URL ends with a slash" do
url = URL.parse("http://www.example.com/")

url.join("/path")

assert_equal "http://www.example.com/path", url.to_s
end

it "does not double slash the path if the parsed URL ends with a slash" do
url = URL.parse("http://www.example.com")

url.join("/path", "/to/", "nowhere")

assert_equal "http://www.example.com/path/to/nowhere", url.to_s
end

it "doesn not remove a trailing slash" do
url = URL.parse("http://www.example.com/")

url.join("path", "to", "nowhere/")

assert_equal "http://www.example.com/path/to/nowhere/", url.to_s
end

it "returns self" do
url = URL.parse("http://www.example.com")

Expand Down

0 comments on commit 5f337e5

Please sign in to comment.