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.



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

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.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
# 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? && (parts = uri.scan(SCP_REGEXP)) && parts.any?
    Gitable::ScpURI.new(:authority => parts.first[0], :path => parts.first[1])
  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.



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

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



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

def authenticated?
  ssh? || interactive_authenticated?
end

#basenameObject

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



240
241
242
# File 'lib/gitable/uri.rb', line 240

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



248
249
250
251
252
253
254
255
256
257
258
# File 'lib/gitable/uri.rb', line 248

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

#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.



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/gitable/uri.rb', line 186

def equivalent?(other_uri)
  other = Gitable::URI.parse(other_uri)

  same_host = normalized_host.to_s == other.normalized_host.to_s

  if github? && other.github?
    # github doesn't care about relative vs absolute paths in scp uris (so we can remove leading / for comparison)
    same_path = normalized_path.sub(%r#\.git/?$#, '').sub(%r#^/#,'') == other.normalized_path.sub(%r#\.git/?$#, '').sub(%r#^/#,'')
    same_host && same_path
  else
    same_path = normalized_path.sub(%r#/$#,'').to_s == other.normalized_path.sub(%r#/$#,'').to_s # remove trailing slashes.
    same_user = normalized_user == other.normalized_user

    # if the path is absolute, we can assume it's the same for all users (so the user doesn't have to match).
    same_host && same_path && (path =~ %r#^/# || same_user)
  end
rescue Gitable::URI::InvalidURIError
  false
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



222
223
224
225
226
# File 'lib/gitable/uri.rb', line 222

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?



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

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



141
142
143
144
145
146
147
# File 'lib/gitable/uri.rb', line 141

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!



209
210
211
# File 'lib/gitable/uri.rb', line 209

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



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

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

#local?Boolean

Detect local filesystem URIs.

Returns:

  • (Boolean)

    Is the URI local



134
135
136
# File 'lib/gitable/uri.rb', line 134

def local?
  inferred_scheme == 'file'
end

#project_nameString

Tries to guess the project name of the repository.

Returns:

  • (String)

    Project name without .git



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

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)



159
160
161
# File 'lib/gitable/uri.rb', line 159

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



234
235
236
# File 'lib/gitable/uri.rb', line 234

def set_git_extname
  self.extname = "git"
end

#ssh?Boolean

Detect URIs that connect over ssh

Returns:

  • (Boolean)

    true if the URI uses ssh?



152
153
154
# File 'lib/gitable/uri.rb', line 152

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? to help ensure correct links.

Parameters:

  • Scheme (String)

    of the web uri (smart defaults)

Returns:

  • (Addressable::URI)

    https://#host/#path_without_git_extension



119
120
121
122
# File 'lib/gitable/uri.rb', line 119

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