Class: Gem::Dependency

Inherits:
Object show all
Defined in:
lib/rubygems/dependency.rb

Overview

The Dependency class holds a Gem name and a Gem::Requirement.

Constant Summary collapse

TYPES =

Valid dependency types. – When this list is updated, be sure to change Gem::Specification::CURRENT_SPECIFICATION_VERSION as well.

REFACTOR: This type of constant, TYPES, indicates we might want two classes, used via inheritance or duck typing.

[
  :development,
  :runtime,
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, *requirements) ⇒ Dependency

Constructs a dependency with name and requirements. The last argument can optionally be the dependency type, which defaults to :runtime.



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/rubygems/dependency.rb', line 35

def initialize(name, *requirements)
  case name
  when String then # ok
  when Regexp then
    msg = ["NOTE: Dependency.new w/ a regexp is deprecated.",
           "Dependency.new called from #{Gem.location_of_caller.join(":")}"]
    warn msg.join("\n") unless Gem::Deprecate.skip
  else
    raise ArgumentError,
          "dependency name must be a String, was #{name.inspect}"
  end

  type         = Symbol === requirements.last ? requirements.pop : :runtime
  requirements = requirements.first if 1 == requirements.length # unpack

  unless TYPES.include? type
    raise ArgumentError, "Valid types are #{TYPES.inspect}, " +
                         "not #{type.inspect}"
  end

  @name        = name
  @requirement = Gem::Requirement.create requirements
  @type        = type
  @prerelease  = false

  # This is for Marshal backwards compatibility. See the comments in
  # +requirement+ for the dirty details.

  @version_requirements = @requirement
end

Instance Attribute Details

#nameObject

Dependency name or regular expression.



23
24
25
# File 'lib/rubygems/dependency.rb', line 23

def name
  @name
end

#prerelease=(value) ⇒ Object (writeonly)

Allows you to force this dependency to be a prerelease.



28
29
30
# File 'lib/rubygems/dependency.rb', line 28

def prerelease=(value)
  @prerelease = value
end

Instance Method Details

#<=>(other) ⇒ Object

Dependencies are ordered by name.



179
180
181
# File 'lib/rubygems/dependency.rb', line 179

def <=>(other)
  self.name <=> other.name
end

#==(other) ⇒ Object

:nodoc:



169
170
171
172
173
174
# File 'lib/rubygems/dependency.rb', line 169

def ==(other) # :nodoc:
  Gem::Dependency === other &&
    self.name        == other.name &&
    self.type        == other.type &&
    self.requirement == other.requirement
end

#=~(other) ⇒ Object Also known as: ===

Uses this dependency as a pattern to compare to other. This dependency will match if the name matches the other’s name, and other has only an equal version requirement that satisfies this dependency.



189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/rubygems/dependency.rb', line 189

def =~(other)
  unless Gem::Dependency === other
    return unless other.respond_to?(:name) && other.respond_to?(:version)
    other = Gem::Dependency.new other.name, other.version
  end

  return false unless name === other.name

  reqs = other.requirement.requirements

  return false unless reqs.length == 1
  return false unless reqs.first.first == '='

  version = reqs.first.last

  requirement.satisfied_by? version
end

#filters_bundler?Boolean

Returns:

  • (Boolean)


298
299
300
# File 'lib/rubygems/dependency.rb', line 298

def filters_bundler?
  name == "bundler".freeze && !specific?
end

#hashObject

A dependency’s hash is the XOR of the hashes of name, type, and requirement.



70
71
72
# File 'lib/rubygems/dependency.rb', line 70

def hash # :nodoc:
  name.hash ^ type.hash ^ requirement.hash
end

#identityObject



337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/rubygems/dependency.rb', line 337

def identity
  if prerelease?
    if specific?
      :complete
    else
      :abs_latest
    end
  elsif latest_version?
    :latest
  else
    :released
  end
end

#inspectObject

:nodoc:



74
75
76
77
78
79
80
81
82
# File 'lib/rubygems/dependency.rb', line 74

def inspect # :nodoc:
  if prerelease?
    "<%s type=%p name=%p requirements=%p prerelease=ok>" %
      [self.class, self.type, self.name, requirement.to_s]
  else
    "<%s type=%p name=%p requirements=%p>" %
      [self.class, self.type, self.name, requirement.to_s]
  end
end

#latest_version?Boolean

Is this dependency simply asking for the latest version of a gem?

Returns:

  • (Boolean)


95
96
97
# File 'lib/rubygems/dependency.rb', line 95

def latest_version?
  @requirement.none?
end

#match?(obj, version = nil, allow_prerelease = false) ⇒ Boolean

:call-seq:

dep.match? name          => true or false
dep.match? name, version => true or false
dep.match? spec          => true or false

Does this dependency match the specification described by name and version or match spec?

NOTE: Unlike #matches_spec? this method does not return true when the version is a prerelease version unless this is a prerelease dependency.

Returns:

  • (Boolean)


221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'lib/rubygems/dependency.rb', line 221

def match?(obj, version=nil, allow_prerelease=false)
  if !version
    name = obj.name
    version = obj.version
  else
    name = obj
  end

  return false unless self.name === name

  version = Gem::Version.new version

  return true if requirement.none? and not version.prerelease?
  return false if version.prerelease? and
                  not allow_prerelease and
                  not prerelease?

  requirement.satisfied_by? version
