class BerkeleyLibrary::Util::URIs::Appender

Appends the specified paths to the path of the specified URI, removing any extraneous slashes, and builds a new URI with that path and the same scheme, host, query, fragment, etc. as the original.

Attributes

elements[R]
original_uri[R]

Public Class Methods

new(uri, *elements) click to toggle source

Creates and invokes a new {Appender}.

@param uri [URI, String] the original URI @param elements [Array<String, Symbol>] the URI elements to join. @raise URI::InvalidComponentError if appending the specified elements would create an invalid URI

# File lib/berkeley_library/util/uris/appender.rb, line 20
def initialize(uri, *elements)
  raise ArgumentError, 'uri cannot be nil' unless (@original_uri = URIs.uri_or_nil(uri))

  @elements = elements.map(&:to_s)
  @elements.each_with_index do |element, elem_index|
    next start_query_at(elem_index) if element.include?('?')
    next start_fragment_at(elem_index) if element.include?('#')

    add_element(element)
  end
end

Public Instance Methods

to_uri() click to toggle source

Returns the new URI.

@return [URI] a new URI appending the joined path elements. @raise URI::InvalidComponentError if appending the specified elements would create an invalid URI

# File lib/berkeley_library/util/uris/appender.rb, line 36
def to_uri
  original_uri.dup.tap do |new_uri|
    new_uri.path = Paths.join(original_uri.path, *path_elements)
    new_uri.query = query unless query_elements.empty?
    new_uri.fragment = fragment unless fragment_elements.empty?
  end
end

Private Instance Methods

add_element(e) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 99
def add_element(e)
  return fragment_elements << e if in_fragment?
  return query_elements << e if in_query? || (e.include?('&') && !query_elements.empty?)

  path_elements << e
end
err_query_after_fragment(elem_index) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 152
def err_query_after_fragment(elem_index)
  "#{elements[elem_index].inspect}: Query delimiter '?' cannot follow fragment delimeter '#'"
end
err_too_many_fragments(elem_index) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 156
def err_too_many_fragments(elem_index)
  "#{elements[elem_index].inspect}: URI already has a fragment: #{fragment.inspect}"
end
err_too_many_queries(elem_index) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 148
def err_too_many_queries(elem_index)
  "#{elements[elem_index].inspect}: URI already has a query string: #{query.inspect}"
end
fragment() click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 62
def fragment
  fragment_elements.join
end
fragment_elements() click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 74
def fragment_elements
  @fragment_elements ||= [].tap { |e| e << original_uri.fragment if original_uri.fragment }
end
handle_fragment_start(elem_index) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 129
def handle_fragment_start(elem_index)
  element = elements[elem_index]

  # if there's anything before the '#', we treat that excess as a path element,
  # or as a query element if there's a query
  excess, f_start = split_around(element, element.index('#'))

  fragment_elements << f_start
  if in_query?
    query_elements << excess
  else
    path_elements << excess
  end
end
handle_query_start(elem_index) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 106
def handle_query_start(elem_index)
  element = elements[elem_index]

  # if there's anything before the '?', we treat that excess as a path element
  excess, q_start = split_around(element, element.index('?'))
  q_start = push_fragment_start(elem_index, q_start)

  query_elements << q_start
  path_elements << excess
end
in_fragment?() click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 54
def in_fragment?
  state == :fragment
end
in_query?() click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 50
def in_query?
  state == :query
end
path_elements() click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 66
def path_elements
  @path_elements ||= []
end
push_fragment_start(elem_index, q_start) click to toggle source

if the fragment starts in the middle of this element, we keep the part before the fragment delimiter '#', and push the rest (w/'#') back onto the next element to be parsed in the next iteration

# File lib/berkeley_library/util/uris/appender.rb, line 120
def push_fragment_start(elem_index, q_start)
  return q_start unless (f_index = q_start.index('#'))

  next_index = elem_index + 1
  q_start, q_next = split_around(q_start, f_index)           # NOTE: this doesn't return the '#'
  elements[next_index] = "##{q_next}#{elements[next_index]}" #       so we prepend one here
  q_start
end
query() click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 58
def query
  query_elements.join
end
query_after_fragment?(elem_index) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 94
def query_after_fragment?(elem_index)
  e = elements[elem_index]
  e.index('?', e.index('#'))
end
query_elements() click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 70
def query_elements
  @query_elements ||= [].tap { |e| e << original_uri.query if original_uri.query }
end
split_around(s, i) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 144
def split_around(s, i)
  [s[0...i], s[(i + 1)..]]
end
start_fragment_at(elem_index) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 86
def start_fragment_at(elem_index)
  raise URI::InvalidComponentError, err_too_many_fragments(elem_index) unless fragment_elements.empty?
  raise URI::InvalidComponentError, err_query_after_fragment(elem_index) if query_after_fragment?(elem_index)

  handle_fragment_start(elem_index)
  @state = :fragment
end
start_query_at(elem_index) click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 78
def start_query_at(elem_index)
  raise URI::InvalidComponentError, err_query_after_fragment(elem_index) if in_fragment?
  raise URI::InvalidComponentError, err_too_many_queries(elem_index) unless query_elements.empty?

  handle_query_start(elem_index)
  @state = :query
end
state() click to toggle source
# File lib/berkeley_library/util/uris/appender.rb, line 46
def state
  @state ||= :path
end