Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active November 22, 2022 14:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/e269335f63b154d2eac37a8251230d6b to your computer and use it in GitHub Desktop.
Save JoshCheek/e269335f63b154d2eac37a8251230d6b to your computer and use it in GitHub Desktop.
Split slashes in paths, but not URLs
def split_path(path)
slash = Regexp.escape File::SEPARATOR
match = path.match(%r~ # regex that is delimited by tildes so I can use slashes, quotes, backticks, etc in the comments
( # capture whatever the path_slash group matches
(?<path_slash> # a named group that matches slashes in paths, but not urls, eg will not match "http://example.com"
# don't match first slash in "://"
(?: # don't capture this group
(?<!:) # not preceeded by ":"
(?!#{slash}#{slash}) # not succeeded by "//" (we haven't matched the slash yet, so it's in front of the cursor)
)
# don't match second slash in "://"
(?<!:#{slash}) # not preceeded by ":/"
# match any number of slashes eg `File.split "a//b" # => ["a", "b"]`
(?:#{slash})+ # but don't capture them
)
)
(?= # make sure it's the last path slash (no more after it)
(?: # don't capture this group
(?!\g<path_slash>) # there is not a path slash in after the cursor
. # consume the next character
)* # 0 or more of these (eg can be the last thing in the string)
\z # and then the string ends
)
~xo) # x ignores whitespace and comments, o means it will onlly build the regex the first time it's evaluated
if !match
[".", path] # File.split "" # => [".", ""]
elsif match.pre_match.empty? && match.post_match.empty?
[slash, slash] # File.split "/" # => ["/", "/"]
elsif match.pre_match.empty?
[slash, match.post_match] # File.split "/a" # => ["/", "a"]
elsif match.post_match.empty?
split_path(match.pre_match) # File.split "a/b/" # => ["a", "b"]
else
[match.pre_match, match.post_match] # File.split "a/b" # => ["a", "b"]
end
end
def components_of(path)
dirname, basename = split_path path
return [basename] if basename == path
components_of(dirname) << basename
end
components_of "/a/b/c.rb"
# => ["/", "a", "b", "c.rb"]
components_of "./a/b//c.rb"
# => [".", "a", "b", "c.rb"]
components_of "http://example.com/some/path"
# => ["http://example.com", "some", "path"]
components_of "path/to////test/namespace_with_the_url_http://url1.com_in_it/test_with_url_http://url2.com_in_it"
# => ["path",
# "to",
# "test",
# "namespace_with_the_url_http://url1.com_in_it",
# "test_with_url_http://url2.com_in_it"]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment