versionomy 0.4.1 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,15 +1,15 @@
1
1
  # -----------------------------------------------------------------------------
2
- #
2
+ #
3
3
  # Versionomy schema wrapper class
4
- #
4
+ #
5
5
  # -----------------------------------------------------------------------------
6
6
  # Copyright 2008-2009 Daniel Azuma
7
- #
7
+ #
8
8
  # All rights reserved.
9
- #
9
+ #
10
10
  # Redistribution and use in source and binary forms, with or without
11
11
  # modification, are permitted provided that the following conditions are met:
12
- #
12
+ #
13
13
  # * Redistributions of source code must retain the above copyright notice,
14
14
  # this list of conditions and the following disclaimer.
15
15
  # * Redistributions in binary form must reproduce the above copyright notice,
@@ -18,7 +18,7 @@
18
18
  # * Neither the name of the copyright holder, nor the names of any other
19
19
  # contributors to this software, may be used to endorse or promote products
20
20
  # derived from this software without specific prior written permission.
21
- #
21
+ #
22
22
  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
23
  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
24
  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -35,17 +35,17 @@
35
35
 
36
36
 
37
37
  module Versionomy
38
-
38
+
39
39
  module Schema
40
-
41
-
40
+
41
+
42
42
  # Creates a schema.
43
43
  # Returns an object of type Versionomy::Schema::Wrapper.
44
- #
44
+ #
45
45
  # You may either pass a root field, or provide a block to use to build
46
46
  # fields. If you provide a block, you must use the methods in
47
47
  # Versionomy::Schema::Builder in the block to create the root field.
48
-
48
+
49
49
  def self.create(field_=nil, opts_={}, &block_)
50
50
  if field_ && block_
51
51
  raise ::ArgumentError, 'You may provide either a root field or block but not both'
@@ -61,17 +61,17 @@ module Versionomy
61
61
  end
62
62
  Schema::Wrapper.new(field_, modules_, aliases_)
63
63
  end
64
-
65
-
64
+
65
+
66
66
  # Schemas are generally referenced through an object of this class.
67
-
67
+
68
68
  class Wrapper
69
-
70
-
69
+
70
+
71
71
  # Create a new schema wrapper object given a root field.
72
72
  # This is a low-level method. Usually you should call
73
73
  # Versionomy::Schema#create instead.
74
-
74
+
75
75
  def initialize(field_, modules_=[], aliases_={})
76
76
  @root_field = field_
77
77
  @names = @root_field._descendants_by_name
@@ -85,43 +85,43 @@ module Versionomy
85
85
  end
86
86
  end
87
87
  end
88
-
89
-
88
+
89
+
90
90
  def inspect # :nodoc:
91
91
  "#<#{self.class}:0x#{object_id.to_s(16)} root=#{@root_field.inspect}>"
92
92
  end
93
-
93
+
94
94
  def to_s # :nodoc:
95
95
  inspect
96
96
  end
97
-
98
-
97
+
98
+
99
99
  # Returns true if this schema is equivalent to the other schema.
100
100
  # Two schemas are equivalent if their root fields are the same--
101
101
  # which means that the entire field tree is the same-- and they
102
102
  # include the same value modules.
103
103
  # Note that this is different from the definition of <tt>==</tt>.
104
-
104
+
105
105
  def eql?(obj_)
106
106
  return false unless obj_.kind_of?(Schema::Wrapper)
107
107
  return @root_field == obj_.root_field && @modules == obj_.modules && @aliases == obj_.aliases
108
108
  end
109
-
110
-
109
+
110
+
111
111
  # Returns true if this schema is compatible with the other schema.
112
112
  # Two schemas are compatible if their root fields are the same--
113
113
  # which means that the entire field tree is the same. They may,
114
114
  # however, include different value modules.
115
115
  # Note that this is different from the definition of <tt>eql?</tt>.
116
-
116
+
117
117
  def ==(obj_)
118
118
  eql?(obj_)
119
119
  end
