Class: Gem::Requirement

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

Overview

A Requirement is a set of one or more version restrictions. It supports a few (=, !=, >, <, >=, <=, ~>) different restriction operators.

See Gem::Version for a description on how versions and requirements work together in RubyGems.

Defined Under Namespace

Classes: BadRequirementError

Constant Summary collapse

OPS =

:nodoc:

{ #:nodoc:
  "="  =>  lambda {|v, r| v == r },
  "!=" =>  lambda {|v, r| v != r },
  ">"  =>  lambda {|v, r| v >  r },
  "<"  =>  lambda {|v, r| v <  r },
  ">=" =>  lambda {|v, r| v >= r },
  "<=" =>  lambda {|v, r| v <= r },
  "~>" =>  lambda {|v, r| v >= r && v.release < r.bump },
}.freeze
SOURCE_SET_REQUIREMENT =

:nodoc:

Struct.new(:for_lockfile).new "!"
PATTERN_RAW =

:nodoc:

"\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*".freeze
PATTERN =

A regular expression that matches a requirement

/\A#{PATTERN_RAW}\z/.freeze
DefaultRequirement =

The default requirement matches any non-prerelease version

[">=", Gem::Version.new(0)].freeze
DefaultPrereleaseRequirement =

The default requirement matches any version

[">=", Gem::Version.new("0.a")].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*requirements) ⇒ Requirement

Constructs a requirement from requirements. Requirements can be Strings, Gem::Versions, or Arrays of those. nil and duplicate requirements are ignored. An empty set of requirements is the same as ">= 0".


130
131
132
133
134
135
136
137
138
139
140
# File 'lib/rubygems/requirement.rb', line 130

def initialize(*requirements)
  requirements = requirements.flatten
  requirements.compact!
  requirements.uniq!

  if requirements.empty?
    @requirements = [DefaultRequirement]
  else
    @requirements = requirements.map! {|r| self.class.parse r }
  end
end

Instance Attribute Details

#requirementsObject (readonly)

An array of requirement pairs. The first element of the pair is the op, and the second is the Gem::Version.


122
123
124
# File 'lib/rubygems/requirement.rb', line 122

def requirements
  @requirements
end

Class Method Details

.create(*inputs) ⇒ Object

Factory method to create a Gem::Requirement object. Input may be a Version, a String, or nil. Intended to simplify client code.

If the input is “weird”, the default version requirement is returned.


54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/rubygems/requirement.rb', line 54

def self.create(*inputs)
  return new inputs if inputs.length > 1

  input = inputs.shift

  case input
  when Gem::Requirement then
    input
  when Gem::Version, Array then
    new input
  when '!' then
    source_set
  else
    if input.respond_to? :to_str
      new [input.to_str]
    else
      default
    end
  end
end

.defaultObject


75
76
77
# File 'lib/rubygems/requirement.rb', line 75

def self.default
  new '>= 0'
end

.default_prereleaseObject


79
80
81
# File 'lib/rubygems/requirement.rb', line 79

def self.default_prerelease
  new '>= 0.a'
end

.parse(obj) ⇒ Object

Parse obj, returning an [op, version] pair. obj can be a String or a Gem::Version.

If obj is a String, it can be either a full requirement specification, like ">= 1.2", or a simple version number, like "1.2".

parse("> 1.0")                 # => [">", Gem::Version.new("1.0")]
parse("1.0")                   # => ["=", Gem::Version.new("1.0")]
parse(Gem::Version.new("1.0")) # => ["=,  Gem::Version.new("1.0")]

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/rubygems/requirement.rb', line 102

def self.parse(obj)
  return ["=", obj] if Gem::Version === obj

  unless PATTERN =~ obj.to_s
    raise BadRequirementError, "Illformed requirement [#{obj.inspect}]"
  end

  if $1 == ">=" && $2 == "0"
    DefaultRequirement
  elsif $1 == ">=" && $2 == "0.a"
    DefaultPrereleaseRequirement
  else
    [-($1 || "="), Gem::Version.new($2)]
  end
end

.source_setObject

A source set requirement, used for Gemfiles and lockfiles


86
87
88
# File 'lib/rubygems/requirement.rb', line 86

def self.source_set # :nodoc:
  SOURCE_SET_REQUIREMENT
end

Instance Method Details

#==(other) ⇒ Object

:nodoc:


269
270
271
272
273
274
275
276
277
278
279
280
281
# File 'lib/rubygems/requirement.rb', line 269

def ==(other) # :nodoc:
  return unless Gem::Requirement === other

  # An == check is always necessary
  return false unless requirements == other.requirements

  # An == check is sufficient unless any requirements use ~>
  return true unless _tilde_requirements.any?

  # If any requirements use ~> we use the stricter `#eql?` that also checks
  # that version precision is the same
  _tilde_requirements.eql?(other._tilde_requirements)
