Class: Gitable::URI

Inherits:
Addressable::URI
  • Object
show all
Defined in:
lib/gitable/uri.rb

Direct Known Subclasses

ScpURI

Constant Summary collapse

SCP_REGEXP =
%r|^([^:/?#]+):([^:?#]*)$|
URIREGEX =
%r|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$|

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.heuristic_parse(uri) ⇒ Gitable::URI?

Attempts to make a copied URL bar into a git repository URI.

First line of defense is for URIs without .git as a basename:

  • Change the scheme from http:// to git://

  • Add .git to the basename

Parameters:

  • uri (Addressable::URI, #to_str)

    URI of a git repository.

Returns:

  • (Gitable::URI, nil)

    the URI object or nil if nil was passed in.

Raises:

  • (TypeError)

    The uri must respond to #to_str.

  • (Gitable::URI::InvalidURIError)

    When the uri is total rubbish.



94
95
96
97
98
99
100
101
102
103
104
# File 'lib/gitable/uri.rb', line 94

def self.heuristic_parse(uri)
  return uri if uri.nil? || uri.kind_of?(self)

  # Addressable::URI.heuristic_parse _does_ return the correct type :)
  gitable = super # boo inconsistency

  if gitable.github? || gitable.bitbucket?
    gitable.extname = "git"
  end
  gitable
end

.parse(uri) ⇒ Gitable::URI?

Parse a git repository URI into a URI object.

Parameters:

  • uri (Addressable::URI, #to_str)

    URI of a git repository.

Returns:

  • (Gitable::URI, nil)

    the URI object or nil if nil was passed in.

Raises:

  • (TypeError)

    The uri must respond to #to_str.

  • (Gitable::URI::InvalidURIError)

    When the uri is total rubbish.



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/gitable/uri.rb', line 18

def self.parse(uri)
  return nil if uri.nil?
  return uri.dup if uri.kind_of?(self)

  # Copied from Addressable to speed up our parsing.
  #
  # If a URI object of the Ruby standard library variety is passed,
  # convert it to a string, then parse the string.
  # We do the check this way because we don't want to accidentally
  # cause a missing constant exception to be thrown.
  if uri.class.name =~ /^URI\b/
    uri = uri.to_s
  end

  # Otherwise, convert to a String
  begin
    uri = uri.to_str
  rescue TypeError, NoMethodError
    raise TypeError, "Can't convert #{uri.class} into String."
  end if not uri.is_a? String

  # This Regexp supplied as an example in RFC 3986, and it works great.
  fragments = uri.scan(URIREGEX)[0]
  scheme    = fragments[1]
  authority = fragments[3]
  path      = fragments[4]
  query     = fragments[6]
  fragment  = fragments[8]
  host = nil

  if authority
    host = authority.gsub(/^([^\[\]]*)@/, '').gsub(/:([^:@\[\]]*?)$/, '')
  else
    authority = scheme
  end

  if host.nil? && uri =~ SCP_REGEXP
    Gitable::ScpURI.new(:authority => $1, :path => $2)
  else
    new(
      :scheme    => scheme,
      :authority => authority,
      :path      => path,
      :query     => query,
      :fragment  => fragment
    )
  end
end

.parse_when_valid(uri) ⇒ Gitable::URI?

Parse a git repository URI into a URI object. Rescue parse errors and return nil if uri is not parseable.

Parameters:

  • uri (Addressable::URI, #to_str)

    URI of a git repository.

Returns:

  • (Gitable::URI, nil)

    The parsed uri, or nil if not parseable.



74
75
76
77
78
# File 'lib/gitable/uri.rb', line 74

def self.parse_when_valid(uri)
  parse(uri)
rescue TypeError, Gitable::URI::InvalidURIError
  nil
end

Instance Method Details

#authenticated?Boolean

Detect URIs that will require some sort of authentication

Returns:

  • (Boolean)

    true if the URI uses ssh or has a user but no password



179
180
181
# File 'lib/gitable/uri.rb', line 179

def authenticated?
  ssh? || interactive_authenticated?
end

#basenameObject

Addressable does basename wrong when there’s no basename. It returns “/” for something like “host.com/”



248
249
250
# File 'lib/gitable/uri.rb', line 248

def basename
  super == "/" ? "" : super
end

#basename=(new_basename) ⇒ String

Set the basename, replacing it if it exists.

Parameters:

  • New (String)

    basename

Returns:

  • (String)

    basename result



256
257
258
259
260
261
262
263
264
265
266
# File 'lib/gitable/uri.rb', line 256

def basename=(new_basename)
  base = basename
  if base.to_s.empty?
    self.path += new_basename
  else
    rpath = normalized_path.reverse
    # replace the last occurrence of the basename with basename.ext
    self.path = rpath.sub(%r|#{Regexp.escape(base.reverse)}|, new_basename.reverse).reverse
  end
  basename
end

#bitbucket?Boolean

Is this uri a bitbucket uri?

Returns:

  • (Boolean)

    bitbucket.org is the host?



116
117
118
# File 'lib/gitable/uri.rb', line 116

def bitbucket?
  !!normalized_host.to_s.match(/\.?bitbucket.org$/)
end

#equivalent?(other_uri) ⇒ Boolean

Detect if two URIs are equivalent versions of the same uri.

When both uris are github repositories, uses a more lenient matching system is used that takes github’s repository organization into account.

For non-github URIs this method requires the two URIs to have the same host, equivalent paths, and either the same user or an absolute path.

Returns:

  • (Boolean)

    true if the URI probably indicates the same repository.



199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/gitable/uri.rb', line 199

def equivalent?(other_uri)
  other = Gitable::URI.parse_when_valid(other_uri)
  return false unless other
  return false unless normalized_host.to_s == other.normalized_host.to_s

  if github? || bitbucket?
    # github doesn't care about relative vs absolute paths in scp uris
    org_project == other.org_project
  else
    # if the path is absolute, we can assume it's the same for all users (so the user doesn't have to match).
    normalized_path.sub(/\/$/,'') == other.normalized_path.sub(/\/$/,'') &&
      (path[0] == '/' || normalized_user == other.normalized_user)
  end
end

#extname=(new_ext) ⇒ String

Set an extension name, replacing one if it exists.

If there is no basename (i.e. no words in the path) this method call will be ignored because it is likely to break the uri.

Use the public method #set_git_extname unless you actually need some other ext

Parameters:

  • New (String)

    extension name

Returns:

  • (String)

    extname result



230
231
232
233
234
# File 'lib/gitable/uri.rb', line 230

def extname=(new_ext)
  return nil if basename.to_s.empty?
  self.basename = "#{basename.sub(%r#\.git/?$#, '')}.#{new_ext.sub(/^\.+/,'')}"
  extname
end

#github?Boolean

Is this uri a github uri?

Returns:

  • (Boolean)

    github.com is the host?



109
110
111
# File 'lib/gitable/uri.rb', line 109

def github?
  !!normalized_host.to_s.match(/\.?github.com$/)
end

#inferred_schemeBoolean

Scheme inferred by the URI (URIs without hosts or schemes are assumed to be ‘file’)

Returns:

  • (Boolean)

    Is the URI local



154
155
156
157
158
159
160
# File 'lib/gitable/uri.rb', line 154

def inferred_scheme
  if normalized_scheme == 'file' || (normalized_scheme.to_s.empty? && normalized_host.to_s.empty?)
    'file'
  else
    normalized_scheme
  end
end

#inspectString

Dun da dun da dun, Inspector Gadget.

Returns:

  • (String)

    I’ll get you next time Gadget, NEXT TIME!



217
218
219
# File 'lib/gitable/uri.rb', line 217

def inspect
  "#<#{self.class.to_s} #{to_s}>"
end

#interactive_authenticated?Boolean

Detect URIs that will require interactive authentication

Returns:

  • (Boolean)

    true if the URI has a user, but is not using ssh



186
187
188
# File 'lib/gitable/uri.rb', line 186

def interactive_authenticated?
  !ssh? && (!normalized_user.nil? && normalized_password.nil?)
end

#local?Boolean

Detect local filesystem URIs.

Returns:

  • (Boolean)

    Is the URI local



147
148
149
# File 'lib/gitable/uri.rb', line 147

def local?
  inferred_scheme == 'file'
end

#org_projectObject



140
141
142
# File 'lib/gitable/uri.rb', line 140

def org_project
  normalized_path.sub(/^\//,'').sub(/\.git\/?$/,'')
end

#project_nameString

Tries to guess the project name of the repository.

Returns:

  • (String)

    Project name without .git



136
137
138
# File 'lib/gitable/uri.rb', line 136

def project_name
  basename.sub(/\.git\/?$/,'')
end

#scp?false

Is this an scp formatted uri? (No, always)

Returns:

  • (false)

    always false (overridden by scp formatted uris)



172
173
174
# File 'lib/gitable/uri.rb', line 172

def scp?
  false
end

#set_git_extnameString

Set the ‘.git’ extension name, replacing one if it exists.

If there is no basename (i.e. no words in the path) this method call will be ignored because it is likely to break the uri.

Returns:

  • (String)

    extname result



242
243
244
# File 'lib/gitable/uri.rb', line 242

def set_git_extname
  self.extname = "git"
end

#ssh?Boolean

Detect URIs that connect over ssh

Returns:

  • (Boolean)

    true if the URI uses ssh?



165
166
167
# File 'lib/gitable/uri.rb', line 165

def ssh?
  !!normalized_scheme.to_s.match(/ssh/)
end

#to_web_uri(uri_scheme = 'https') ⇒ Addressable::URI

Create a web link uri for repositories that follow the github pattern.

This probably won’t work for all git hosts, so it’s a good idea to use this in conjunction with #github? or #bitbucket? to help ensure correct links.

Parameters:

  • Scheme (String)

    of the web uri (smart defaults)

Returns:

  • (Addressable::URI)

    https://#host/#path_without_git_extension



128
129
130
131
# File 'lib/gitable/uri.rb', line 128

def to_web_uri(uri_scheme='https')
  return nil if normalized_host.to_s.empty?
  Addressable::URI.new(:scheme => uri_scheme, :host => normalized_host, :port => normalized_port, :path => normalized_path.sub(%r#\.git/?$#, ''))
end