versionomy 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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