versionomy 0.4.1 → 0.4.2

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.
@@ -1,15 +1,15 @@
1
1
  # -----------------------------------------------------------------------------
2
- #
2
+ #
3
3
  # Versionomy schema namespace
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,10 +35,10 @@
35
35
 
36
36
 
37
37
  module Versionomy
38
-
39
-
38
+
39
+
40
40
  # === Version number schema.
41
- #
41
+ #
42
42
  # A schema defines the structure and semantics of a version number.
43
43
  # The schema controls what fields are present in the version, how
44
44
  # version numbers are compared, what the default values are, and how
@@ -46,50 +46,50 @@ module Versionomy
46
46
  # compared with one another, and version numbers can be converted
47
47
  # trivially to formats that share the same schema, without requiring a
48
48
  # Conversion implementation.
49
- #
49
+ #
50
50
  # At its simplest, a version number is defined as a sequence of fields,
51
51
  # each with a name and data type. These fields may be integer-valued,
52
52
  # string-valued, or symbolic, though most will probably be integers.
53
53
  # Symbolic fields are enumerated types that are useful, for example, if
54
54
  # you want a field to specify the type of prerelease (e.g. "alpha",
55
55
  # "beta", or "release candidate").
56
- #
56
+ #
57
57
  # As a simple conceptual example, you could construct a schema for
58
58
  # version numbers of the form "major.minor.tiny" like this. (This is a
59
59
  # conceptual diagram, not actual syntax.)
60
- #
60
+ #
61
61
  # ("major": integer), ("minor": integer), ("tiny": integer)
62
- #
62
+ #
63
63
  # More generally, fields are actually organized into a DAG (directed
64
64
  # acyclic graph) in which the "most significant" field is the root, the
65
65
  # next most significant is a child of that root, and so forth down the
66
66
  # line. The simple schema above, then, is actually represented as a
67
67
  # linked list (a graph with one path), like this:
68
- #
68
+ #
69
69
  # ("major": integer) ->
70
70
  # ("minor": integer) ->
71
71
  # ("tiny": integer) ->
72
72
  # nil
73
- #
73
+ #
74
74
  # It is, however, possible for the form of a field to depend on the value
75
75
  # of the previous field. For example, suppose we wanted a schema in which
76
76
  # if the value of the "minor" field is 0, then the "tiny" field doesn't
77
77
  # exist. e.g.
78
- #
78
+ #
79
79
  # ("major": integer) ->
80
80
  # ("minor": integer) ->
81
81
  # [value == 0] : nil
82
82
  # [otherwise] : ("tiny": integer) ->
83
83
  # nil
84
- #
84
+ #
85
85
  # The Versionomy::Schema::Field class represents a field in this graph.
86
86
  # The Versionomy::Schema::Wrapper class represents a full schema object.
87
- #
87
+ #
88
88
  # Generally, you should create schemas using Versionomy::Schema#create.
89
89
  # That method provides a DSL that lets you quickly create the fields.
90
-
90
+
91
91
  module Schema
92
92
  end
93
-
94
-
93
+
94
+
95
95
  end
@@ -1,15 +1,15 @@
1
1
  # -----------------------------------------------------------------------------
2
- #
2
+ #
3
3
  # Versionomy schema field 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
@@ -38,19 +38,19 @@ require 'set'
38
38
 
39
39
 
40
40
  module Versionomy
41
-
41
+
42
42
  module Schema
43
-
44
-
43
+
44
+
45
45
  # Objects of this class represent fields in a schema.
46
-
46
+
47
47
  class Field
48
-
49
-
48
+
49
+
50
50
  # Create a field with the given name.
51
- #
51
+ #
52
52
  # Recognized options include:
53
- #
53
+ #
54
54
  # <tt>:type</tt>::
55
55
  # Type of field. This should be <tt>:integer</tt>, <tt>:string</tt>,
56
56
  # or <tt>:symbol</tt>. Default is <tt>:integer</tt>.
@@ -58,14 +58,14 @@ module Versionomy
58
58
  # Default value for the field if no value is explicitly set. Default
59
59
  # is 0 for an integer field, the empty string for a string field, or
60
60
  # the first symbol added for a symbol field.
61
- #
61
+ #
62
62
  # You may provide an optional block. Within the block, you may call
63
63
  # methods of Versionomy::Schema::FieldBuilder to further customize the
64
64
  # field, or add child fields.
65
- #
65
+ #
66
66
  # Raises Versionomy::Errors::IllegalValueError if the given default
67
67
  # value is not legal.
68
-
68
+
69
69
  def initialize(name_, opts_={}, &block_)
70
70
  @name = name_.to_sym
71
71
  @type = opts_[:type] || :integer
@@ -93,12 +93,12 @@ module Versionomy
93
93
  ::Blockenspiel.invoke(block_, Schema::FieldBuilder.new(self, master_builder_)) if block_
94
94
  @default_value = canonicalize_value(@default_value)
95
95
  end
96
-
97
-
96
+
97
+
98
98
  def _set_default_value(value_) # :nodoc:
99
99
  @default_value = value_
100
100
  end
101
-
101
+
102
102
  def _add_symbol(symbol_, opts_={}) # :nodoc:
103
103
  if @type != :symbol
104
104
  raise Errors::TypeMismatchError
@@ -112,64 +112,64 @@ module Versionomy
112
112
  @default_value = symbol_
113
113
  end
114
114
  end
115
-
115
+
116
116
  def _set_bump_proc(block_) # :nodoc:
117
117
  @bump_proc = block_
118
118
  end
119
-
119
+
120
120
  def _set_canonicalize_proc(block_) # :nodoc:
121
121
  @canonicalize_proc = block_
122
122
  end
123
-
123
+
124
124
  def _set_compare_proc(block_) # :nodoc:
125
125
  @compare_proc = block_
126
126
  end
127
-
128
-
127
+
128
+
129
129
  def inspect # :nodoc:
130
130
  "#<#{self.class}:0x#{object_id.to_s(16)} name=#{@name}>"
131
131
  end
132
-
132
+
133
133
  def to_s # :nodoc:
134
134
  inspect
135
135
  end
136
-
137
-
136
+
137
+
138
138
  # The name of the field.
139
-
139
+
140
140
  def name
141
141
  @name
142
142
  end
143
-
144
-
143
+
144
+
145
145
  # The type of the field.
146
146
  # Possible values are <tt>:integer</tt>, <tt>:string</tt>, or
147
147
  # <tt>:symbol</tt>.
148
-
148
+
149
149
  def type
150
150
  @type
151
151
  end
152
-
153
-
152
+
153
+
154
154
  # The default value of the field
155
-
155
+
156
156
  def default_value
157
157
  @default_value
158
158
  end
159
-
160
-
159
+
160
+
161
161
  # Returns a list of possible values for this field, if the type is
162
162
  # <tt>:symbol</tt>. Returns nil for any other type
163
-
163
+
164
164
  def possible_values
165
165
  @symbol_order ? @symbol_order.dup : nil
166
166
  end
167
-
168
-
167
+
168
+
169
169
  # Given a value, bump it to the "next" value.
170
170
  # Utilizes a bump procedure if given;
171
171
  # otherwise uses default behavior depending on the type.
172
-
172
+
173
173
  def bump_value(value_)
174
174
  if @bump_proc
175
175
  nvalue_ = @bump_proc.call(value_)
@@ -181,13 +181,13 @@ module Versionomy
181
181
  info_ ? info_[1] || value_ : nil
182
182
  end
183
183
  end
184
-
185
-
184
+
185
+
186
186
  # Perform a standard comparison on two values.
187
187
  # Returns an integer that may be positive, negative, or 0.
188
188
  # Utilizes a comparison procedure if given;
189
189
  # otherwise uses default behavior depending on the type.
190
-
190
+
191
191
  def compare_values(val1_, val2_)
192
192
  if @compare_proc
193
193
  @compare_proc.call(val1_, val2_)
@@ -199,15 +199,15 @@ module Versionomy
199
199
  info1_ && info2_ ? info1_[0] <=> info2_[0] : nil
200
200
  end
201
201
  end
202
-
203
-
202
+
203
+
204
204
  # Given a value, return a "canonical" value for this field.
205
205
  # Utilizes a canonicalization procedure if given;
206
206
  # otherwise uses default behavior depending on the type.
207
- #
207
+ #
208
208
  # Raises Versionomy::Errors::IllegalValueError if the given value is
209
209
  # not legal.
210
-
210
+
211
211
  def canonicalize_value(value_)
212
212
  orig_value_ = value_
213
213
  if @canonicalize_proc
@@ -227,11 +227,11 @@ module Versionomy
227
227
  end
228
228
  value_
229
229
  end
230
-
231
-
230
+
231
+
232
232
  # Returns the child field associated with the given value.
233
233
  # Returns nil if this field has no child for the given value.
234
-
234
+
235
235
  def child(value_) # :nodoc:
236
236
  if @ranges
237
237
  @ranges.each do |r_|
@@ -248,30 +248,30 @@ module Versionomy
248
248
  end
249
249
  @default_child
250
250
  end
251
-
252
-
251
+
252
+
253
253
  # Adds the given child field for the given range.
254
- #
254
+ #
255
255
  # If you provide a range of nil, adds the given child field as the
256
256
  # default child for values that do not fall into any other
257
257
  # explicitly specified range.
258
- #
258
+ #
259
259
  # Otherwise, the ranges parameter must be an array of "range" objects.
260
260
  # Each of these range objects must be either a single String, Symbol,
261
261
  # or Integer to specify a single value; or a two-element array or a
262
262
  # Range object (only inclusive ends are supported) to specify a range
263
263
  # of values.
264
- #
264
+ #
265
265
  # Raises Versionomy::Errors::RangeOverlapError if the specified
266
266
  # range overlaps another previously specified range, or if more than
267
267
  # one default child has been set.
268
- #
268
+ #
269
269
  # Raises Versionomy::Errors::RangeSpecificationError if the range
270
270
  # is incorrectly specified.
271
- #
271
+ #
272
272
  # Raises Versionomy::Errors::CircularDescendantError if adding this
273
273
  # child will result in a circular reference.
274
-
274
+
275
275
  def add_child(child_, ranges_=nil)
276
276
  if child_._descendant_fields.include?(self)
277
277
  raise Errors::CircularDescendantError
@@ -348,101 +348,101 @@ module Versionomy
348
348
  @ranges.insert(insert_index_, normalized_range_)
349
349
  end
350
350
  end
351
-
352
-
351
+
352
+
353
353
  # Compute descendants as a hash of names to fields, including this field.
354
-
354
+
355
355
  def _descendants_by_name # :nodoc:
356
356
  hash_ = {@name => self}
357
357
  @children.each{ |child_| hash_.merge!(child_._descendants_by_name) }
358
358
  hash_
359
359
  end
360
-
361
-
360
+
361
+
362
362
  # Return a set of all descendant fields, including this field.
363
-
363
+
364
364
  def _descendant_fields(set_=nil) # :nodoc:
365
365
  set_ ||= Set.new
366
366
  set_ << self
367
367
  @children.each{ |child_| child_._descendant_fields(set_) }
368
368
  set_
369
369
  end
370
-
371
-
370
+
371
+
372
372
  end
373
-
374
-
373
+
374
+
375
375
  # These methods are available in a schema field definition block.
376
-
376
+
377
377
  class FieldBuilder
378
-
378
+
379
379
  include ::Blockenspiel::DSL
380
-
380
+
381
381
  def initialize(field_, master_builder_) # :nodoc:
382
382
  @field = field_
383
383
  @master_builder = master_builder_
384
384
  end
385
-
386
-
385
+
386
+
387
387
  # Define the given symbol.
388
- #
388
+ #
389
389
  # Recognized options include:
390
- #
390
+ #
391
391
  # <tt>:bump</tt>::
392
392
  # The symbol to transition to when "bump" is called.
393
393
  # Default is to remain on the same value.
394
- #
394
+ #
395
395
  # Raises Versionomy::Errors::TypeMismatchError if called when the current field
396
396
  # is not of type <tt>:symbol</tt>.
397
- #
397
+ #
398
398
  # Raises Versionomy::Errors::SymbolRedefinedError if the given symbol name is
399
399
  # already defined.
400
-
400
+
401
401
  def symbol(symbol_, opts_={})
402
402
  @field._add_symbol(symbol_, opts_)
403
403
  end
404
-
405
-
404
+
405
+
406
406
  # Provide a default value.
407
-
407
+
408
408
  def default_value(value_)
409
409
  @field._set_default_value(value_)
410
410
  end
411
-
412
-
411
+
412
+
413
413
  # Provide a "bump" procedure.
414
414
  # The given block should take a value, and return the value to transition to.
415
415
  # If you return nil, the value will remain the same.
416
-
416
+
417
417
  def to_bump(&block_)
418
418
  @field._set_bump_proc(block_)
419
419
  end
420
-
421
-
420
+
421
+
422
422
  # Provide a "compare" procedure.
423
423
  # The given block should take two values and compare them.
424
424
  # It should return a negative integer if the first is less than the second,
425
425
  # a positive integer if the first is greater than the second, or 0 if the
426
426
  # two values are equal. If the values cannot be compared, return nil.
427
-
427
+
428
428
  def to_compare(&block_)
429
429
  @field._set_compare_proc(block_)
430
430
  end
431
-
432
-
431
+
432
+
433
433
  # Provide a "canonicalize" procedure.
434
434
  # The given block should take a value and return a canonicalized value.
435
435
  # Return nil if the given value is illegal.
436
-
436
+
437
437
  def to_canonicalize(&block_)
438
438
  @field._set_canonicalize_proc(block_)
439
439
  end
440
-
441
-
440
+
441
+
442
442
  # Add a child field.
443
- #
443
+ #
444
444
  # Recognized options include:
445
- #
445
+ #
446
446
  # <tt>:only</tt>::
447
447
  # The child should be available only for the given values of this
448
448
  # field. See below for ways to specify this constraint.
@@ -453,16 +453,16 @@ module Versionomy
453
453
  # Default value for the field if no value is explicitly set. Default
454
454
  # is 0 for an integer field, the empty string for a string field, or
455
455
  # the first symbol added for a symbol field.
456
- #
456
+ #
457
457
  # You may provide an optional block. Within the block, you may call
458
458
  # methods of this class again to customize the child.
459
- #
459
+ #
460
460
  # Raises Versionomy::Errors::IllegalValueError if the given default
461
461
  # value is not legal.
462
- #
462
+ #
463
463
  # The <tt>:only</tt> constraint may be specified in one of the
464
464
  # following ways:
465
- #
465
+ #
466
466
  # * A single value (integer, string, or symbol)
467
467
  # * The result of calling range() to define an inclusive range of
468
468
  # integers, strings, or symbols. In this case, either element may be
@@ -472,38 +472,38 @@ module Versionomy
472
472
  # * A Range object defining a range of integers or strings.
473
473
  # Only inclusive, not exclusive, ranges are supported.
474
474
  # * An array of the above.
475
- #
475
+ #
476
476
  # Raises Versionomy::Errors::RangeSpecificationError if the given
477
477
  # ranges are not legal.
478
- #
478
+ #
479
479
  # Raises Versionomy::Errors::RangeOverlapError if the given ranges
480
480
  # overlap previously specified ranges, or more than one default schema
481
481
  # is specified.
482
-
482
+
483
483
  def field(name_, opts_={}, &block_)
484
484
  only_ = opts_.delete(:only)
485
485
  opts_.merge!(:master_builder => @master_builder)
486
486
  @field.add_child(Schema::Field.new(name_, opts_, &block_), only_)
487
487
  end
488
-
489
-
488
+
489
+
490
490
  # Define a range for the <tt>:only</tt> parameter to +child+.
491
- #
491
+ #
492
492
  # This creates an object that +child+ interprets like a standard ruby Range. However, it
493
493
  # is customized for the use of +child+ in the following ways:
494
- #
494
+ #
495
495
  # * It supports only inclusive, not exclusive ranges.
496
496
  # * It supports open-ended ranges by setting either endpoint to nil.
497
497
  # * It supports symbol ranges under Ruby 1.8.
498
-
498
+
499
499
  def range(first_, last_)
500
500
  [first_, last_]
501
501
  end
502
-
503
-
502
+
503
+
504
504
  end
505
-
506
-
505
+
506
+
507
507
  end
508
-
508
+
509
509
  end