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
Public Class Methods
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
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
# 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
# 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
# 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
# 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
# File lib/berkeley_library/util/uris/appender.rb, line 62 def fragment fragment_elements.join end
# 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
# 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
# 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
# File lib/berkeley_library/util/uris/appender.rb, line 54 def in_fragment? state == :fragment end
# File lib/berkeley_library/util/uris/appender.rb, line 50 def in_query? state == :query end
# File lib/berkeley_library/util/uris/appender.rb, line 66 def path_elements @path_elements ||= [] end
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
# File lib/berkeley_library/util/uris/appender.rb, line 58 def query query_elements.join end
# 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
# 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
# File lib/berkeley_library/util/uris/appender.rb, line 144 def split_around(s, i) [s[0...i], s[(i + 1)..]] end
# 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
# 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
# File lib/berkeley_library/util/uris/appender.rb, line 46 def state @state ||= :path end