@@ -33,9 +33,7 @@ def +(other)
3333 # Protocol-relative URL: inherit scheme from base:
3434 return Absolute . new ( @scheme , other . authority , other . path , other . query , other . fragment )
3535 when Relative
36- # Already a Relative, use directly:
37- when Reference
38- other = Relative . new ( other . path , other . query , other . fragment )
36+ # Already a Relative, use directly.
3937 when String
4038 other = URL [ other ]
4139 # If parsing resulted in an Absolute URL, handle it:
@@ -61,14 +59,10 @@ def +(other)
6159 # Fragment-only: keep everything from base, just change fragment:
6260 Absolute . new ( @scheme , @authority , @path , @query , other . fragment || @fragment )
6361 end
64- elsif other . path . start_with? ( "/" )
65- # Absolute path: use base scheme+authority with new path:
66- Absolute . new ( @scheme , @authority , normalize_path ( other . path ) , other . query , other . fragment )
6762 else
6863 # Relative path: merge with base path:
69- merged_path = merge_paths ( @path , other . path )
70- normalized_path = normalize_path ( merged_path )
71- Absolute . new ( @scheme , @authority , normalized_path , other . query , other . fragment )
64+ path = Path . expand ( @path , other . path )
65+ Absolute . new ( @scheme , @authority , path , other . query , other . fragment )
7266 end
7367 end
7468
@@ -82,64 +76,6 @@ def append(buffer = String.new)
8276 def to_s
8377 append
8478 end
85-
86- def absolute?
87- true
88- end
89-
90- def relative?
91- false
92- end
93-
94- private
95-
96- # Merge a base path with a relative path according to RFC 3986 Section 5.2.3
97- def merge_paths ( base , relative )
98- # If base has authority and empty path, use "/" + relative
99- if @authority && !@authority . empty? && base . empty?
100- return "/" + relative
101- end
102-
103- # Otherwise, remove everything after the last "/" in base and append relative
104- if base . include? ( "/" )
105- base . sub ( /\/ [^\/ ]*\z / , "/" ) + relative
106- else
107- relative
108- end
109- end
110-
111- # Remove dot-segments from a path according to RFC 3986 Section 5.2.4
112- def normalize_path ( path )
113- # Remember if path starts with "/" (absolute path)
114- absolute = path . start_with? ( "/" )
115- # Remember if path ends with "/" or "/." or "/.."
116- trailing_slash = path . end_with? ( "/" ) || path . end_with? ( "/." ) || path . end_with? ( "/.." )
117-
118- output = [ ]
119- input = path . split ( "/" , -1 )
120-
121- input . each do |segment |
122- if segment == ".."
123- # Go up one level (pop), but not beyond root
124- output . pop unless output . empty? || ( absolute && output . size == 1 && output . first == "" )
125- elsif segment != "." && segment != ""
126- # Keep all segments except "." and empty
127- output << segment
128- end
129- end
130-
131- # For absolute paths, ensure we start with /
132- if absolute
133- result = "/" + output . join ( "/" )
134- else
135- result = output . join ( "/" )
136- end
137-
138- # Add trailing slash if original had one or ended with dot-segments
139- result += "/" if trailing_slash && !result . end_with? ( "/" )
140-
141- result
142- end
14379 end
14480 end
14581end
0 commit comments