1
0

url.rb 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. require 'uri'
  2. require 'pathname'
  3. module Docs
  4. class URL < URI::Generic
  5. PARSER = URI::Parser.new
  6. def initialize(*args)
  7. if args.empty?
  8. super(*Array.new(9))
  9. elsif args.length == 1 && args.first.is_a?(Hash)
  10. args.first.assert_valid_keys URI::Generic::COMPONENT
  11. super(*args.first.values_at(*URI::Generic::COMPONENT))
  12. else
  13. super
  14. end
  15. end
  16. def self.parse(url)
  17. return url if url.kind_of? self
  18. new(*PARSER.split(url), PARSER)
  19. end
  20. def self.join(*args)
  21. PARSER.join(*args)
  22. end
  23. def join(*args)
  24. self.class.join self, *args
  25. end
  26. def merge!(hash)
  27. return super unless hash.is_a? Hash
  28. hash.assert_valid_keys URI::Generic::COMPONENT
  29. hash.each_pair do |key, value|
  30. send "#{key}=", value
  31. end
  32. self
  33. end
  34. def merge(hash)
  35. return super unless hash.is_a? Hash
  36. dup.merge!(hash)
  37. end
  38. def origin
  39. if scheme && host
  40. origin = "#{scheme}://#{host}"
  41. origin.downcase!
  42. origin << ":#{port}" if port
  43. origin
  44. else
  45. nil
  46. end
  47. end
  48. def normalized_path
  49. path == '' ? '/' : path
  50. end
  51. def subpath_to(url, options = nil)
  52. url = self.class.parse(url)
  53. return unless origin == url.origin
  54. base = path
  55. dest = url.path
  56. if options && options[:ignore_case]
  57. base = base.downcase
  58. dest = dest.downcase
  59. end
  60. if base == dest
  61. ''
  62. elsif dest.start_with? File.join(base, '')
  63. url.path[(path.length)..-1]
  64. end
  65. end
  66. def subpath_from(url, options = nil)
  67. self.class.parse(url).subpath_to(self, options)
  68. end
  69. def contains?(url, options = nil)
  70. !!subpath_to(url, options)
  71. end
  72. def relative_path_to(url)
  73. url = self.class.parse(url)
  74. return unless origin == url.origin
  75. base_dir = Pathname.new(normalized_path)
  76. base_dir = base_dir.parent unless path.end_with? '/'
  77. dest = url.normalized_path
  78. dest_dir = Pathname.new(dest)
  79. if dest.end_with? '/'
  80. dest_dir.relative_path_from(base_dir).to_s.tap do |result|
  81. result << '/' if result != '.'
  82. end
  83. else
  84. dest_dir.parent.relative_path_from(base_dir).join(dest.split('/').last).to_s
  85. end
  86. end
  87. def relative_path_from(url)
  88. self.class.parse(url).relative_path_to(self)
  89. end
  90. end
  91. end