versionomy 0.1.3 → 0.2.0

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,145 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Versionomy conversion interface and registry
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2008-2009 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
+ # === Conversion between version schemas.
41
+ #
42
+ # Conversions are algorithms for converting from one schema to another.
43
+ # This is useful for performing conversions as well as comparing version
44
+ # numbers that use different schemas.
45
+ #
46
+ # To implement a conversion algorithm, implement the API defined by
47
+ # Versionomy::Conversion::Base. Then, register your conversion by calling
48
+ # Versionomy::Conversion#register. You will need to specify which schemas
49
+ # (from and to) that your conversion should handle. From that point on,
50
+ # whenever Versionomy needs to convert a value between those two schemas,
51
+ # it will use your conversion. You can register the same conversion object
52
+ # for multiple pairs of schemas, but you can register only one conversion
53
+ # object for any pair.
54
+ #
55
+ # A common technique for doing conversions is to unparse the version to a
56
+ # string, and then parse it in the new format. Versionomy provides a tool,
57
+ # Versionomy::Conversion::Parsing, for performing such conversions. The
58
+ # conversions between the standard and rubygems formats uses this tool.
59
+ # See Versionomy::Conversion::Rubygems for annotated examples.
60
+
61
+ module Conversion
62
+
63
+ @registry = ::Hash.new
64
+
65
+ class << self
66
+
67
+
68
+ # Convert the given value to the given format. This is identical to
69
+ # calling <tt>value_.convert(format_, convert_params_)</tt>.
70
+ #
71
+ # The format may be specified as a format object or as the name of a
72
+ # format in the Format registry.
73
+ #
74
+ # Raises Versionomy::Errors::ConversionError if the value could not
75
+ # be converted.
76
+
77
+ def convert(value_, format_, convert_params_=nil)
78
+ value_.convert(format_, convert_params_)
79
+ end
80
+
81
+
82
+ # Get a conversion capable of converting between the given schemas.
83
+ #
84
+ # The schemas may be specified as format names, Format objects,
85
+ # schema wrapper objects, or the root field of the schema.
86
+ #
87
+ # If strict is set to false, returns nil if no such conversion could
88
+ # be found. If strict is set to true, may raise one of these errors:
89
+ #
90
+ # Raises Versionomy::Errors::UnknownFormatError if a format was
91
+ # specified by name but the name is not known.
92
+ #
93
+ # Raises Versionomy::Errors::UnknownConversionError if the formats
94
+ # were recognized but no conversion was found to handle them.
95
+
96
+ def get(from_schema_, to_schema_, strict_=false)
97
+ key_ = _get_key(from_schema_, to_schema_)
98
+ conversion_ = @registry[key_]
99
+ if strict_ && conversion_.nil?
100
+ raise Errors::UnknownConversionError
101
+ end
102
+ conversion_
103
+ end
104
+
105
+
106
+ # Register the given conversion as the handler for the given schemas.
107
+ #
108
+ # The schemas may be specified as format names, Format objects,
109
+ # schema wrapper objects, or the root field of the schema.
110
+ #
111
+ # Raises Versionomy::Errors::ConversionRedefinedError if a conversion
112
+ # has already been registered for the given schemas.
113
+ #
114
+ # Raises Versionomy::Errors::UnknownFormatError if a format was
115
+ # specified by name but the name is not known.
116
+
117
+ def register(from_schema_, to_schema_, conversion_)
118
+ key_ = _get_key(from_schema_, to_schema_)
119
+ if @registry.include?(key_)
120
+ raise Errors::ConversionRedefinedError
121
+ end
122
+ @registry[key_] = conversion_
123
+ end
124
+
125
+
126
+ private
127
+
128
+ def _get_key(from_schema_, to_schema_) # :nodoc:
129
+ [_get_schema(from_schema_), _get_schema(to_schema_)]
130
+ end
131
+
132
+ def _get_schema(schema_) # :nodoc:
133
+ schema_ = Format.get(schema_, true) if schema_.kind_of?(::String) || schema_.kind_of?(::Symbol)
134
+ schema_ = schema_.schema if schema_.respond_to?(:schema)
135
+ schema_ = schema_.root_field if schema_.respond_to?(:root_field)
136
+ schema_
137
+ end
138
+
139
+
140
+ end
141
+
142
+ end
143
+
144
+
145
+ end
@@ -109,7 +109,7 @@ module Versionomy
109
109
 
110
110
 
111
111
  # This exception is raised during schema creation if you try to
112
- # create a circular dependency.
112
+ # create a circular graph.
113
113
 
