require 'uri' require 'pathname' module Docs class URL < URI::Generic PARSER = URI::Parser.new def initialize(*args) if args.empty? super(*Array.new(9)) elsif args.length == 1 && args.first.is_a?(Hash) args.first.assert_valid_keys URI::Generic::COMPONENT super(*args.first.values_at(*URI::Generic::COMPONENT)) else super end end def self.parse(url) return url if url.kind_of? self new(*PARSER.split(url), PARSER) end def self.join(*args) PARSER.join(*args) end def join(*args) self.class.join self, *args end def merge!(hash) return super unless hash.is_a? Hash hash.assert_valid_keys URI::Generic::COMPONENT hash.each_pair do |key, value| send "#{key}=", value end self end def merge(hash) return super unless hash.is_a? Hash dup.merge!(hash) end def origin if scheme && host origin = "#{scheme}://#{host}" origin.downcase! origin << ":#{port}" if port origin else nil end end def normalized_path path == '' ? '/' : path end def subpath_to(url, options = nil) url = self.class.parse(url) return unless origin == url.origin base = path dest = url.path if options && options[:ignore_case] base = base.downcase dest = dest.downcase end if base == dest '' elsif dest.start_with? File.join(base, '') url.path[(path.length)..-1] end end def subpath_from(url, options = nil) self.class.parse(url).subpath_to(self, options) end def contains?(url, options = nil) !!subpath_to(url, options) end def relative_path_to(url) url = self.class.parse(url) return unless origin == url.origin base_dir = Pathname.new(normalized_path) base_dir = base_dir.parent unless path.end_with? '/' dest = url.normalized_path dest_dir = Pathname.new(dest) if dest.end_with? '/' dest_dir.relative_path_from(base_dir).to_s.tap do |result| result << '/' if result != '.' end else dest_dir.parent.relative_path_from(base_dir).join(::File.basename(dest)).to_s end end def relative_path_from(url) self.class.parse(url).relative_path_to(self) end end end