Geminstaller C0 Coverage Information - RCov

spec/fixture/rubygems_dist/rubygems-trunk/lib/rubygems/version.rb

Name Total Lines Lines of Code Total Coverage Code Coverage
spec/fixture/rubygems_dist/rubygems-trunk/lib/rubygems/version.rb 308 86
93.51%
80.23%

Key

Code reported as executed by Ruby looks like this...and this: this line is also marked as covered.Lines considered as run by rcov, but not reported by Ruby, look like this,and this: these lines were inferred by rcov (using simple heuristics).Finally, here's a line marked as not executed.

Coverage Details

1 ##
2 # The Version class processes string versions into comparable
3 # values. A version string should normally be a series of numbers
4 # separated by periods. Each part (digits separated by periods) is
5 # considered its own number, and these are used for sorting. So for
6 # instance, 3.10 sorts higher than 3.2 because ten is greater than
7 # two.
8 #
9 # If any part contains letters (currently only a-z are supported) then
10 # that version is considered prerelease. Versions with a prerelease
11 # part in the Nth part sort less than versions with N-1 parts. Prerelease
12 # parts are sorted alphabetically using the normal Ruby string sorting
13 # rules.
14 #
15 # Prereleases sort between real releases (newest to oldest):
16 #
17 # 1. 1.0
18 # 2. 1.0.b
19 # 3. 1.0.a
20 # 4. 0.9
21 #
22 # == How Software Changes
23 #
24 # Users expect to be able to specify a version constraint that gives them
25 # some reasonable expectation that new versions of a library will work with
26 # their software if the version constraint is true, and not work with their
27 # software if the version constraint is false.  In other words, the perfect
28 # system will accept all compatible versions of the library and reject all
29 # incompatible versions.
30 #
31 # Libraries change in 3 ways (well, more than 3, but stay focused here!).
32 #
33 # 1. The change may be an implementation detail only and have no effect on
34 #    the client software.
35 # 2. The change may add new features, but do so in a way that client software
36 #    written to an earlier version is still compatible.
37 # 3. The change may change the public interface of the library in such a way
38 #    that old software is no longer compatible.
39 #
40 # Some examples are appropriate at this point.  Suppose I have a Stack class
41 # that supports a <tt>push</tt> and a <tt>pop</tt> method.
42 #
43 # === Examples of Category 1 changes:
44 #
45 # * Switch from an array based implementation to a linked-list based
46 #   implementation.
47 # * Provide an automatic (and transparent) backing store for large stacks.
48 #
49 # === Examples of Category 2 changes might be:
50 #
51 # * Add a <tt>depth</tt> method to return the current depth of the stack.
52 # * Add a <tt>top</tt> method that returns the current top of stack (without
53 #   changing the stack).
54 # * Change <tt>push</tt> so that it returns the item pushed (previously it
55 #   had no usable return value).
56 #
57 # === Examples of Category 3 changes might be:
58 #
59 # * Changes <tt>pop</tt> so that it no longer returns a value (you must use
60 #   <tt>top</tt> to get the top of the stack).
61 # * Rename the methods to <tt>push_item</tt> and <tt>pop_item</tt>.
62 #
63 # == RubyGems Rational Versioning
64 #
65 # * Versions shall be represented by three non-negative integers, separated
66 #   by periods (e.g. 3.1.4).  The first integers is the "major" version
67 #   number, the second integer is the "minor" version number, and the third
68 #   integer is the "build" number.
69 #
70 # * A category 1 change (implementation detail) will increment the build
71 #   number.
72 #
73 # * A category 2 change (backwards compatible) will increment the minor
74 #   version number and reset the build number.
75 #
76 # * A category 3 change (incompatible) will increment the major build number
77 #   and reset the minor and build numbers.
78 #
79 # * Any "public" release of a gem should have a different version.  Normally
80 #   that means incrementing the build number.  This means a developer can
81 #   generate builds all day long for himself, but as soon as he/she makes a
82 #   public release, the version must be updated.
83 #
84 # === Examples
85 #
86 # Let's work through a project lifecycle using our Stack example from above.
87 #
88 # Version 0.0.1:: The initial Stack class is release.
89 # Version 0.0.2:: Switched to a linked=list implementation because it is
90 #                 cooler.
91 # Version 0.1.0:: Added a <tt>depth</tt> method.
92 # Version 1.0.0:: Added <tt>top</tt> and made <tt>pop</tt> return nil
93 #                 (<tt>pop</tt> used to return the  old top item).
94 # Version 1.1.0:: <tt>push</tt> now returns the value pushed (it used it
95 #                 return nil).
96 # Version 1.1.1:: Fixed a bug in the linked list implementation.
97 # Version 1.1.2:: Fixed a bug introduced in the last fix.
98 #
99 # Client A needs a stack with basic push/pop capability.  He writes to the
100 # original interface (no <tt>top</tt>), so his version constraint looks
101 # like:
102 #
103 #   gem 'stack', '~> 0.0'
104 #
105 # Essentially, any version is OK with Client A.  An incompatible change to
106 # the library will cause him grief, but he is willing to take the chance (we
107 # call Client A optimistic).
108 #
109 # Client B is just like Client A except for two things: (1) He uses the
110 # <tt>depth</tt> method and (2) he is worried about future
111 # incompatibilities, so he writes his version constraint like this:
112 #
113 #   gem 'stack', '~> 0.1'
114 #
115 # The <tt>depth</tt> method was introduced in version 0.1.0, so that version
116 # or anything later is fine, as long as the version stays below version 1.0
117 # where incompatibilities are introduced.  We call Client B pessimistic
118 # because he is worried about incompatible future changes (it is OK to be
119 # pessimistic!).
120 #
121 # == Preventing Version Catastrophe:
122 #
123 # From: http://blog.zenspider.com/2008/10/rubygems-howto-preventing-cata.html
124 #
125 # Let's say you're depending on the fnord gem version 2.y.z. If you
126 # specify your dependency as ">= 2.0.0" then, you're good, right? What
127 # happens if fnord 3.0 comes out and it isn't backwards compatible
128 # with 2.y.z? Your stuff will break as a result of using ">=". The
129 # better route is to specify your dependency with a "spermy" version
130 # specifier. They're a tad confusing, so here is how the dependency
131 # specifiers work:
132 #
133 #   Specification From  ... To (exclusive)
134 #   ">= 3.0"      3.0   ... &infin;
135 #   "~> 3.0"      3.0   ... 4.0
136 #   "~> 3.0.0"    3.0.0 ... 3.1
137 #   "~> 3.5"      3.5   ... 4.0
138 #   "~> 3.5.0"    3.5.0 ... 3.6
139 
140 class Gem::Version
141   include Comparable
142 
143   VERSION_PATTERN = '[0-9]+(\.[0-9a-zA-Z]+)*' # :nodoc:
144   ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/ # :nodoc:
145 
146   ##
147   # A string representation of this Version.
148 
149   attr_reader :version
150   alias to_s version
151 
152   ##
153   # True if the +version+ string matches RubyGems' requirements.
154 
155   def self.correct? version
156     version.to_s =~ ANCHORED_VERSION_PATTERN
157   end
158 
159   ##
160   # Factory method to create a Version object. Input may be a Version
161   # or a String. Intended to simplify client code.
162   #
163   #   ver1 = Version.create('1.3.17')   # -> (Version object)
164   #   ver2 = Version.create(ver1)       # -> (ver1)
165   #   ver3 = Version.create(nil)        # -> nil
166 
167   def self.create input
168     if input.respond_to? :version then
169       input
170     elsif input.nil? then
171       nil
172     else
173       new input
174     end
175   end
176 
177   ##
178   # Constructs a Version from the +version+ string.  A version string is a
179   # series of digits or ASCII letters separated by dots.
180 
181   def initialize version
182     raise ArgumentError, "Malformed version number string #{version}" unless
183       self.class.correct?(version)
184 
185     @version = version.to_s
186     @version.strip!
187 
188     segments # prime @segments
189   end
190 
191   ##
192   # Return a new version object where the next to the last revision
193   # number is one greater (e.g., 5.3.1 => 5.4).
194   #
195   # Pre-release (alpha) parts, e.g, 5.3.1.b2 => 5.4, are ignored.
196 
197   def bump
198     segments = self.segments.dup
199     segments.pop while segments.any? { |s| String === s }
200     segments.pop if segments.size > 1
201 
202     segments[-1] = segments[-1].succ
203     self.class.new segments.join(".")
204   end
205 
206   ##
207   # A Version is only eql? to another version if it's specified to the
208   # same precision. Version "1.0" is not the same as version "1".
209 
210   def eql? other
211     self.class === other and segments == other.segments
212   end
213 
214   def hash # :nodoc:
215     @hash ||= segments.hash
216   end
217 
218   def inspect # :nodoc:
219     "#<#{self.class} #{version.inspect}>"
220   end
221 
222   ##
223   # Dump only the raw version string, not the complete object. It's a
224   # string for backwards (RubyGems 1.3.5 and earlier) compatibility.
225 
226   def marshal_dump
227     [version]
228   end
229 
230   ##
231   # Load custom marshal format. It's a string for backwards (RubyGems
232   # 1.3.5 and earlier) compatibility.
233 
234   def marshal_load array
235     initialize array[0]
236   end
237 
238   ##
239   # A version is considered a prerelease if it contains a letter.
240 
241   def prerelease?
242     @prerelease ||= segments.any? { |s| String === s }
243   end
244 
245   def pretty_print q # :nodoc:
246     q.text "Gem::Version.new(#{version.inspect})"
247   end
248 
249   ##
250   # The release for this version (e.g. 1.2.0.a -> 1.2.0).
251   # Non-prerelease versions return themselves.
252 
253   def release
254     return self unless prerelease?
255 
256     segments = self.segments.dup
257     segments.pop while segments.any? { |s| String === s }
258     self.class.new segments.join('.')
259   end
260 
261   def segments # :nodoc:
262 
263     # @segments is lazy so it can pick up @version values that come
264     # from old marshaled versions, which don't go through
265     # marshal_load. +segments+ is called in +initialize+ to "prime
266     # the pump" in normal cases.
267 
268     @segments ||= @version.scan(/[0-9a-z]+/i).map do |s|
269       /^\d+$/ =~ s ? s.to_i : s
270     end
271   end
272 
273   ##
274   # A recommended version for use with a ~> Requirement.
275 
276   def spermy_recommendation
277     segments = self.segments.dup
278 
279     segments.pop    while segments.any? { |s| String === s }
280     segments.pop    while segments.size > 2
281     segments.push 0 while segments.size < 2
282 
283     "~> #{segments.join(".")}"
284   end
285 
286   ##
287   # Compares this version with +other+ returning -1, 0, or 1 if the other
288   # version is larger, the same, or smaller than this one.
289 
290   def <=> other
291     return   1 unless other # HACK: comparable with nil? why?
292     return nil unless self.class === other
293 
294     lhsize = segments.size
295     rhsize = other.segments.size
296     limit  = (lhsize > rhsize ? lhsize : rhsize) - 1
297 
298     0.upto(limit) do |i|
299       lhs, rhs = segments[i] || 0, other.segments[i] || 0
300 
301       return  -1         if String  === lhs && Numeric === rhs
302       return   1         if Numeric === lhs && String  === rhs
303       return lhs <=> rhs if lhs != rhs
304     end
305 
306     return 0
307   end
308 end

Generated on Mon May 10 23:40:29 -0700 2010 with rcov 0.9.8