120
-
121
-
120
+
121
+
122
122
  # If the RHS is a schema, returns true if the schemas are equivalent.
123
123
  # If the RHS is a value, returns true if the value uses this schema.
124
-
124
+
125
125
  def ===(obj_)
126
126
  if obj_.kind_of?(Value)
127
127
  obj_.schema == self
@@ -129,86 +129,86 @@ module Versionomy
129
129
  obj_ == self
130
130
  end
131
131
  end
132
-
133
-
132
+
133
+
134
134
  def hash # :nodoc:
135
135
  @hash ||= @root_field.hash ^ @modules.hash
136
136
  end
137
-
138
-
137
+
138
+
139
139
  # Returns the root (most significant) field in this schema.
140
-
140
+
141
141
  def root_field
142
142
  @root_field
143
143
  end
144
-
145
-
144
+
145
+
146
146
  # Return the canonical field name given a name, or nil if the name
147
147
  # is not recognized.
148
-
148
+
149
149
  def canonical_name(name_)
150
150
  name_ = name_.to_sym
151
151
  name_ = @aliases[name_] || name_
152
152
  @names.include?(name_) ? name_ : nil
153
153
  end
154
-
155
-
154
+
155
+
156
156
  # Return the field with the given name, or nil if the given name
157
157
  # is not found in this schema. If include_aliases_ is set to true,
158
158
  # this also supports lookup by alias.
159
-
159
+
160
160
  def field_named(name_, include_aliases_=false)
161
161
  name_ = name_.to_sym
162
162
  name_ = @aliases[name_] || name_ if include_aliases_
163
163
  field_ = @names[name_]
164
164
  end
165
-
166
-
165
+
166
+
167
167
  # Returns an array of names present in this schema, in no particular
168
168
  # order. Does not include aliases.
169
-
169
+
170
170
  def names
171
171
  @names.keys
172
172
  end
173
-
174
-
173
+
174
+
175
175
  # Returns an array of modules that should be included in values that
176
176
  # use this schema.
177
-
177
+
178
178
  def modules
179
179
  @modules.dup
180
180
  end
181
-
182
-
181
+
182
+
183
183
  # Returns a hash of field name aliases.
184
-
184
+
185
185
  def aliases
186
186
  @aliases.dup
187
187
  end
188
-
189
-
188
+
189
+
190
190
  end
191
-
192
-
191
+
192
+
193
193
  # These methods are available in a schema definition block given to
194
194
  # Versionomy::Schema#create.
195
-
195
+
196
196
  class Builder
197
-
197
+
198
198
  include ::Blockenspiel::DSL
199
-
199
+
200
200
  def initialize() # :nodoc:
201
201
  @field = nil
202
202
  @modules = []
203
203
  @aliases = {}
204
204
  @defaults = { :integer => {}, :string => {}, :symbol => {} }
205
205
  end
206
-
207
-
206
+
207
+
208
208
  # Create the root field.
209
- #
209
+ #
210
210
  # Recognized options include:
211
- #
211
+ #
212
212
  # <tt>:type</tt>::
213
213
  # Type of field. This should be <tt>:integer</tt>, <tt>:string</tt>,
214
214
  # or <tt>:symbol</tt>. Default is <tt>:integer</tt>.
@@ -216,51 +216,51 @@ module Versionomy
216
216
  # Default value for the field if no value is explicitly set. Default
217
217
  # is 0 for an integer field, the empty string for a string field, or
218
218
  # the first symbol added for a symbol field.
219
- #
219
+ #
220
220
  # You may provide an optional block. Within the block, you may call
221
221
  # methods of Versionomy::Schema::FieldBuilder to customize this field.
222
- #
222
+ #
223
223
  # Raises Versionomy::Errors::IllegalValueError if the given default
224
224
  # value is not legal.
225
- #
225
+ #
226
226
  # Raises Versionomy::Errors::RangeOverlapError if a root field has
227
227
  # already been created.
228
-
228
+
229
229
  def field(name_, opts_={}, &block_)
230
230
  if @field
231
231
  raise Errors::RangeOverlapError, "Root field already defined"
232
232
  end
233
233
  @field = Schema::Field.new(name_, opts_.merge(:master_builder => self), &block_)
234
234
  end
235
-
236
-
235
+
236
+
237
237
  # Create a field alias.
238
-
238
+
239
239
  def alias_field(alias_name_, field_name_)
240
240
  @aliases[alias_name_.to_sym] = field_name_.to_sym
241
241
  end
242
-
243
-
242
+
243
+
244
244
  # Add a module to the schema. All values that use this schema will
245
245
  # include this module. This provides a way to add schema-specific
246
246
  # capabilities to version numbers.
247
-
247
+
248
248
  def add_module(mod_)
249
249
  @modules << mod_
250
250
  end
251
-
252
-
251
+
252
+
253
253
  # Provide a default bump procedure for the given type.
254
254
  # The type should be <tt>:integer</tt>, <tt>:string</tt>, or
255
255
  # <tt>:symbol</tt>. You must provide a block that takes a field value
256
256
  # and returns the "bumped" value. This procedure will be used for
257
257
  # all fields of this type, unless explicitly overridden by the field.
258
-
258
+
259
259
  def to_bump_type(type_, &block_)
260
260
  @defaults[type_][:bump] = block_
261
261
  end
262
-
263
-
262
+
263
+
264
264
  # Provide a default compare procedure for the given type.
265
265
  # The type should be <tt>:integer</tt>, <tt>:string</tt>, or
266
266
  # <tt>:symbol</tt>. You must provide a block that takes two values
@@ -269,53 +269,53 @@ module Versionomy
269
269
  # positive integer if the first value is greater. This procedure will
270
270
  # be used for all fields of this type, unless explicitly overridden
271
271
  # by the field.
272
-
272
+
273
273
  def to_compare_type(type_, &block_)
274
274
  @defaults[type_][:compare] = block_
275
275
  end
276
-
277
-
276
+
277
+
278
278
  # Provide a default canonicalization procedure for the given type.
279
279
  # The type should be <tt>:integer</tt>, <tt>:string</tt>, or
280
280
  # <tt>:symbol</tt>. You must provide a block that takes a field value
281
281
  # and returns the canonical value. This procedure will be used for
282
282
  # all fields of this type, unless explicitly overridden by the field.
283
-
283
+
284
284
  def to_canonicalize_type(type_, &block_)
285
285
  @defaults[type_][:canonicalize] = block_
286
286
  end
287
-
288
-
287
+
288
+
289
289
  # Provide a default value for the given type.
290
290
  # The type should be <tt>:integer</tt>, <tt>:string</tt>, or
291
291
  # <tt>:symbol</tt>. You must provide a default value that will be
292
292
  # used for all fields of this type, unless explicitly overridden by
293
293
  # the field.
294
-
294
+
295
295
  def default_value_for_type(type_, value_)
296
296
  @defaults[type_][:value] = value_
297
297
  end
298
-
299
-
298
+
299
+
300
300
  def _get_field # :nodoc:
301
301
  @field
302
302
  end
303
-
303
+
304
304
  def _get_modules # :nodoc:
305
305
  @modules
306
306
  end
307
-
307
+
308
308
  def _get_aliases # :nodoc:
309
309
  @aliases
310
310
  end
311
-
311
+
312
312
  def _get_default_setting(type_, setting_) # :nodoc:
313
313
  @defaults[type_][setting_]
314
314
  end
315
-
315
+
316
316
  end
317
-
318
-
317
+
318
+
319
319
  end
320
-
320
+
321
321
  end
@@ -1,15 +1,15 @@
1
1
  # -----------------------------------------------------------------------------
2
- #
2
+ #
3
3
  # Versionomy value
4
- #
4
+ #
5
5
  # -----------------------------------------------------------------------------
6
6
  # Copyright 2008-2009 Daniel Azuma
7
- #
7
+ #
8
8
  # All rights reserved.
9
- #
9
+ #
10
10
  # Redistribution and use in source and binary forms, with or without
11
11
  # modification, are permitted provided that the following conditions are met:
12
- #
12
+ #
13
13
  # * Redistributions of source code must retain the above copyright notice,
14
14
  # this list of conditions and the following disclaimer.
15
15
  # * Redistributions in binary form must reproduce the above copyright notice,
@@ -18,7 +18,7 @@
18
18
  # * Neither the name of the copyright holder, nor the names of any other
19
19
  # contributors to this software, may be used to endorse or promote products
20
20
  # derived from this software without specific prior written permission.
21
- #
21
+ #
22
22
  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23
23
  # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
24
  # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -34,35 +34,39 @@
34
34
  ;
35
35
 
36
36
 
37
- require 'yaml'
37
+ begin
38
+ require 'psych'
39
+ rescue ::LoadError
40
+ require 'yaml'
41
+ end
38
42
 
39
43
 
40
44
  module Versionomy
41
-
42
-
45
+
46
+
43
47
  # === Version number value
44
- #
48
+ #
45
49
  # A version number value is an ordered list of values, corresponding to an
46
50
  # ordered list of fields defined by a schema. For example, if the schema
47
51
  # is a simple one of the form "major.minor.tiny", then the the version
48
52
  # number "1.4.2" would have the values <tt>[1, 4, 2]</tt> in that order,
49
53
  # corresponding to the fields <tt>[:major, :minor, :tiny]</tt>.
50
- #
54
+ #
51
55
  # Version number values are comparable with other values that have an
52
56
  # equivalent schema.
53
-
57
+
54
58
  class Value
55
-
56
-
59
+
60
+
57
61
  # Create a value, given a hash or array of values, and a format. Both
58
62
  # these parameters are required.
59
- #
63
+ #
60
64
  # The values should either be a hash of field names and values, or an
61
65
  # array of values that will be interpreted in field order.
62
- #
66
+ #
63
67
  # You can also optionally provide default unparsing parameters for the
64
68
  # value.
65
-
69
+
66
70
  def initialize(values_, format_, unparse_params_=nil)
67
71
  unless values_.kind_of?(::Hash) || values_.kind_of?(::Array)
68
72
  raise ::ArgumentError, "Expected hash or array but got #{values_.class}"
@@ -83,8 +87,8 @@ module Versionomy
83
87
  modules_ = @_format.schema.modules
84
88
  extend(*modules_) if modules_.size > 0
85
89
  end
86
-
87
-
90
+
91
+
88
92
  def inspect # :nodoc:
89
93
  begin
90
94
  str_ = unparse
@@ -93,17 +97,17 @@ module Versionomy
93
97
  _inspect
94
98
  end
95
99
  end
96
-
100
+
97
101
  def _inspect # :nodoc:
98
102
  "#<#{self.class}:0x#{object_id.to_s(16)} " +
99
103
  @_field_path.map{ |field_| "#{field_.name}=#{@_values[field_.name].inspect}" }.join(' ')
100
104
  end
101
-
102
-
105
+
106
+
103
107
  # Returns a string representation generated by unparsing.
104
108
  # If unparsing fails, does not raise Versionomy::Errors::UnparseError,
105
109
  # but instead returns the string generated by +inspect+.
106
-
110
+
107
111
  def to_s
108
112
  begin
109
113
  unparse
@@ -111,149 +115,72 @@ module Versionomy
111
115
  _inspect
112
116
  end
113
117
  end
114
-
115
-
116
- # Marshal this version number.
117
-
118
- def marshal_dump # :nodoc:
119
- format_name_ = Format.canonical_name_for(@_format, true)
120
- unparsed_data_ = nil
121
- if @_format.respond_to?(:unparse_for_serialization)
122
- unparsed_data_ = @_format.unparse_for_serialization(self) rescue nil
123
- end
124
- unparsed_data_ ||= @_format.unparse(self) rescue nil
125
- data_ = [format_name_]
126
- case unparsed_data_
127
- when ::Array
128
- data_ << unparsed_data_[0]
129
- data_ << unparsed_data_[1] if unparsed_data_[1]
130
- when ::String
131
- data_ << unparsed_data_
132
- else
133
- data_ << values_array
134
- data_ << @_unparse_params if @_unparse_params
135
- end
136
- data_
137
- end
138
-
139
-
140
- # Unmarshal this version number.
141
-
142
- def marshal_load(data_) # :nodoc:
143
- format_ = Format.get(data_[0], true)
144
- if data_[1].kind_of?(::String)
145
- val_ = format_.parse(data_[1], data_[2])
146
- initialize(val_.values_array, format_, val_.unparse_params)
147
- else
148
- initialize(data_[1], format_, data_[2])
149
- end
150
- end
151
-
152
-
153
- # YAML tags. The last one is the canonical one.
154
- yaml_as "tag:danielazuma.com,2009:version"
155
- yaml_as "tag:verse15.com,2009:version"
156
-
157
-
158
- # Deserialize a version number from YAML
159
-
160
- def self.yaml_new(klass_, tag_, data_) # :nodoc:
161
- unless data_.kind_of?(::Hash)
162
- raise ::YAML::TypeError, "Invalid version format: #{val_.inspect}"
163
- end
164
- format_ = Format.get(data_['format'], true)
165
- value_ = data_['value']
166
- if value_
167
- format_.parse(value_, data_['parse_params'])
168
- else
169
- Value.new(format_, data_['fields'], data_['unparse_params'])
170
- end
171
- end
172
-
173
-
174
- # Serialize this version number to YAML format.
175
-
176
- def to_yaml(opts_={})
177
- data_ = marshal_dump
178
- ::YAML::quick_emit(nil, opts_) do |out_|
179
- out_.map(taguri, to_yaml_style) do |map_|
180
- map_.add('format', data_[0])
181
- if data_[1].kind_of?(::String)
182
- map_.add('value', data_[1])
183
- map_.add('parse_params', data_[2]) if data_[2]
184
- else
185
- map_.add('fields', data_[1])
186
- map_.add('unparse_params', data_[2]) if data_[2]
187
- end
188
- end
189
- end
190
- end
191
-
192
-
118
+
119
+
193
120
  # Unparse this version number and return a string.
194
- #
121
+ #
195
122
  # Raises Versionomy::Errors::UnparseError if unparsing failed.
196
-
123
+
197
124
  def unparse(params_=nil)
198
125
  @_format.unparse(self, params_)
199
126
  end
200
-
201
-
127
+
128
+
202
129
  # Return the schema defining the structure and semantics of this
203
130
  # version number.
204
-
131
+
205
132
  def schema
206
133
  @_format.schema
207
134
  end
208
-
209
-
135
+
136
+
210
137
  # Return the format defining the schema and formatting/parsing of
211
138
  # this version number.
212
-
139
+
213
140
  def format
214
141
  @_format
215
142
  end
216
-
217
-
143
+
144
+
218
145
  # Return the unparsing parameters for this value.
219
146
  # Returns nil if this value was not created using a parser.
220
-
147
+
221
148
  def unparse_params
222
149
  @_unparse_params ? @_unparse_params.dup : nil
223
150
  end
224
-
225
-
151
+
152
+
226
153
  # Iterates over each field, in field order, yielding the field name and value.
227
-
154
+
228
155
  def each_field
229
156
  @_field_path.each do |field_|
230
157
  yield(field_, @_values[field_.name])
231
158
  end
232
159
  end
233
-
234
-
160
+
161
+
235
162
  # Iterates over each field, in field order, yielding the
236
163
  # Versionomy::Schema::Field object and value.
237
-
164
+
238
165
  def each_field_object # :nodoc:
239
166
  @_field_path.each do |field_|
240
167
  yield(field_, @_values[field_.name])
241
168
  end
242
169
  end
243
-
244
-
170
+
171
+
245
172
  # Returns an array of recognized field names for this value, in field order.
246
173
  # This is the order of the fields actually present in this value, in
247
174
  # order from most to least significant.
248
-
175
+
249
176
  def field_names
250
177
  @_field_path.map{ |field_| field_.name }
251
178
  end
252
-
253
-
179
+
180
+
254
181
  # Returns true if this value contains the given field, which may be specified
255
182
  # as a field object, name, or index.
256
-
183
+
257
184
  def has_field?(field_)
258
185
  case field_
259
186
  when Schema::Field
@@ -266,38 +193,38 @@ module Versionomy
266
193
  raise ::ArgumentError
267
194
  end
268
195
  end
269
-
270
-
196
+
197
+
271
198
  # Returns the value of the given field, or nil if the field is not
272
199
  # recognized. The field may be specified as a field object, field name,
273
200
  # or field index.
274
-
201
+
275
202
  def [](field_)
276
203
  @_values[_interpret_field(field_)]
277
204
  end
278
-
279
-
205
+
206
+
280
207
  # Returns the value as an array of field values, in field order.
281
208
  # This is the order of the fields actually present in this value, in
282
209
  # order from most to least significant.
283
-
210
+
284
211
  def values_array
285
212
  @_field_path.map{ |field_| @_values[field_.name] }
286
213
  end
287
-
288
-
214
+
215
+
289
216
  # Returns the value as a hash of values keyed by field name.
290
-
217
+
291
218
  def values_hash
292
219
  @_values.dup
293
220
  end
294
-
295
-
221
+
222
+
296
223
  # Returns a new version number created by bumping the given field. The
297
224
  # field may be specified as a field object, field name, or field index.
298
225
  # Returns self unchanged if the field was not recognized or could not
299
226
  # be modified.
300
-
227
+
301
228
  def bump(field_)
302
229
  name_ = _interpret_field(field_)
303
230
  return self unless name_ && @_values.include?(name_)
@@ -315,13 +242,13 @@ module Versionomy
315
242
  end
316
243
  self
317
244
  end
318
-
319
-
245
+
246
+
320
247
  # Returns a new version number created by resetting the given field. The
321
248
  # field may be specified as a field object, field name, or field index.
322
249
  # Returns self unchanged if the field was not recognized or could not
323
250
  # be modified.
324
-
251
+
325
252
  def reset(field_)
326
253
  name_ = _interpret_field(field_)
327
254
  return self unless name_ && @_values.include?(name_)
@@ -337,33 +264,33 @@ module Versionomy
337
264
  end
338
265
  self
339
266
  end
340
-
341
-
267
+
268
+
342
269
  # Returns a new version number created by cloning this version number
343
270
  # and changing the given field values.
344
- #
271
+ #
345
272
  # You should pass in a hash of field names to values. These are the
346
273
  # fields to modify; any other fields will be left alone, unless they
347
274
  # are implicitly changed by the modifications you are making.
348
275
  # For example, changing the :release_type on a value using the standard
349
276
  # format, may change which fields are present in the resulting value.
350
- #
277
+ #
351
278
  # You may also pass a delta hash to modify the unparse params stored in
352
279
  # the value.
353
-
280
+
354
281
  def change(values_={}, unparse_params_={})
355
282
  unparse_params_ = @_unparse_params.merge(unparse_params_) if @_unparse_params
356
283
  values_ = _canonicalize_values_hash(values_)
357
284
  Value.new(@_values.merge(values_), @_format, unparse_params_)
358
285
  end
359
-
360
-
286
+
287
+
361
288
  # Attempts to convert this value to the given format, and returns the
362
289
  # resulting value.
363
- #
290
+ #
364
291
  # Raises Versionomy::Errors::ConversionError if the value could not
365
292
  # be converted.
366
-
293
+
367
294
  def convert(format_, convert_params_=nil)
368
295
  if format_.kind_of?(::String) || format_.kind_of?(::Symbol)
369
296
  format_ = Format.get(format_)
@@ -389,18 +316,18 @@ module Versionomy
389
316
  end
390
317
  end
391
318
  end
392
-
393
-
319
+
320
+
394
321
  def hash # :nodoc:
395
322
  @_hash ||= @_values.hash
396
323
  end
397
-
398
-
324
+
325
+
399
326
  # Returns true if this version number is equivalent to the given number.
400
327
  # This type of equality means their schemas are compatible and their
401
328
  # field values are equal.
402
329
  # Note that this is different from the definition of <tt>==</tt>.
403
-
330
+
404
331
  def eql?(obj_)
405
332
  if obj_.kind_of?(::String)
406
333
  obj_ = @_format.parse(obj_) rescue nil
@@ -413,25 +340,25 @@ module Versionomy
413
340
  end
414
341
  true
415
342
  end
416
-
417
-
343
+
344
+
418
345
  # Returns true if this version number is value-equal to the given number.
419
346
  # This type of equality means that they are equivalent, or that it is
420
347
  # possible to convert the RHS to the LHS's format, and that they would
421
348
  # be equivalent after such a conversion has taken place.
422
349
  # Note that this is different from the definition of <tt>eql?</tt>.
423
-
350
+
424
351
  def ==(obj_)
425
352
  (self <=> obj_) == 0
426
353
  end
427
-
428
-
354
+
355
+
429
356
  # Compare this version number with the given version number,
430
357
  # returning 0 if the two are value-equal, a negative number if the RHS
431
358
  # is greater, or a positive number if the LHS is greater.
432
359
  # The comparison may succeed even if the two have different schemas,
433
360
  # if the RHS can be converted to the LHS's format.
434
-
361
+
435
362
  def <=>(obj_)
436
363
  if obj_.kind_of?(::String)
437
364
  obj_ = @_format.parse(obj_)
@@ -450,12 +377,12 @@ module Versionomy
450
377
  end
451
378
  0
452
379
  end
453
-
454
-
380
+
381
+
455
382
  # Compare this version number with the given version number.
456
383
  # The comparison may succeed even if the two have different schemas,
457
384
  # if the RHS can be converted to the LHS's format.
458
-
385
+
459
386
  def <(obj_)
460
387
  val_ = (self <=> obj_)
461
388
  unless val_
@@ -463,12 +390,12 @@ module Versionomy
463
390
  end
464
391
  val_ < 0
465
392
  end
466
-
467
-
393
+
394
+
468
395
  # Compare this version number with the given version number.
469
396
  # The comparison may succeed even if the two have different schemas,
470
397
  # if the RHS can be converted to the LHS's format.
471
-
398
+
472
399
  def >(obj_)
473
400
  val_ = (self <=> obj_)
474
401
  unless val_
@@ -476,20 +403,137 @@ module Versionomy
476
403
  end
477
404
  val_ > 0
478
405
  end
479
-
480
-
406
+
407
+
481
408
  include ::Comparable
482
-
483
-
409
+
410
+
484
411
  # Field values may be retrieved by calling them as methods.
485
-
412
+
486
413
  def method_missing(symbol_)
487
414
  self[symbol_] || super
488
415
  end
489
-
490
-
416
+
417
+
418
+ # :stopdoc:
419
+
420
+
421
+ # Marshal support
422
+
423
+ # Marshal this version number
424
+ def marshal_dump
425
+ format_name_ = Format.canonical_name_for(@_format, true)
426
+ unparsed_data_ = nil
427
+ if @_format.respond_to?(:unparse_for_serialization)
428
+ unparsed_data_ = @_format.unparse_for_serialization(self) rescue nil
429
+ end
430
+ unparsed_data_ ||= @_format.unparse(self) rescue nil
431
+ data_ = [format_name_]
432
+ case unparsed_data_
433
+ when ::Array
434
+ data_ << unparsed_data_[0]
435
+ data_ << unparsed_data_[1] if unparsed_data_[1]
436
+ when ::String
437
+ data_ << unparsed_data_
438
+ else
439
+ data_ << values_array
440
+ data_ << @_unparse_params if @_unparse_params
441
+ end
442
+ data_
443
+ end
444
+
445
+ # Unmarshal this version number.
446
+ def marshal_load(data_)
447
+ format_ = Format.get(data_[0], true)
448
+ if data_[1].kind_of?(::String)
449
+ val_ = format_.parse(data_[1], data_[2])
450
+ initialize(val_.values_array, format_, val_.unparse_params)
451
+ else
452
+ initialize(data_[1], format_, data_[2])
453
+ end
454
+ end
455
+
456
+
457
+ if defined?(::Psych)
458
+
459
+ # YAML support through psych
460
+
461
+ # YAML tags. The last one is the canonical one.
462
+ yaml_tag "tag:danielazuma.com,2009:version"
463
+ yaml_tag "tag:verse15.com,2009:version"
464
+
465
+ # Deserialize a version number from YAML
466
+ def init_with(coder_) # :nodoc:
467
+ format_ = Format.get(coder_['format'], true)
468
+ value_ = coder_['value']
469
+ if value_
470
+ value_ = format_.parse(value_, coder_['parse_params'])
471
+ initialize(value_.values_array, format_, value_.unparse_params)
472
+ else
473
+ initialize(coder_['fields'], format_, coder_['unparse_params'])
474
+ end
475
+ end
476
+
477
+ # Serialize this version number to YAML format.
478
+ def encode_with(coder_) # :nodoc:
479
+ data_ = marshal_dump
480
+ coder_['format'] = data_[0]
481
+ if data_[1].kind_of?(::String)
482
+ coder_['value'] = data_[1]
483
+ coder_['parse_params'] = data_[2] if data_[2]
484
+ else
485
+ coder_['fields'] = data_[1]
486
+ coder_['unparse_params'] = data_[2] if data_[2]
487
+ end
488
+ end
489
+
490
+ else
491
+
492
+ # YAML support through syck
493
+
494
+ # YAML tags. The last one is the canonical one.
495
+ yaml_as "tag:danielazuma.com,2009:version"
496
+ yaml_as "tag:verse15.com,2009:version"
497
+
498
+ # Deserialize a version number from YAML
499
+ def self.yaml_new(klass_, tag_, data_) # :nodoc:
500
+ unless data_.kind_of?(::Hash)
501
+ raise ::YAML::TypeError, "Invalid version format: #{data_.inspect}"
502
+ end
503
+ format_ = Format.get(data_['format'], true)
504
+ value_ = data_['value']
505
+ if value_
506
+ format_.parse(value_, data_['parse_params'])
507
+ else
508
+ Value.new(data_['fields'], format_, data_['unparse_params'])
509
+ end
510
+ end
511
+
512
+ # Serialize this version number to YAML format.
513
+ def to_yaml(opts_={})
514
+ data_ = marshal_dump
515
+ ::YAML.quick_emit(nil, opts_) do |out_|
516
+ out_.map(taguri, to_yaml_style) do |map_|
517
+ map_.add('format', data_[0])
518
+ if data_[1].kind_of?(::String)
519
+ map_.add('value', data_[1])
520
+ map_.add('parse_params', data_[2]) if data_[2]
521
+ else
522
+ map_.add('fields', data_[1])
523
+ map_.add('unparse_params', data_[2]) if data_[2]
524
+ end
525
+ end
526
+ end
527
+ end
528
+
529
+ end
530
+
531
+
532
+ # :startdoc:
533
+
534
+
491
535
  private
492
-
536
+
493
537
  def _interpret_field(field_) # :nodoc:
494
538
  case field_
495
539
  when Schema::Field
@@ -501,8 +545,8 @@ module Versionomy
501
545
  @_format.schema.canonical_name(field_)
502
546
  end
503
547
  end
504
-
505
-
548
+
549
+
506
550
  def _canonicalize_values_hash(values_) # :nodoc:
507
551
  schema_ = @_format.schema
508
552
  new_values_ = {}
@@ -512,9 +556,9 @@ module Versionomy
512
556
  end
513
557
  new_values_
514
558
  end
515
-
516
-
559
+
560
+
517
561
  end
518
-
519
-
562
+
563
+
520
564
  end