versionomy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,385 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Versionomy standard schema and formats
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2008 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module Versionomy
38
+
39
+
40
+ # === The standard schema
41
+ #
42
+ # The standard schema is designed to handle most commonly-used version
43
+ # number forms, and allow parsing and comparison between them.
44
+ #
45
+ # It begins with four numeric fields: "major.minor.tiny.tiny2".
46
+ #
47
+ # The next field, "release_type", defines the remaining structure.
48
+ # The release type can be one of these symbolic values: <tt>:prerelease</tt>,
49
+ # <tt>:development</tt>, <tt>:alpha</tt>, <tt>:beta</tt>,
50
+ # <tt>:release_candidate</tt>, or <tt>:release</tt>.
51
+ #
52
+ # Depending on that value, additional fields become available. For example,
53
+ # the <tt>:alpha</tt> value enables the fields "alpha_version"
54
+ # and "alpha_minor", which represent version numbers after the "a" alpha
55
+ # specifier. i.e. "2.1a30" has an alpha_version of 30. "2.1a30.2" also
56
+ # has an alpha_minor of 2. Similarly, the <tt>:beta</tt> release_type
57
+ # value enables the fields "beta_version" and "beta_minor". A release_type
58
+ # of <tt>:release</tt> enables "patchlevel" and "patchlevel_minor", to
59
+ # support versions like "1.8.7p72".
60
+ #
61
+ # The full definition of the standard schema is as follows:
62
+ #
63
+ # Schema.new(:major, :initial => 1) do
64
+ # schema(:minor) do
65
+ # schema(:tiny) do
66
+ # schema(:tiny2) do
67
+ # schema(:release_type, :type => :symbol) do
68
+ # symbol(:prerelease, :bump => :release)
69
+ # symbol(:development, :bump => :alpha)
70
+ # symbol(:alpha, :bump => :beta)
71
+ # symbol(:beta, :bump => :release_candidate)
72
+ # symbol(:release_candidate, :bump => :release)
73
+ # symbol(:release, :bump => :release)
74
+ # initial_value(:release)
75
+ # schema(:prerelease_version, :only => :prerelease, :initial => 1) do
76
+ # schema(:prerelease_minor)
77
+ # end
78
+ # schema(:development_version, :only => :development, :initial => 1) do
79
+ # schema(:development_minor)
80
+ # end
81
+ # schema(:alpha_version, :only => :alpha, :initial => 1) do
82
+ # schema(:alpha_minor)
83
+ # end
84
+ # schema(:beta_version, :only => :beta, :initial => 1) do
85
+ # schema(:beta_minor)
86
+ # end
87
+ # schema(:release_candidate_version, :only => :release_candidate, :initial => 1) do
88
+ # schema(:release_candidate_minor)
89
+ # end
90
+ # schema(:patchlevel, :only => :release) do
91
+ # schema(:patchlevel_minor)
92
+ # end
93
+ # end
94
+ # end
95
+ # end
96
+ # end
97
+ # end
98
+
99
+ module Standard
100
+
101
+
102
+ # A formatter for the standard schema
103
+
104
+ class StandardFormat
105
+
106
+
107
+ # Create a new formatter
108
+
109
+ def initialize(opts_={})
110
+ @patchlevel_separator = opts_[:patchlevel_separators] || ['-', 'p']
111
+ @prerelease_symbol = opts_[:prerelease_symbols] || 'pre'
112
+ @development_symbol = opts_[:development_symbols] || 'd'
113
+ @alpha_symbol = opts_[:alpha_symbols] || 'a'
114
+ @beta_symbol = opts_[:beta_symbols] || 'b'
115
+ @release_candidate_symbol = opts_[:release_candidate_symbols] || 'rc'
116
+ end
117
+
118
+
119
+ def _create_regex(given_, default_) # :nodoc:
120
+ if given_
121
+ if given_.respond_to?(:join)
122
+ given_.join('|')
123
+ else
124
+ given_.to_s
125
+ end
126
+ else
127
+ if default_.respond_to?(:join)
128
+ default_.join('|')
129
+ else
130
+ default_.to_s
131
+ end
132
+ end
133
+ end
134
+ private :_create_regex
135
+
136
+ def _create_separator(given_, default_) # :nodoc:
137
+ if given_
138
+ given_.to_s
139
+ else
140
+ if default_.respond_to?(:join)
141
+ default_[0].to_s
142
+ else
143
+ default_.to_s
144
+ end
145
+ end
146
+ end
147
+ private :_create_separator
148
+
149
+
150
+ # Parse a string for the standard schema.
151
+
152
+ def parse(schema_, str_, params_)
153
+ params_ = Hash.new.merge(params_)
154
+ hash_ = Hash.new
155
+ if str_ =~ /^(\d+)(.*)$/
156
+ hash_[:major] = $1.to_i
157
+ str_ = $2
158
+ else
159
+ hash_[:major] = 0
160
+ end
161
+ if str_ =~ /^\.(\d+)(.*)$/
162
+ hash_[:minor] = $1.to_i
163
+ str_ = $2
164
+ if str_ =~ /^\.(\d+)(.*)$/
165
+ hash_[:tiny] = $1.to_i
166
+ str_ = $2
167
+ if str_ =~ /^\.(\d+)(.*)$/
168
+ hash_[:tiny2] = $1.to_i
169
+ str_ = $2
170
+ params_[:required_fields] = 4
171
+ else
172
+ hash_[:tiny2] = 0
173
+ params_[:required_fields] = 3
174
+ end
175
+ else
176
+ hash_[:tiny] = 0
177
+ params_[:required_fields] = 2
178
+ end
179
+ else
180
+ hash_[:minor] = 0
181
+ params_[:required_fields] = 1
182
+ end
183
+ if str_ =~ /^(#{_create_regex(params_[:prerelease_symbol], @prerelease_symbol)})(\d+)(.*)$/
184
+ params_[:prerelease_symbol] = $1
185
+ hash_[:release_type] = :prerelease
186
+ hash_[:prerelease_version] = $2.to_i
187
+ str_ = $3
188
+ if str_ =~ /^\.(\d+)/
189
+ hash_[:prerelease_minor] = $1.to_i
190
+ params_[:prerelease_required_fields] = 2
191
+ else
192
+ params_[:prerelease_required_fields] = 1
193
+ end
194
+ elsif str_ =~ /^(#{_create_regex(params_[:development_symbol], @development_symbol)})(\d+)(.*)$/
195
+ params_[:development_symbol] = $1
196
+ hash_[:release_type] = :development
197
+ hash_[:development_version] = $2.to_i
198
+ str_ = $3
199
+ if str_ =~ /^\.(\d+)/
200
+ hash_[:development_minor] = $1.to_i
201
+ params_[:development_required_fields] = 2
202
+ else
203
+ params_[:development_required_fields] = 1
204
+ end
205
+ elsif str_ =~ /^(#{_create_regex(params_[:alpha_symbol], @alpha_symbol)})(\d+)(.*)$/
206
+ params_[:alpha_symbol] = $1
207
+ hash_[:release_type] = :alpha
208
+ hash_[:alpha_version] = $2.to_i
209
+ str_ = $3
210
+ if str_ =~ /^\.(\d+)/
211
+ hash_[:alpha_minor] = $1.to_i
212
+ params_[:alpha_required_fields] = 2
213
+ else
214
+ params_[:alpha_required_fields] = 1
215
+ end
216
+ elsif str_ =~ /^(#{_create_regex(params_[:beta_symbol], @beta_symbol)})(\d+)(.*)$/
217
+ params_[:beta_symbol] = $1
218
+ hash_[:release_type] = :beta
219
+ hash_[:beta_version] = $2.to_i
220
+ str_ = $3
221
+ if str_ =~ /^\.(\d+)/
222
+ hash_[:beta_minor] = $1.to_i
223
+ params_[:beta_required_fields] = 2
224
+ else
225
+ params_[:beta_required_fields] = 1
226
+ end
227
+ elsif str_ =~ /^(#{_create_regex(params_[:release_candidate_symbol], @release_candidate_symbol)})(\d+)(.*)$/
228
+ params_[:release_candidate_symbol] = $1
229
+ hash_[:release_candidate_version] = $2.to_i
230
+ hash_[:release_type] = :release_candidate
231
+ str_ = $3
232
+ if str_ =~ /^\.(\d+)/
233
+ hash_[:release_candidate_minor] = $1.to_i
234
+ params_[:release_candidate_required_fields] = 2
235
+ else
236
+ params_[:release_candidate_required_fields] = 1
237
+ end
238
+ else
239
+ hash_[:release_type] = :release
240
+ if str_ =~ /^(#{_create_regex(params_[:patchlevel_separator], @patchlevel_separator)})(\d+)(.*)$/
241
+ params_[:patchlevel_separator] = $1
242
+ params_[:patchlevel_format] = :digit
243
+ hash_[:patchlevel] = $2.to_i
244
+ str_ = $3
245
+ if str_ =~ /^\.(\d+)/
246
+ hash_[:patchlevel_minor] = $1.to_i
247
+ params_[:patchlevel_required_fields] = 2
248
+ else
249
+ params_[:patchlevel_required_fields] = 1
250
+ end
251
+ elsif str_ =~ /^([a-z])/
252
+ char_ = $1
253
+ params_[:patchlevel_format] = :alpha_lower
254
+ params_[:patchlevel_required_fields] = 1
255
+ hash[:patchlevel] = (char_.bytes.next rescue char_[0]) - 96
256
+ elsif str_ =~ /^([A-Z])/
257
+ char_ = $1
258
+ params_[:patchlevel_format] = :alpha_upper
259
+ params_[:patchlevel_required_fields] = 1
260
+ hash[:patchlevel] = (char_.bytes.next rescue char_[0]) - 64
261
+ end
262
+ end
263
+ Versionomy::Value._new(schema_, hash_, params_)
264
+ end
265
+
266
+
267
+ # Unparse a value for the standard schema.
268
+
269
+ def unparse(schema_, value_, params_)
270
+ params_ = value_.parse_params.merge(params_)
271
+ str_ = "#{value_.major}.#{value_.minor}.#{value_.tiny}.#{value_.tiny2}"
272
+ (4 - (params_[:required_fields] || 2)).times{ str_.sub!(/\.0$/, '') }
273
+ case value_.release_type
274
+ when :prerelease
275
+ prerelease_required_fields_ = params_[:prerelease_required_fields] || 1
276
+ str_ << _create_separator(params_[:prerelease_symbol], @prerelease_symbol)
277
+ str_ << value_.prerelease_version.to_s
278
+ if value_.prerelease_minor > 0 || prerelease_required_fields_ > 1
279
+ str_ << ".#{value_.prerelease_minor}"
280
+ end
281
+ when :development
282
+ development_required_fields_ = params_[:development_required_fields] || 1
283
+ str_ << _create_separator(params_[:development_symbol], @development_symbol)
284
+ str_ << value_.development_version.to_s
285
+ if value_.development_minor > 0 || development_required_fields_ > 1
286
+ str_ << ".#{value_.development_minor}"
287
+ end
288
+ when :alpha
289
+ alpha_required_fields_ = params_[:alpha_required_fields] || 1
290
+ str_ << _create_separator(params_[:alpha_symbol], @alpha_symbol)
291
+ str_ << value_.alpha_version.to_s
292
+ if value_.alpha_minor > 0 || alpha_required_fields_ > 1
293
+ str_ << ".#{value_.alpha_minor}"
294
+ end
295
+ when :beta
296
+ beta_required_fields_ = params_[:beta_required_fields] || 1
297
+ str_ << _create_separator(params_[:beta_symbol], @beta_symbol)
298
+ str_ << value_.beta_version.to_s
299
+ if value_.beta_minor > 0 || beta_required_fields_ > 1
300
+ str_ << ".#{value_.beta_minor}"
301
+ end
302
+ when :release_candidate
303
+ release_candidate_required_fields_ = params_[:release_candidate_required_fields] || 1
304
+ str_ << _create_separator(params_[:release_candidate_symbol], @release_candidate_symbol)
305
+ str_ << value_.release_candidate_version.to_s
306
+ if value_.release_candidate_minor > 0 || release_candidate_required_fields_ > 1
307
+ str_ << ".#{value_.release_candidate_minor}"
308
+ end
309
+ else
310
+ patchlevel_required_fields_ = params_[:patchlevel_required_fields] || 0
311
+ if value_.patchlevel > 0 || patchlevel_required_fields_ > 0
312
+ if params_[:patchlevel_format] == :alpha_lower
313
+ str_.concat(96 + value_.patchlevel)
314
+ elsif params_[:patchlevel_format] == :alpha_upper
315
+ str_.concat(64 + value_.patchlevel)
316
+ else
317
+ str_ << _create_separator(params_[:patchlevel_separator], @patchlevel_separator)
318
+ str_ << value_.patchlevel.to_s
319
+ if value_.patchlevel_minor > 0 || patchlevel_required_fields_ > 1
320
+ str_ << ".#{value_.patchlevel_minor}"
321
+ end
322
+ end
323
+ end
324
+ end
325
+ str_
326
+ end
327
+
328
+ end
329
+
330
+
331
+ # Get the standard schema
332
+
333
+ def self.schema
334
+ @standard_schema ||= SchemaCreator._create_schema
335
+ end
336
+
337
+
338
+ module SchemaCreator # :nodoc:
339
+
340
+ def self._create_schema
341
+ Schema.new(:major, :initial => 1) do
342
+ schema(:minor) do
343
+ schema(:tiny) do
344
+ schema(:tiny2) do
345
+ schema(:release_type, :type => :symbol) do
346
+ symbol(:prerelease, :bump => :release)
347
+ symbol(:development, :bump => :alpha)
348
+ symbol(:alpha, :bump => :beta)
349
+ symbol(:beta, :bump => :release_candidate)
350
+ symbol(:release_candidate, :bump => :release)
351
+ symbol(:release, :bump => :release)
352
+ initial_value(:release)
353
+ schema(:prerelease_version, :only => :prerelease, :initial => 1) do
354
+ schema(:prerelease_minor)
355
+ end
356
+ schema(:development_version, :only => :development, :initial => 1) do
357
+ schema(:development_minor)
358
+ end
359
+ schema(:alpha_version, :only => :alpha, :initial => 1) do
360
+ schema(:alpha_minor)
361
+ end
362
+ schema(:beta_version, :only => :beta, :initial => 1) do
363
+ schema(:beta_minor)
364
+ end
365
+ schema(:release_candidate_version, :only => :release_candidate, :initial => 1) do
366
+ schema(:release_candidate_minor)
367
+ end
368
+ schema(:patchlevel, :only => :release) do
369
+ schema(:patchlevel_minor)
370
+ end
371
+ end
372
+ end
373
+ end
374
+ end
375
+ define_format(:default, StandardFormat.new)
376
+ end
377
+ end
378
+
379
+
380
+ end
381
+
382
+ end
383
+
384
+
385
+ end
@@ -0,0 +1,291 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Versionomy value
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2008 Daniel Azuma
7
+ #
8
+ # All rights reserved.
9
+ #
10
+ # Redistribution and use in source and binary forms, with or without
11
+ # modification, are permitted provided that the following conditions are met:
12
+ #
13
+ # * Redistributions of source code must retain the above copyright notice,
14
+ # this list of conditions and the following disclaimer.
15
+ # * Redistributions in binary form must reproduce the above copyright notice,
16
+ # this list of conditions and the following disclaimer in the documentation
17
+ # and/or other materials provided with the distribution.
18
+ # * Neither the name of the copyright holder, nor the names of any other
19
+ # contributors to this software, may be used to endorse or promote products
20
+ # derived from this software without specific prior written permission.
21
+ #
22
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32
+ # POSSIBILITY OF SUCH DAMAGE.
33
+ # -----------------------------------------------------------------------------
34
+ ;
35
+
36
+
37
+ module Versionomy
38
+
39
+
40
+ # === Version number value
41
+ #
42
+ # A version number value is an ordered list of values, corresponding to an
43
+ # ordered list of fields defined by a schema. For example, if the schema
44
+ # is a simple one of the form "major.minor.tiny", then the the version
45
+ # number "1.4.2" would have the values <tt>[1, 4, 2]</tt> in that order,
46
+ # corresponding to the fields <tt>[:major, :minor, :tiny]</tt>.
47
+ #
48
+ # Version number values are comparable with other values that have the same
49
+ # form.
50
+
51
+ class Value
52
+
53
+
54
+ def initialize(schema_, values_=nil, parse_params_=nil, subvalue_=nil) # :nodoc:
55
+ @schema = schema_
56
+ val_ = nil
57
+ case values_
58
+ when Hash
59
+ val_ = values_[@schema.name]
60
+ when Array
61
+ val_ = values_.first
62
+ values_ = values_[1..-1]
63
+ else
64
+ val_ = values_
65
+ values_ = nil
66
+ end
67
+ @value = val_ ? @schema.canonicalize_value(val_) : @schema.initial_value
68
+ @parse_params = parse_params_ || Hash.new
69
+ if subvalue_
70
+ @subvalue = subvalue_
71
+ else
72
+ subschema_ = @schema._subschema(@value)
73
+ @subvalue = subschema_ ? Versionomy::Value._new(subschema_, values_) : nil
74
+ end
75
+ end
76
+
77
+
78
+ # Returns a string representation generated by unparsing.
79
+ # If unparsing fails, does not raise Versionomy::Errors::ParseError,
80
+ # but instead returns the string generated by +inspect+.
81
+ #
82
+
83
+ def to_s
84
+ begin
85
+ unparse
86
+ rescue Versionomy::Errors::ParseError
87
+ inspect
88
+ end
89
+ end
90
+
91
+
92
+ # Unparse this version number.
93
+ #
94
+ # Raises Versionomy::Errors::ParseError if unparsing failed.
95
+
96
+ def unparse(params_={})
97
+ format_ = @schema.get_format(params_[:format])
98
+ if format_.nil?
99
+ raise Versionomy::Errors::UnknownFormatError
100
+ end
101
+ format_.unparse(@schema, self, params_)
102
+ end
103
+
104
+
105
+ # Return the schema defining the form of this version number
106
+
107
+ def schema
108
+ @schema
109
+ end
110
+
111
+
112
+ # Return the parsing parameters for this value.
113
+
114
+ def parse_params
115
+ @parse_params
116
+ end
117
+
118
+
119
+ # Returns an array of recognized field names for this value, in field order.
120
+ def fields
121
+ @subvalue ? @subvalue.fields.unshift(@schema.name) : [@schema.name]
122
+ end
123
+
124
+
125
+ # Returns true if this value contains the given field.
126
+
127
+ def has_field?(symbol_)
128
+ symbol_ = symbol_.to_sym
129
+ if symbol_ == @schema.name
130
+ true
131
+ elsif @subvalue
132
+ @subvalue.has_field?(symbol_)
133
+ else
134
+ false
135
+ end
136
+ end
137
+
138
+
139
+ # Returns the value of the given field, or nil if the field is not recognized.
140
+
141
+ def [](symbol_)
142
+ symbol_ = symbol_ ? symbol_.to_sym : @schema.name
143
+ if symbol_ == @schema.name
144
+ @value
145
+ elsif @subvalue
146
+ @subvalue[symbol_]
147
+ else
148
+ nil
149
+ end
150
+ end
151
+
152
+
153
+ # Returns the value as an array of field values, in field order.
154
+
155
+ def value_array
156
+ @subvalue ? @subvalue.value_array.unshift(@value) : [@value]
157
+ end
158
+
159
+
160
+ # Returns the value as a hash of values keyed by field name.
161
+
162
+ def value_hash
163
+ hash_ = {@schema.name => @value}
164
+ @subvalue ? @subvalue.value_hash.merge(hash_) : hash_
165
+ end
166
+
167
+
168
+ # Returns a new version number created by bumping the given field.
169
+
170
+ def bump(symbol_)
171
+ if (symbol_ == @schema.name)
172
+ bumped_ = @schema.bump_value(@value)
173
+ if bumped_ == @value
174
+ self
175
+ else
176
+ Versionomy::Value._new(@schema, bumped_, @parse_params)
177
+ end
178
+ else
179
+ if @subvalue
180
+ bumped_ = @subvalue.bump(symbol_)
181
+ if @subvalue.equal?(bumped_)
182
+ self
183
+ else
184
+ Versionomy::Value._new(@schema, @value, @parse_params, bumped_)
185
+ end
186
+ else
187
+ self
188
+ end
189
+ end
190
+ end
191
+
192
+
193
+ # Returns a new version number created by changing the given field values.
194
+
195
+ def change(values_={})
196
+ Versionomy::Value._new(@schema, value_hash.merge(values_), @parse_params)
197
+ end
198
+
199
+
200
+ # Returns true if this version number is equal to the given verison number.
201
+ # Equality means the values and field names are the same, although the
202
+ # schemas may actually be different.
203
+
204
+ def eql?(obj_)
205
+ return false unless obj_.kind_of?(Versionomy::Value)
206
+ return false if @schema.name != obj_.schema.name || @value != obj_.toplevel_value
207
+ @subvalue.eql?(obj_.subvalue)
208
+ end
209
+
210
+
211
+ # Returns true if this version number is equal to the given verison number.
212
+ # Equality means the values and field names are the same, even if the schemas
213
+ # are different.
214
+
215
+ def ==(obj_)
216
+ eql?(obj_)
217
+ end
218
+
219
+
220
+ # Compare this version number with the given version number.
221
+ # Version numbers with the same field names and types are comparable,
222
+ # even if the schemas are different.
223
+
224
+ def <=>(obj_)
225
+ return nil unless obj_.kind_of?(Versionomy::Value)
226
+ return nil if @schema.name != obj_.schema.name
227
+ val_ = @schema.compare_values(@value, obj_.toplevel_value)
228
+ if val_ == 0
229
+ if @subvalue.nil?
230
+ obj_.subvalue.nil? ? 0 : nil
231
+ else
232
+ @subvalue <=> obj_.subvalue
233
+ end
234
+ else
235
+ val_
236
+ end
237
+ end
238
+
239
+
240
+ # Compare this version number with the given version number.
241
+ # Version numbers with the same field names and types are comparable,
242
+ # even if the schemas are different.
243
+
244
+ def <(obj_)
245
+ (self <=> obj_) < 0
246
+ end
247
+
248
+
249
+ # Compare this version number with the given version number.
250
+ # Version numbers with the same field names and types are comparable,
251
+ # even if the schemas are different.
252
+
253
+ def >(obj_)
254
+ (self <=> obj_) > 0
255
+ end
256
+
257
+
258
+ # Get the value of the most significant field
259
+
260
+ def toplevel_value
261
+ @value
262
+ end
263
+
264
+
265
+ # Get a value representing all fields except the most significant field
266
+
267
+ def subvalue
268
+ @subvalue
269
+ end
270
+
271
+
272
+ # Field values may be retrieved by calling them as methods.
273
+
274
+ def method_missing(symbol_)
275
+ self[symbol_] || super
276
+ end
277
+
278
+
279
+ class << self
280
+
281
+ # :stopdoc:
282
+ alias_method :_new, :new
283
+ private :new
284
+ # :startdoc:
285
+
286
+ end
287
+
288
+ end
289
+
290
+
291
+ end