114
114
  class CircularDescendantError < SchemaCreationError
115
115
  end
@@ -128,13 +128,33 @@ module Versionomy
128
128
  end
129
129
 
130
130
 
131
- # Raised by the Formats registry if you try to retrieve a format with
131
+ # Raised by the Format registry if you try to retrieve a format with
132
132
  # an unrecognized name in strict mode.
133
133
 
134
134
  class UnknownFormatError < VersionomyError
135
135
  end
136
136
 
137
137
 
138
+ # Raised when a conversion fails.
139
+
140
+ class ConversionError < VersionomyError
141
+ end
142
+
143
+
144
+ # Raised when a conversion fails because no conversion implementation
145
+ # was found.
146
+
147
+ class UnknownConversionError < ConversionError
148
+ end
149
+
150
+
151
+ # Raised when you try to register a conversion when one already
152
+ # exists for its schemas.
153
+
154
+ class ConversionRedefinedError < VersionomyError
155
+ end
156
+
157
+
138
158
  end
139
159
 
140
160
  end
@@ -44,10 +44,14 @@ module Versionomy
44
44
  #
45
45
  # This format doesn't actually do anything useful. It causes all strings
46
46
  # to parse to the schema's default value, and unparses all values to the
47
- # empty string.
47
+ # empty string. Instead, the purpose here is to define the API for a
48
+ # format.
49
+ #
50
+ # All formats must define the methods +schema+, +parse+, and +unparse+.
51
+ # It is also recommended that formats define the <tt>===</tt> method,
52
+ # though this is not strictly required. Finally, formats may optionally
53
+ # implement <tt>uparse_for_serialize</tt>.
48
54
  #
49
- # Instead, the purpose here is to define the API for a format. All
50
- # formats must define the methods +schema+, +parse+, and +unparse+.
51
55
  # Formats need not extend this base class, as long as they duck-type
52
56
  # these methods.
53
57
 
@@ -57,14 +61,23 @@ module Versionomy
57
61
  # Create an instance of this base format, with the given schema.
58
62
 
59
63
  def initialize(schema_)
60
- @schema = schema_
64
+ @_schema = schema_
65
+ end
66
+
67
+
68
+ def inspect # :nodoc:
69
+ "#<#{self.class}:0x#{object_id.to_s(16)} schema=#{@_schema.inspect}>"
70
+ end
71
+
72
+ def to_s # :nodoc:
73
+ inspect
61
74
  end
62
75
 
63
76
 
64
77
  # Returns the schema understood by this format.
65
78
 
66
79
  def schema
67
- @schema
80
+ @_schema
68
81
  end
69
82
 
70
83
 
@@ -90,6 +103,41 @@ module Versionomy
90
103
  end
91
104
 
92
105
 
106
+ # An optional method that does unparsing especially for serialization.
107
+ # Implement this if normal unparsing is "lossy" and doesn't guarantee
108
+ # reconstruction of the version number. This method should attempt to
109
+ # unparse in such a way that the entire version value can be
110
+ # reconstructed from the unparsed string. Serialization routines will
111
+ # first attempt to call this method to unparse for serialization. If
112
+ # this method is not present, the normal unparse method will be used.
113
+ #
114
+ # Return either the unparsed string, or an array consisting of the
115
+ # unparsed string and a hash of parse params to pass to the parser
116
+ # when the string is to be reconstructed. You may also either return
117
+ # nil or raise Versionomy::Errors::UnparseError if the unparsing
118
+ # cannot be done satisfactorily for serialization. In this case,
119
+ # serialization will be done using the raw value data rather than an
120
+ # unparsed string.
121
+ #
122
+ # This default implementation just turns around and calls unparse.
123
+ # Thus it is equivalent to the method not being present at all.
124
+
125
+ def unparse_for_serialization(value_)
126
+ unparse(value_)
127
+ end
128
+
129
+
130
+ # Determine whether the given value uses this format.
131
+
132
+ def ===(obj_)
133
+ if obj_.kind_of?(Value)
134
+ obj_.format == self
135
+ else
136
+ obj_ == self
137
+ end
138
+ end
139
+
140
+
93
141
  end
94
142
 
95
143
 
@@ -70,9 +70,9 @@ module Versionomy
70
70
  # the parse and unparse methods for details.
71
71
  #
72
72
  # For a usage example, see the definition of the standard format in
73
- # Versionomy::Formats#_create_standard.
73
+ # Versionomy::Format::Standard#create.
74
74
 
