Skip to content

Instantly share code, notes, and snippets.

@st0012
Last active February 14, 2020 10:40
Show Gist options
  • Save st0012/54d846701b6146c4491200ab6ae7258c to your computer and use it in GitHub Desktop.
Save st0012/54d846701b6146c4491200ab6ae7258c to your computer and use it in GitHub Desktop.
module URLHelper
IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/
HOST_REGEXP = /(^[^:]+:\/\/)?(\[[^\]]+\]|[^:]+)(?::(\d+$))?/
PROTOCOL_REGEXP = /^([^:]+)(:)?(\/\/)?$/
class << self
def url_for(options)
if options[:only_path]
path_for options
else
full_url_for options
end
end
def full_url_for(options)
host = options[:host]
protocol = options[:protocol]
port = options[:port]
unless host
raise ArgumentError, "Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true"
end
build_host_url(host, port, protocol, options, path_for(options))
end
def path_for(options)
path = options[:script_name].to_s.chomp("/")
path << options[:path] if options.key?(:path)
add_trailing_slash(path) if options[:trailing_slash]
add_params(path, options[:params]) if options.key?(:params)
add_anchor(path, options[:anchor]) if options.key?(:anchor)
path
end
private
def add_params(path, params)
params = { params: params } unless params.is_a?(Hash)
params.reject! { |_, v| v.nil? }
query = params.to_query
path << "?#{query}" unless query.empty?
end
def add_anchor(path, anchor)
if anchor
path << "##{anchor}"
end
end
def extract_domain_from(host, tld_length)
host.split(".").last(2 + tld_length).join(".")
end
def build_host_url(host, port, protocol, options, path)
if match = host.match(HOST_REGEXP)
protocol ||= match[1] unless protocol == false
host = match[2]
port = match[3] unless options.key? :port
end
protocol = normalize_protocol protocol
host = normalize_host(host, options)
result = protocol.dup
result << host
normalize_port(port, protocol) { |normalized_port|
result << ":#{normalized_port}"
}
result.concat path
end
def named_host?(host)
!IP_HOST_REGEXP.match?(host)
end
def normalize_protocol(protocol)
case protocol
when nil
"http://"
when false, "//"
"//"
when PROTOCOL_REGEXP
"#{$1}://"
else
raise ArgumentError, "Invalid :protocol option: #{protocol.inspect}"
end
end
def normalize_host(_host, options)
return _host unless named_host?(_host)
tld_length = options[:tld_length] || @@tld_length
subdomain = options.fetch :subdomain, true
domain = options[:domain]
host = +""
if subdomain == true
return _host if domain.nil?
host << extract_subdomains_from(_host, tld_length).join(".")
elsif subdomain
host << subdomain
end
host << "." unless host.empty?
host << (domain || extract_domain_from(_host, tld_length))
host
end
def normalize_port(port, protocol)
return unless port
case protocol
when "//" then yield port
when "https://"
yield port unless port.to_i == 443
else
yield port unless port.to_i == 80
end
end
end
end
url = URLHelper.url_for(host: "www.ror.co.uk", subdomain: "api", tld_length: 2, path: "/shows", anchor: "title-1")
expected_url = "http://api.ror.co.uk/shows#title-1"
if url == expected_url
puts("It works :-)")
else
puts("Expect url to be #{expected_url}, got #{url}")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment