lib/protocol/http/reference.rb in protocol-http-0.6.0 vs lib/protocol/http/reference.rb in protocol-http-0.7.0
- old
+ new
@@ -22,11 +22,11 @@
require_relative 'url'
module Protocol
module HTTP
- # A relative reference, excluding any authority.
+ # A relative reference, excluding any authority. The path part of an HTTP request.
class Reference
include Comparable
# Generate a reference from a path and user parameters. The path may contain a `#fragment` or `?query=parameters`.
def self.parse(path = '/', parameters = nil)
@@ -114,62 +114,86 @@
append(String.new)
end
alias to_s to_str
+ # Merges two references as specified by RFC2396, similar to `URI.join`.
def + other
other = self.class[other]
self.class.new(
- expand_path(self.path, other.path),
+ expand_path(self.path, other.path, true),
other.query_string,
other.fragment,
other.parameters,
)
end
- def dup(path = nil, parameters = nil, merge = true)
- if merge and @parameters
+ # Just the base path, without any query string, parameters or fragment.
+ def base
+ self.class.new(@path, nil, nil, nil)
+ end
+
+ # @option path [String] Append the string to this reference similar to `File.join`.
+ # @option parameters [Hash] Append the parameters to this reference.
+ # @option fragment [String] Set the fragment to this value.
+ def with(path: nil, parameters: nil, fragment: @fragment)
+ if @parameters
if parameters
parameters = @parameters.merge(parameters)
else
parameters = @parameters
end
end
if path
- path = expand_path(@path, path)
+ path = expand_path(@path, path, false)
else
path = @path
end
- self.class.new(path, @query_string, @fragment, parameters)
+ self.class.new(path, @query_string, fragment, parameters)
end
+ # The arguments to this function are legacy, prefer to use `with`.
+ def dup(path = nil, parameters = nil, merge_parameters = true)
+ if merge_parameters
+ with(path: path, parameters: parameters)
+ else
+ self.base.with(path: path, parameters: parameters)
+ end
+ end
+
private
def split(path)
if path.empty?
[path]
else
path.split('/', -1)
end
end
- def expand_path(base, relative)
+ # @param pop [Boolean] whether to remove the last path component of the base path, to conform to URI merging behaviour, as defined by RFC2396.
+ def expand_path(base, relative, pop = true)
if relative.start_with? '/'
return relative
else
path = split(base)
- # drop the last path element for relative computations, e.g.
- # /foo/bar/index.html -> /foo/bar/#{relative}
- path.pop
+ # 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.
+ path.pop if pop or path.last == ''
+
parts = split(relative)
parts.each do |part|
if part == '..'
path.pop
+ elsif part == '.'
+ # Do nothing.
else
path << part
end
end