end

#matches_spec?(spec) ⇒ Boolean

Does this dependency match spec?

NOTE: This is not a convenience method. Unlike #match? this method returns true when spec is a prerelease version even if this dependency is not a prerelease dependency.

Returns:

  • (Boolean)


248
249
250
251
252
253
# File 'lib/rubygems/dependency.rb', line 248

def matches_spec?(spec)
  return false unless name === spec.name
  return true  if requirement.none?

  requirement.satisfied_by?(spec.version)
end

#matching_specs(platform_only = false) ⇒ Object



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/rubygems/dependency.rb', line 274

def matching_specs(platform_only = false)
  env_req = Gem.env_requirement(name)
  matches = Gem::Specification.stubs_for(name).find_all do |spec|
    requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
  end.map(&:to_spec)

  Gem::BundlerVersionFinder.filter!(matches) if filters_bundler?

  if platform_only
    matches.reject! do |spec|
      spec.nil? || !Gem::Platform.match_spec?(spec)
    end
  end

  matches
end

#merge(other) ⇒ Object

Merges the requirements of other into this dependency



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/rubygems/dependency.rb', line 258

def merge(other)
  unless name == other.name
    raise ArgumentError,
          "#{self} and #{other} have different names"
  end

  default = Gem::Requirement.default
  self_req = self.requirement
  other_req = other.requirement

  return self.class.new name, self_req  if other_req == default
  return self.class.new name, other_req if self_req  == default

  self.class.new name, self_req.as_list.concat(other_req.as_list)
end

#prerelease?Boolean

Does this dependency require a prerelease?

Returns:

  • (Boolean)


87
88
89
# File 'lib/rubygems/dependency.rb', line 87

def prerelease?
  @prerelease || requirement.prerelease?
end

#pretty_print(q) ⇒ Object

:nodoc:



99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/rubygems/dependency.rb', line 99

def pretty_print(q) # :nodoc:
  q.group 1, 'Gem::Dependency.new(', ')' do
    q.pp name
    q.text ','
    q.breakable

    q.pp requirement

    q.text ','
    q.breakable

    q.pp type
  end
end

#requirementObject

What does this dependency require?



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/rubygems/dependency.rb', line 117

def requirement
  return @requirement if defined?(@requirement) and @requirement

  # @version_requirements and @version_requirement are legacy ivar
  # names, and supported here because older gems need to keep
  # working and Dependency doesn't implement marshal_dump and
  # marshal_load. In a happier world, this would be an
  # attr_accessor. The horrifying instance_variable_get you see
  # below is also the legacy of some old restructurings.
  #
  # Note also that because of backwards compatibility (loading new
  # gems in an old RubyGems installation), we can't add explicit
  # marshaling to this class until we want to make a big
  # break. Maybe 2.0.
  #
  # Children, define explicit marshal and unmarshal behavior for
  # public classes. Marshal formats are part of your public API.

  # REFACTOR: See above

  if defined?(@version_requirement) && @version_requirement
    version = @version_requirement.instance_variable_get :@version
    @version_requirement = nil
    @version_requirements = Gem::Requirement.new version
  end

  @requirement = @version_requirements if defined?(@version_requirements)
end

#requirements_listObject



146
147
148
# File 'lib/rubygems/dependency.rb', line 146

def requirements_list
  requirement.as_list
end

#runtime?Boolean

Returns:

  • (Boolean)


165
166
167
# File 'lib/rubygems/dependency.rb', line 165

def runtime?
  @type == :runtime || !@type
end

#specific?Boolean

True if the dependency will not always match the latest version.

Returns:

  • (Boolean)


294
295
296
# File 'lib/rubygems/dependency.rb', line 294

def specific?
  @requirement.specific?
end

#to_sObject

:nodoc:



150
151
152
153
154
155
156
# File 'lib/rubygems/dependency.rb', line 150

def to_s # :nodoc:
  if type != :runtime
    "#{name} (#{requirement}, #{type})"
  else
    "#{name} (#{requirement})"
  end
end

#to_specObject



322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'lib/rubygems/dependency.rb', line 322

def to_spec
  matches = self.to_specs.compact

  active = matches.find {|spec| spec.activated? }
  return active if active

  return matches.first if prerelease?

  # Move prereleases to the end of the list for >= 0 requirements
  pre, matches = matches.partition {|spec| spec.version.prerelease? }
  matches += pre if requirement == Gem::Requirement.default

  matches.first
end

#to_specsObject



302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/rubygems/dependency.rb', line 302

def to_specs
  matches = matching_specs true

  # TODO: check Gem.activated_spec[self.name] in case matches falls outside

  if matches.empty?
    specs = Gem::Specification.stubs_for name

    if specs.empty?
      raise Gem::MissingSpecError.new name, requirement
    else
      raise Gem::MissingSpecVersionError.new name, requirement, specs
    end
  end

  # TODO: any other resolver validations should go here

  matches
end

#typeObject

Dependency type.



161
162
163
# File 'lib/rubygems/dependency.rb', line 161

def type
  @type ||= :runtime
end