75
- class Delimiter
75
+ class Delimiter < Base
76
76
 
77
77
 
78
78
  # Create a format using delimiter tools.
@@ -128,11 +128,11 @@ module Versionomy
128
128
  #
129
129
  # <tt>:extra_characters</tt>::
130
130
  # Determines what to do if the entire string cannot be consumed by
131
- # the parsing process. If set to <tt>:ignore</tt> (the default),
132
- # any extra characters are ignored. If set to <tt>:suffix</tt>,
133
- # the extra characters are set as the <tt>:suffix</tt> unparse
134
- # parameter and are thus appended to the end of the string when
135
- # unparsing takes place. If set to <tt>:error</tt>, causes a
131
+ # the parsing process. If set to <tt>:ignore</tt>, any extra
132
+ # characters are ignored. If set to <tt>:suffix</tt>, the extra
133
+ # characters are set as the <tt>:suffix</tt> unparse parameter and
134
+ # are thus appended to the end of the string when unparsing takes
135
+ # place. If set to <tt>:error</tt> (the default), causes a
136
136
  # Versionomy::Errors::ParseError to be raised if there are
137
137
  # uninterpreted characters.
138
138
 
@@ -152,10 +152,12 @@ module Versionomy
152
152
  end
153
153
  if parse_params_[:string].length > 0
154
154
  case parse_params_[:extra_characters]
155
- when :error
156
- raise Errors::ParseError, "Extra characters: #{parse_params_[:string].inspect}"
155
+ when :ignore
156
+ # do nothing
157
157
  when :suffix
158
158
  unparse_params_[:suffix] = parse_params_[:string]
159
+ else
160
+ raise Errors::ParseError, "Extra characters: #{parse_params_[:string].inspect}"
159
161
  end
160
162
  end
161
163
  Value.new(values_, self, unparse_params_)
@@ -412,7 +414,7 @@ module Versionomy
412
414
  #
413
415
  # The standard format uses styles to preserve the different
414
416
  # syntaxes for the release_type field. See the source code in
415
- # Versionomy::Formats#_create_standard for this example.
417
+ # Versionomy::Format::Standard#create for this example.
416
418
 
417
419
  def field(name_, opts_={}, &block_)
418
420
  name_ = name_.to_sym
@@ -689,15 +691,17 @@ module Versionomy
689
691
  @style = opts_[:style]
690
692
  @default_value_optional = opts_[:default_value_optional]
691
693
  @regexp_options = opts_[:case_sensitive] ? nil : ::Regexp::IGNORECASE
692
- @value_regexp = ::Regexp.new("^(#{value_regexp_})", @regexp_options)
693
- regexp_ = opts_.fetch(:delimiter_regexp, '\.')
694
- @delimiter_regexp = regexp_.length > 0 ? ::Regexp.new("^(#{regexp_})", @regexp_options) : nil
695
- regexp_ = opts_.fetch(:post_delimiter_regexp, '')
696
- @post_delimiter_regexp = regexp_.length > 0 ? ::Regexp.new("^(#{regexp_})", @regexp_options) : nil
697
- regexp_ = opts_.fetch(:expected_follower_regexp, '')
698
- @follower_regexp = regexp_.length > 0 ? ::Regexp.new("^(#{regexp_})", @regexp_options) : nil
699
- @default_delimiter = opts_.fetch(:default_delimiter, '.')
700
- @default_post_delimiter = opts_.fetch(:default_post_delimiter, '')
694
+ @value_regexp = ::Regexp.new("\\A(#{value_regexp_})", @regexp_options)
695
+ regexp_ = opts_[:delimiter_regexp] || '\.'
696
+ @delimiter_regexp = regexp_.length > 0 ? ::Regexp.new("\\A(#{regexp_})", @regexp_options) : nil
697
+ @full_delimiter_regexp = regexp_.length > 0 ? ::Regexp.new("\\A(#{regexp_})\\z", @regexp_options) : nil
698
+ regexp_ = opts_[:post_delimiter_regexp] || ''
699
+ @post_delimiter_regexp = regexp_.length > 0 ? ::Regexp.new("\\A(#{regexp_})", @regexp_options) : nil
700
+ @full_post_delimiter_regexp = regexp_.length > 0 ? ::Regexp.new("\\A(#{regexp_})\\z", @regexp_options) : nil
701
+ regexp_ = opts_[:expected_follower_regexp] || ''
702
+ @follower_regexp = regexp_.length > 0 ? ::Regexp.new("\\A(#{regexp_})", @regexp_options) : nil
703
+ @default_delimiter = opts_[:default_delimiter] || '.'
704
+ @default_post_delimiter = opts_[:default_post_delimiter] || ''
701
705
  @requires_previous_field = opts_.fetch(:requires_previous_field, true)
702
706
  name_ = field_.name
703
707
  @default_field_value = field_.default_value
@@ -777,13 +781,21 @@ module Versionomy
777
781
  then
778
782
  str_ = unparsed_value(value_, style_, unparse_params_)
779
783
  if str_
780
- delim_ = unparse_params_[@delim_unparse_param_key]
781
- if !delim_ || @delimiter_regexp && @delimiter_regexp !~ delim_
782
- delim_ = @default_delimiter
784
+ if !@full_delimiter_regexp
785
+ delim_ = ''
786
+ else
787
+ delim_ = unparse_params_[@delim_unparse_param_key] || @default_delimiter
788
+ if @full_delimiter_regexp !~ delim_
789
+ delim_ = @default_delimiter
790
+ end
783
791
  end
784
- post_delim_ = unparse_params_[@post_delim_unparse_param_key]
785
- if !post_delim_ || @post_delimiter_regexp && @post_delimiter_regexp !~ post_delim_
786
- post_delim_ = @default_post_delimiter
792
+ if !@full_post_delimiter_regexp
793
+ post_delim_ = ''
794
+ else
795
+ post_delim_ = unparse_params_[@post_delim_unparse_param_key] || @default_post_delimiter
796
+ if @full_post_delimiter_regexp !~ post_delim_
797
+ post_delim_ = @default_post_delimiter
798
+ end
787
799
  end
788
800
  str_ = delim_ + str_ + post_delim_
789
801
  end
@@ -876,7 +888,7 @@ module Versionomy
876
888
  end
877
889
 
878
890
  def unparsed_value(value_, style_, unparse_params_)
879
- value_
891
+ value_.to_s
880
892
  end
881
893
 
882
894
  end
@@ -921,7 +933,7 @@ module Versionomy
921
933
  regexps_ = @mappings_in_order.map{ |map_| "(#{map_[0]})" }
922
934
  setup(field_, regexps_.join('|'), opts_)
923
935
  @mappings_in_order.each do |map_|
924
- map_[0] = ::Regexp.new("^(#{map_[0]})", @regexp_options)
936
+ map_[0] = ::Regexp.new("\\A(#{map_[0]})", @regexp_options)
925
937
  end
926
938
  end
927
939
 
@@ -0,0 +1,234 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Versionomy standard format implementation
4
+ #
5
+ # -----------------------------------------------------------------------------
6
+ # Copyright 2008-2009 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
+ module Format
40
+
41
+
42
+ # Get the rubygems format.
43
+ # This is identical to calling <tt>get('rubygems')</tt>.
44
+ #
45
+ # The rubygems format is designed to be parse-compatible with the
46
+ # Gem::Version class used in rubygems. The only caveat is, whereas
47
+ # Gem::Version handles an arbitrary number of fields, this format is
48
+ # limited to a maximum of 8.
49
+ #
50
+ # For the exact annotated definition of the rubygems schema and format,
51
+ # see the source code for Versionomy::Format::Rubygems#create.
52
+
53
+ def self.rubygems
54
+ get('rubygems')
55
+ end
56
+
57
+
58
+ # This is a namespace for the implementation of the Rubygems schema
59
+ # and format.
60
+
61
+ module Rubygems
62
+
63
+
64
+ # Extra methods added to version values that use the rubygems schema.
65
+
66
+ module ExtraMethods
67
+
68
+
69
+ # Returns true if the version is a prerelease version-- that is,
70
+ # if any of the fields is non-numeric.
71
+ #
72
+ # This behaves the same as the Gem::Version#prerelease? method
73
+ # in rubygems.
74
+
75
+ def prerelease?
76
+ values_array.any?{ |val_| val_.kind_of?(::String) }
77
+ end
78
+
79
+
80
+ # Returns the release for this version.
81
+ # For example, converts "1.2.0.a.1" to "1.2.0".
82
+ # Non-prerelease versions return themselves.
83
+ #
84
+ # This behaves the same as the Gem::Version#release method
85
+ # in rubygems.
86
+
87
+ def release
88
+ values_ = []
89
+ self.each_field_object do |field_, val_|
90
+ break unless val_.kind_of?(::Integer)
91
+ values_ << val_
92
+ end
93
+ Value.new(values_, self.format, self.unparse_params)
94
+ end
95
+
96
+
97
+ # Returns a list of the field values, in field order, with
98
+ # trailing zeroes stripped off.
99
+ #
100
+ # This behaves the same as the Gem::Version#parts method
101
+ # in rubygems.
102
+
103
+ def parts
104
+ unless @parts
105
+ @parts = values_array
106
+ @parts.pop while @parts.size > 1 && @parts.last == 0
107
+ end
108
+ @parts
109
+ end
110
+
111
+
112
+ end
113
+
114
+
115
+ # Create the rubygems format.
116
+ # This method is called internally when Versionomy initializes itself,
117
+ # and you should not need to call it again. It is documented, however,
118
+ # so that you can inspect its source code from RDoc, since the source
119
+ # contains useful examples of how to use the schema and format
120
+ # definition DSLs.
121
+
122
+ def self.create
123
+
124
+ # The following is the definition of the rubygems schema
125
+ schema_ = Schema.create do
126
+
127
+ # Global comparison function
128
+ to_compare_type(:string) do |a_, b_|
129
+ if a_.kind_of?(::Integer)
130
+ if b_.kind_of?(::Integer)
131
+ a_ - b_
132
+ else
133
+ 1
134
+ end
135
+ else
136
+ if b_.kind_of?(::Integer)
137
+ -1
138
+ else
139
+ a_ <=> b_
140
+ end
141
+ end
142
+ end
143
+
144
+ # Global canonicalization function
145
+ to_canonicalize_type(:string) do |val_|
146
+ if val_.kind_of?(::Integer)
147
+ val_
148
+ else
149
+ val_ = val_.to_s
150
+ if val_ =~ /\A\d*\z/
151
+ val_.to_i
152
+ else
153
+ val_
154
+ end
155
+ end
156
+ end
157
+
158
+ # The first field has the default value of 1. All other fields
159
+ # have a default value of 0. Thus, the default version number
160
+ # overall is "1.0".
161
+ field(:field0, :type => :integer, :default_value => 1) do
162
+ field(:field1, :type => :string) do
163
+ field(:field2, :type => :string) do
164
+ field(:field3, :type => :string) do
165
+ field(:field4, :type => :string) do
166
+ field(:field5, :type => :string) do
167
+ field(:field6, :type => :string) do
168
+ field(:field7, :type => :string)
169
+ end
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ # Add the methods in this module to each value
178
+ add_module(Format::Rubygems::ExtraMethods)
179
+ end
180
+
181
+ # The following is the definition of the standard format. It
182
+ # understands the standard schema defined above.
183
+ format_ = Format::Delimiter.new(schema_) do
184
+
185
+ # All version number strings must start with the major version.
186
+ # Unlike other fields, it is not preceded by any delimiter.
187
+ field(:field0) do
188
+ recognize_number(:delimiter_regexp => '', :default_delimiter => '')
189
+ end
190
+
191
+ # The remainder of the version number are represented as strings
192
+ # or integers delimited by periods by default. Each is also
193
+ # dependent on the presence of the previous field, so
194
+ # :requires_previous_field retains its default value of true.
195
+ # Finally, they can be optional in an unparsed string if they are
196
+ # set to the default value of 0.
197
+ field(:field1) do
198
+ recognize_regexp('[0-9a-zA-Z]+', :default_value_optional => true)
199
+ end
200
+ field(:field2) do
201
+ recognize_regexp('[0-9a-zA-Z]+', :default_value_optional => true)
202
+ end
203
+ field(:field3) do
204
+ recognize_regexp('[0-9a-zA-Z]+', :default_value_optional => true)
205
+ end
206
+ field(:field4) do
207
+ recognize_regexp('[0-9a-zA-Z]+', :default_value_optional => true)
208
+ end
209
+ field(:field5) do
210
+ recognize_regexp('[0-9a-zA-Z]+', :default_value_optional => true)
211
+ end
212
+ field(:field6) do
213
+ recognize_regexp('[0-9a-zA-Z]+', :default_value_optional => true)
214
+ end
215
+ field(:field7) do
216
+ recognize_regexp('[0-9a-zA-Z]+', :default_value_optional => true)
217
+ end
218
+
219
+ # By default, we require that at least the first two fields
220
+ # appear in an unparsed version string.
221
+ default_unparse_params(:required_fields => [:field1])
222
+ end
223
+ end
224
+
225
+
226
+ end
227
+
228
+
229
+ register('rubygems', Format::Rubygems.create) unless get('rubygems')
230
+
231
+
232
+ end
233
+
234
+ end