end

#as_listObject

:nodoc:


188
189
190
# File 'lib/rubygems/requirement.rb', line 188

def as_list # :nodoc:
  requirements.map {|op, version| "#{op} #{version}" }
end

#concat(new) ⇒ Object

Concatenates the new requirements onto this requirement.


145
146
147
148
149
150
151
152
# File 'lib/rubygems/requirement.rb', line 145

def concat(new)
  new = new.flatten
  new.compact!
  new.uniq!
  new = new.map {|r| self.class.parse r }

  @requirements.concat new
end

#encode_with(coder) ⇒ Object

:nodoc:


225
226
227
# File 'lib/rubygems/requirement.rb', line 225

def encode_with(coder) # :nodoc:
  coder.add 'requirements', @requirements
end

#exact?Boolean

true if the requirement is for only an exact version

Returns:

  • (Boolean)

183
184
185
186
# File 'lib/rubygems/requirement.rb', line 183

def exact?
  return false unless @requirements.size == 1
  @requirements[0][0] == "="
end

#for_lockfileObject

Formats this requirement for use in a Gem::RequestSet::Lockfile.


157
158
159
160
161
162
163
164
165
166
167
# File 'lib/rubygems/requirement.rb', line 157

def for_lockfile # :nodoc:
  return if [DefaultRequirement] == @requirements

  list = requirements.sort_by do |_, version|
    version
  end.map do |op, version|
    "#{op} #{version}"
  end.uniq

  " (#{list.join ', '})"
end

#hashObject

:nodoc:


192
193
194
# File 'lib/rubygems/requirement.rb', line 192

def hash # :nodoc:
  requirements.sort.hash
end

#init_with(coder) ⇒ Object

:nodoc:


217
218
219
# File 'lib/rubygems/requirement.rb', line 217

def init_with(coder) # :nodoc:
  yaml_initialize coder.tag, coder.map
end

#marshal_dumpObject

:nodoc:


196
197
198
199
200
# File 'lib/rubygems/requirement.rb', line 196

def marshal_dump # :nodoc:
  fix_syck_default_key_in_requirements

  [@requirements]
end

#marshal_load(array) ⇒ Object

:nodoc:


202
203
204
205
206
# File 'lib/rubygems/requirement.rb', line 202

def marshal_load(array) # :nodoc:
  @requirements = array[0]

  fix_syck_default_key_in_requirements
end

#none?Boolean

true if this gem has no requirements.

Returns:

  • (Boolean)

172
173
174
175
176
177
178
# File 'lib/rubygems/requirement.rb', line 172

def none?
  if @requirements.size == 1
    @requirements[0] == DefaultRequirement
  else
    false
  end
end

#prerelease?Boolean

A requirement is a prerelease if any of the versions inside of it are prereleases

Returns:

  • (Boolean)

233
234
235
# File 'lib/rubygems/requirement.rb', line 233

def prerelease?
  requirements.any? {|r| r.last.prerelease? }
end

#pretty_print(q) ⇒ Object

:nodoc:


237
238
239
240
241
# File 'lib/rubygems/requirement.rb', line 237

def pretty_print(q) # :nodoc:
  q.group 1, 'Gem::Requirement.new(', ')' do
    q.pp as_list
  end
end

#satisfied_by?(version) ⇒ Boolean Also known as: ===, =~

True if version satisfies this Requirement.

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)

246
247
248
249
250
251
# File 'lib/rubygems/requirement.rb', line 246

def satisfied_by?(version)
  raise ArgumentError, "Need a Gem::Version: #{version.inspect}" unless
    Gem::Version === version
  # #28965: syck has a bug with unquoted '=' YAML.loading as YAML::DefaultKey
  requirements.all? {|op, rv| (OPS[op] || OPS["="]).call version, rv }
end

#specific?Boolean

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

Returns:

  • (Boolean)

259
260
261
262
263
# File 'lib/rubygems/requirement.rb', line 259

def specific?
  return true if @requirements.length > 1 # GIGO, > 1, > 2 is silly

  not %w[> >=].include? @requirements.first.first # grab the operator
end

#to_sObject

:nodoc:


265
266
267
# File 'lib/rubygems/requirement.rb', line 265

def to_s # :nodoc:
  as_list.join ", "
end

#to_yaml_propertiesObject

:nodoc:


221
222
223
# File 'lib/rubygems/requirement.rb', line 221

def to_yaml_properties # :nodoc:
  ["@requirements"]
end

#yaml_initialize(tag, vals) ⇒ Object

:nodoc:


208
209
210
211
212
213
214
215
# File 'lib/rubygems/requirement.rb', line 208

def yaml_initialize(tag, vals) # :nodoc:
  vals.each do |ivar, val|
    instance_variable_set "@#{ivar}", val
  end

  Gem.load_yaml
  fix_syck_default_key_in_requirements
end