versionomy 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +31 -0
- data/README.rdoc +144 -0
- data/Rakefile +93 -12
- data/lib/versionomy/errors.rb +30 -11
- data/lib/versionomy/format/base.rb +96 -0
- data/lib/versionomy/format/delimiter.rb +951 -0
- data/lib/versionomy/format.rb +26 -112
- data/lib/versionomy/formats/standard.rb +346 -0
- data/lib/versionomy/formats.rb +79 -0
- data/lib/versionomy/interface.rb +23 -17
- data/lib/versionomy/schema/field.rb +500 -0
- data/lib/versionomy/schema/wrapper.rb +177 -0
- data/lib/versionomy/schema.rb +41 -500
- data/lib/versionomy/value.rb +129 -157
- data/lib/versionomy/version.rb +8 -8
- data/lib/versionomy.rb +25 -10
- data/tests/tc_custom_format.rb +66 -0
- data/tests/tc_readme_examples.rb +121 -0
- data/tests/tc_standard_basic.rb +17 -16
- data/tests/tc_standard_bump.rb +11 -10
- data/tests/tc_standard_change.rb +2 -1
- data/tests/tc_standard_comparison.rb +2 -1
- data/tests/tc_standard_parse.rb +41 -23
- metadata +28 -31
- data/History.txt +0 -21
- data/Manifest.txt +0 -17
- data/README.txt +0 -133
- data/lib/versionomy/standard.rb +0 -392
data/lib/versionomy/format.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
2
|
#
|
3
|
-
# Versionomy format
|
3
|
+
# Versionomy format module
|
4
4
|
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
|
-
# Copyright 2008 Daniel Azuma
|
6
|
+
# Copyright 2008-2009 Daniel Azuma
|
7
7
|
#
|
8
8
|
# All rights reserved.
|
9
9
|
#
|
@@ -37,118 +37,32 @@
|
|
37
37
|
module Versionomy
|
38
38
|
|
39
39
|
|
40
|
-
#
|
40
|
+
# === Version number format.
|
41
|
+
#
|
42
|
+
# A format controls the parsing and unparsing of a version number.
|
43
|
+
# Any time a version number is parsed from a string, a format is provided
|
44
|
+
# to parse it. Similarly, every version number value references a format
|
45
|
+
# that is used to unparse it back into a string.
|
46
|
+
#
|
47
|
+
# A format is always tied to a particular schema and knows how to parse
|
48
|
+
# only that schema's version numbers.
|
49
|
+
#
|
50
|
+
# Under many circumstances, you should use the standard format, which
|
51
|
+
# can be retrieved by calling Versionomy::Formats#standard. This format
|
52
|
+
# understands most of the common version numbers, including prerelease
|
53
|
+
# (e.g. alpha, beta, release candidate, etc.) forms and patchlevels.
|
54
|
+
#
|
55
|
+
# You may also create your own formats, either by implementing the
|
56
|
+
# format contract (see Versionomy::Format::Base) or by using the
|
57
|
+
# Versionomy::Format::Delimiter tool, which can be used to construct
|
58
|
+
# parsers for many version number formats.
|
59
|
+
#
|
60
|
+
# Formats may be registered with Versionomy and given a name using the
|
61
|
+
# methods of this Versionomy::Formats. This allows version numbers to be
|
62
|
+
# serialized with their format.
|
41
63
|
|
42
64
|
module Format
|
43
|
-
|
44
|
-
|
45
|
-
# A simple base formatter.
|
46
|
-
#
|
47
|
-
# Formats need not extend this base class, as long as they duck-type the
|
48
|
-
# required methods name, parse, and unparse.
|
49
|
-
|
50
|
-
class Base
|
51
|
-
|
52
|
-
# Create the formatter.
|
53
|
-
# If a block is provided, you may call methods of Versionomy::Format::Builder
|
54
|
-
# within the block, to specify ways to parse and unparse.
|
55
|
-
|
56
|
-
def initialize(name_, &block_)
|
57
|
-
@name = name_.to_sym
|
58
|
-
@parser = @unparser = nil
|
59
|
-
Blockenspiel.invoke(block_, Versionomy::Format::Builder.new(self))
|
60
|
-
end
|
61
|
-
|
62
|
-
|
63
|
-
def _set_parser(block_) # :nodoc:
|
64
|
-
@parser = block_
|
65
|
-
end
|
66
|
-
|
67
|
-
def _set_unparser(block_) # :nodoc:
|
68
|
-
@unparser = block_
|
69
|
-
end
|
70
|
-
|
71
|
-
def _set_name(name_) # :nodoc:
|
72
|
-
@name = name_
|
73
|
-
end
|
74
|
-
|
75
|
-
|
76
|
-
# The format name
|
77
|
-
|
78
|
-
def name
|
79
|
-
@name
|
80
|
-
end
|
81
|
-
|
82
|
-
|
83
|
-
# A simple parse algorithm.
|
84
|
-
# If a parser block was provided during initialization, calls that block.
|
85
|
-
# Otherwise, attempts to parse using "." as a delimiter.
|
86
|
-
|
87
|
-
def parse(schema_, string_, params_)
|
88
|
-
if @parser
|
89
|
-
@parser.call(schema_, string_, params_)
|
90
|
-
else
|
91
|
-
array_ = string_.split('.')
|
92
|
-
Versionomy::Value.new(schema_, array_)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
|
97
|
-
# A simple parse algorithm.
|
98
|
-
# If an unparser block was provided during initialization, calls that block.
|
99
|
-
# Otherwise, attempts to unparse using "." as a delimiter.
|
100
|
-
|
101
|
-
def unparse(schema_, value_, params_)
|
102
|
-
if @unparser
|
103
|
-
@unparser.call(schema_, value_, params_)
|
104
|
-
else
|
105
|
-
value_.values.join('.')
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
110
|
-
|
111
|
-
|
112
|
-
# These methods are available in an initializer block for Versionomy::Format::Base.
|
113
|
-
|
114
|
-
class Builder < Blockenspiel::Base
|
115
|
-
|
116
|
-
def initialize(format_) # :nodoc:
|
117
|
-
@format = format_
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
# Specify how to parse a string into a version value.
|
122
|
-
#
|
123
|
-
# The block should take three parameters: a schema, a string, and a parameters hash.
|
124
|
-
# The block should return an object of type Versionomy::Value.
|
125
|
-
# You may raise Versionomy::Errors::ParseError if parsing failed.
|
126
|
-
|
127
|
-
def to_parse(&block_)
|
128
|
-
@format._set_parser(block_)
|
129
|
-
end
|
130
|
-
|
131
|
-
|
132
|
-
# Specify how to represent a version value as a string.
|
133
|
-
#
|
134
|
-
# The block should take three parameters: a schema, a Versionomy::Value, and a parameters hash.
|
135
|
-
# The block should return a string.
|
136
|
-
# You may raise Versionomy::Errors::ParseError if unparsing failed.
|
137
|
-
|
138
|
-
def to_unparse(&block_)
|
139
|
-
@format._set_unparser(block_)
|
140
|
-
end
|
141
|
-
|
142
|
-
|
143
|
-
# Specify the format name
|
144
|
-
|
145
|
-
def set_name(name_)
|
146
|
-
@format._set_name(name_)
|
147
|
-
end
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
|
152
65
|
end
|
153
66
|
|
67
|
+
|
154
68
|
end
|
@@ -0,0 +1,346 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Versionomy format 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
|
+
module Formats
|
40
|
+
|
41
|
+
|
42
|
+
# Get the standard format.
|
43
|
+
# This is identical to calling <tt>get('standard')</tt>.
|
44
|
+
#
|
45
|
+
# The standard format is designed to handle most commonly-used version
|
46
|
+
# number forms, and allow parsing and comparison between them.
|
47
|
+
#
|
48
|
+
# The standard schema is the heart of this format, providing a
|
49
|
+
# common structure for most version numbers.
|
50
|
+
#
|
51
|
+
# It begins with four numeric fields:
|
52
|
+
# "<tt>major.minor.tiny.tiny2</tt>".
|
53
|
+
#
|
54
|
+
# The next field, <tt>:release_type</tt>, defines the remaining
|
55
|
+
# structure. The release type can be one of these symbolic values:
|
56
|
+
# <tt>:development</tt>, <tt>:alpha</tt>, <tt>:beta</tt>,
|
57
|
+
# <tt>:preview</tt>, <tt>:release_candidate</tt>, <tt>:release</tt>.
|
58
|
+
#
|
59
|
+
# Depending on that value, additional fields become available. For
|
60
|
+
# example, the <tt>:alpha</tt> value enables the fields
|
61
|
+
# <tt>:alpha_version</tt> and <tt>:alpha_minor</tt>, which represent
|
62
|
+
# version number fields after the "a" alpha specifier. i.e. "2.1a30"
|
63
|
+
# has an alpha_version of 30. "2.1a30.2" also has an alpha_minor of 2.
|
64
|
+
# Similarly, the <tt>:beta</tt> release_type value enables the fields
|
65
|
+
# <tt>:beta_version</tt> and <tt>:beta_minor</tt>. A release_type
|
66
|
+
# of <tt>:release</tt> enables <tt>:patchlevel</tt> and
|
67
|
+
# <tt>:patchlevel_minor</tt>, to support versions like "1.8.7p72".
|
68
|
+
#
|
69
|
+
# The format itself is a delimiter-based format that understands a
|
70
|
+
# wide variety of string representations of this version schema.
|
71
|
+
# Examples of supported syntax include:
|
72
|
+
#
|
73
|
+
# 2.0
|
74
|
+
# 2.0.42.10
|
75
|
+
# 2.0b2
|
76
|
+
# 2.0rc15
|
77
|
+
# 2.0-5
|
78
|
+
# 2.0p5
|
79
|
+
# 2.0 Alpha 1
|
80
|
+
# 2.0a5.3
|
81
|
+
# 2.1.42.10-4.3
|
82
|
+
#
|
83
|
+
# Because the standard format is based on Versionomy::Format::Delimiter,
|
84
|
+
# a number of parameters are available for parsing and unparsing. See
|
85
|
+
# the documentation for the delimiter class for more information.
|
86
|
+
#
|
87
|
+
# Two of the fields have styles that can be set when unparsing.
|
88
|
+
# The <tt>:release_type</tt> field can be unparsed as either
|
89
|
+
# <tt>:long</tt> style (e.g. "1.0alpha2") or <tt>:short</tt> style
|
90
|
+
# (e.g. "1.0a2"). The patchlevel field can be unparsed as either
|
91
|
+
# <tt>:number</tt> style (e.g. "2.1-1") or <tt>:letter</tt> style
|
92
|
+
# (e.g. "2.1a"). Most fields can have their delimiter specified during
|
93
|
+
# unparsing as well.
|
94
|
+
#
|
95
|
+
# For the exact annotated definition of the standard schema and format,
|
96
|
+
# see the source code for the _create_standard method.
|
97
|
+
|
98
|
+
def self.standard
|
99
|
+
get('standard')
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
# Create the standard format.
|
104
|
+
# This method is called internally when Versionomy initializes itself,
|
105
|
+
# and you should not need to call it again. It is documented, however,
|
106
|
+
# so that you can inspect its source code from RDoc, since the source
|
107
|
+
# contains useful examples of how to use the schema and format
|
108
|
+
# definition DSLs.
|
109
|
+
|
110
|
+
def self._create_standard
|
111
|
+
|
112
|
+
# The following is the definition of the standard schema
|
113
|
+
schema_ = Schema.create do
|
114
|
+
|
115
|
+
# The major field has the default value of 1. Most other fields
|
116
|
+
# have a default value of 0. Thus, the default version number
|
117
|
+
# overall is "1.0".
|
118
|
+
# We first create the core version fields "major.minor.tiny.tiny2".
|
119
|
+
field(:major, :default_value => 1) do
|
120
|
+
field(:minor) do
|
121
|
+
field(:tiny) do
|
122
|
+
field(:tiny2) do
|
123
|
+
|
124
|
+
# The next field is a symbolic field that specifies the
|
125
|
+
# release type: e.g. beta, release candidate, release, etc.
|
126
|
+
field(:release_type, :type => :symbol) do
|
127
|
+
|
128
|
+
# Development releases are typically expressed like
|
129
|
+
# "1.0d3" and are intended for unstable development
|
130
|
+
# progress. Bumping the release type will change it to
|
131
|
+
# alpha.
|
132
|
+
symbol(:development, :bump => :alpha)
|
133
|
+
|
134
|
+
# Alpha releases are typically expressed like "1.0a2" and
|
135
|
+
# are intended for internal testing.
|
136
|
+
# Bumping the release type advances to beta.
|
137
|
+
symbol(:alpha, :bump => :beta)
|
138
|
+
|
139
|
+
# Beta releases are typically expressed like "1.0b2" and
|
140
|
+
# are intended for external or public testing.
|
141
|
+
# Bumping the release type advances to release candidate.
|
142
|
+
symbol(:beta, :bump => :release_candidate)
|
143
|
+
|
144
|
+
# Release candidate releases are typically expressed like
|
145
|
+
# "1.0rc2" and are intended for final public testing
|
146
|
+
# prior to release.
|
147
|
+
# Bumping the release type advances to final release.
|
148
|
+
symbol(:release_candidate, :bump => :final)
|
149
|
+
|
150
|
+
# Preview releases represent an alternative release type
|
151
|
+
# progression, and are typically used for public testing
|
152
|
+
# similar to beta or release candidate.
|
153
|
+
# Bumping the release type advances to final release.
|
154
|
+
symbol(:preview, :bump => :final)
|
155
|
+
|
156
|
+
# This type represents a final release. This is the
|
157
|
+
# default value for the release_type field if no value is
|
158
|
+
# explicitly provided.
|
159
|
+
# Bumping the release type has no effect.
|
160
|
+
symbol(:final, :bump => :final)
|
161
|
+
default_value(:final)
|
162
|
+
|
163
|
+
# If the release type is development, these fields are
|
164
|
+
# made available to indicate which development release
|
165
|
+
# is being represented.
|
166
|
+
field(:development_version, :only => :development,
|
167
|
+
:default_value => 1) do
|
168
|
+
field(:development_minor)
|
169
|
+
end
|
170
|
+
|
171
|
+
# If the release type is alpha, these fields are made
|
172
|
+
# available to indicate which alpha release is being
|
173
|
+
# represented.
|
174
|
+
field(:alpha_version, :only => :alpha, :default_value => 1) do
|
175
|
+
field(:alpha_minor)
|
176
|
+
end
|
177
|
+
|
178
|
+
# If the release type is beta, these fields are made
|
179
|
+
# available to indicate which beta release is being
|
180
|
+
# represented.
|
181
|
+
field(:beta_version, :only => :beta, :default_value => 1) do
|
182
|
+
field(:beta_minor)
|
183
|
+
end
|
184
|
+
|
185
|
+
# If the release type is release candidate, these fields
|
186
|
+
# are made available to indicate which release candidate
|
187
|
+
# is being represented.
|
188
|
+
field(:release_candidate_version, :only => :release_candidate,
|
189
|
+
:default_value => 1) do
|
190
|
+
field(:release_candidate_minor)
|
191
|
+
end
|
192
|
+
|
193
|
+
# If the release type is preview, these fields are made
|
194
|
+
# available to indicate which preview release is being
|
195
|
+
# represented.
|
196
|
+
field(:preview_version, :only => :preview, :default_value => 1) do
|
197
|
+
field(:preview_minor)
|
198
|
+
end
|
199
|
+
|
200
|
+
# If the release type is final, these fields are made
|
201
|
+
# available to indicate an optional patchlevel.
|
202
|
+
field(:patchlevel, :only => :final) do
|
203
|
+
field(:patchlevel_minor)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
# The following is the definition of the standard format. It
|
213
|
+
# understands the standard schema defined above.
|
214
|
+
format_ = Format::Delimiter.new(schema_) do
|
215
|
+
|
216
|
+
# All version number strings must start with the major version.
|
217
|
+
# Unlike other fields, it is not preceded by any delimiter.
|
218
|
+
field(:major) do
|
219
|
+
recognize_number(:delimiter_regexp => '', :default_delimiter => '')
|
220
|
+
end
|
221
|
+
|
222
|
+
# The remainder of the core version number are represented as
|
223
|
+
# integers delimited by periods by default. Each is also dependent
|
224
|
+
# on the presence of the previous field, so :requires_previous_field
|
225
|
+
# retains its default value of true. Finally, they can be optional
|
226
|
+
# in an unparsed string if they are set to the default value of 0.
|
227
|
+
field(:minor) do
|
228
|
+
recognize_number(:default_value_optional => true)
|
229
|
+
end
|
230
|
+
field(:tiny) do
|
231
|
+
recognize_number(:default_value_optional => true)
|
232
|
+
end
|
233
|
+
field(:tiny2) do
|
234
|
+
recognize_number(:default_value_optional => true)
|
235
|
+
end
|
236
|
+
|
237
|
+
# The release type field is the most complex field because of the
|
238
|
+
# variety of syntaxes we support. The basic strategy is to map
|
239
|
+
# a few specific sets of characters as signaling particular release
|
240
|
+
# types. For example, the "a" in "1.0a5" signals an alpha release.
|
241
|
+
# If no such release type marker is found, it defaults to the final
|
242
|
+
# release type.
|
243
|
+
# We set up two styles, a short style and a long style. Short style
|
244
|
+
# syntax looks like "1.0a5". Long syntax looks more like
|
245
|
+
# "1.0 Alpha 5". The parsed value retains knowledge of which style
|
246
|
+
# it came from so it can be reconstructed when the value is unparsed.
|
247
|
+
# Finally, we turn requires_previous_field off because the release
|
248
|
+
# type syntax markers don't require any particular set of the core
|
249
|
+
# version number fields to be present. "1.0a5" and "1.0.0.0a5" are
|
250
|
+
# both valid version numbers.
|
251
|
+
field(:release_type, :requires_previous_field => false,
|
252
|
+
:default_style => :short) do
|
253
|
+
# First check for "short form" syntax. Not that we support post-
|
254
|
+
# delimiters; that is, we recognize "1.0 pre-2" where the hyphen
|
255
|
+
# is a post-delimiter. Also notice that we expect prerelease types
|
256
|
+
# to be followed by a numeric prerelease version number.
|
257
|
+
recognize_regexp_map(:style => :short, :default_delimiter => '',
|
258
|
+
:delimiter_regexp => '-|\.|\s?',
|
259
|
+
:post_delimiter_regexp => '\s?|-',
|
260
|
+
:expected_follower_regexp => '\d') do
|
261
|
+
map(:development, 'd')
|
262
|
+
map(:alpha, 'a')
|
263
|
+
map(:beta, 'b')
|
264
|
+
map(:release_candidate, 'rc')
|
265
|
+
map(:preview, 'pre')
|
266
|
+
# Note that we omit the value <tt>:final</tt>. This is because
|
267
|
+
# that value is signaled by the absence of any syntax in the
|
268
|
+
# version string, including the absence of any delimiters. So we
|
269
|
+
# just allow it to fall through to the default.
|
270
|
+
end
|
271
|
+
# Check for "long form" syntax. Note again that we omit :final.
|
272
|
+
recognize_regexp_map(:style => :long, :default_delimiter => '',
|
273
|
+
:delimiter_regexp => '-|\.|\s?',
|
274
|
+
:post_delimiter_regexp => '\s?|-',
|
275
|
+
:expected_follower_regexp => '\d') do
|
276
|
+
map(:development, 'dev')
|
277
|
+
map(:alpha, 'alpha')
|
278
|
+
map(:beta, 'beta')
|
279
|
+
map(:release_candidate, 'rc')
|
280
|
+
map(:preview, 'preview')
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
# The development version must appear in the string if it is present
|
285
|
+
# in the value, even if the value is 0. Similar for all the other
|
286
|
+
# prerelease version numbers: alpha, beta, release candidate, and
|
287
|
+
# preview. However, the minor fields are optional.
|
288
|
+
field(:development_version) do
|
289
|
+
recognize_number(:delimiter_regexp => '', :default_delimiter => '')
|
290
|
+
end
|
291
|
+
field(:development_minor) do
|
292
|
+
recognize_number(:default_value_optional => true)
|
293
|
+
end
|
294
|
+
field(:alpha_version) do
|
295
|
+
recognize_number(:delimiter_regexp => '', :default_delimiter => '')
|
296
|
+
end
|
297
|
+
field(:alpha_minor) do
|
298
|
+
recognize_number(:default_value_optional => true)
|
299
|
+
end
|
300
|
+
field(:beta_version) do
|
301
|
+
recognize_number(:delimiter_regexp => '', :default_delimiter => '')
|
302
|
+
end
|
303
|
+
field(:beta_minor) do
|
304
|
+
recognize_number(:default_value_optional => true)
|
305
|
+
end
|
306
|
+
field(:release_candidate_version) do
|
307
|
+
recognize_number(:delimiter_regexp => '', :default_delimiter => '')
|
308
|
+
end
|
309
|
+
field(:release_candidate_minor) do
|
310
|
+
recognize_number(:default_value_optional => true)
|
311
|
+
end
|
312
|
+
field(:preview_version) do
|
313
|
+
recognize_number(:delimiter_regexp => '', :default_delimiter => '')
|
314
|
+
end
|
315
|
+
field(:preview_minor) do
|
316
|
+
recognize_number(:default_value_optional => true)
|
317
|
+
end
|
318
|
+
|
319
|
+
# The patchlevel field does not require the previous field (which is
|
320
|
+
# release_type). Here we also set up two styles: a numeric style and
|
321
|
+
# a letter style. So "1.0a" and "1.0-1" are equivalent.
|
322
|
+
field(:patchlevel, :requires_previous_field => false,
|
323
|
+
:default_value_optional => true, :default_style => :number) do
|
324
|
+
recognize_number(:style => :number, :default_delimiter => '-',
|
325
|
+
:delimiter_regexp => '-|(-|\.|\s?)p')
|
326
|
+
recognize_letter(:style => :letter, :default_delimiter => '',
|
327
|
+
:delimiter_regexp => '-|\.|\s?',
|
328
|
+
:expected_follower_regexp => '$')
|
329
|
+
end
|
330
|
+
field(:patchlevel_minor) do
|
331
|
+
recognize_number(:default_value_optional => true)
|
332
|
+
end
|
333
|
+
|
334
|
+
# By default, we require that at least the major and minor fields
|
335
|
+
# appear in an unparsed version string.
|
336
|
+
default_unparse_params(:required_fields => [:minor])
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
|
341
|
+
register('standard', _create_standard) unless get('standard')
|
342
|
+
|
343
|
+
|
344
|
+
end
|
345
|
+
|
346
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Versionomy format module
|
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
|
+
# === Version number format regsitry.
|
41
|
+
#
|
42
|
+
# Use the methods of this module to register formats with a name. This
|
43
|
+
# allows version numbers to be serialized with their format.
|
44
|
+
#
|
45
|
+
# You may also access predefined formats such as the standard format from
|
46
|
+
# this module. It also contains the implementations of these formats as
|
47
|
+
# examples.
|
48
|
+
|
49
|
+
module Formats
|
50
|
+
|
51
|
+
|
52
|
+
@names = ::Hash.new
|
53
|
+
|
54
|
+
|
55
|
+
# Get the format with the given name.
|
56
|
+
|
57
|
+
def self.get(name_)
|
58
|
+
@names[name_.to_s]
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# Register the given format under the given name.
|
63
|
+
#
|
64
|
+
# Raises Versionomy::Errors::FormatRedefinedError if the name has
|
65
|
+
# already been defined.
|
66
|
+
|
67
|
+
def self.register(name_, format_)
|
68
|
+
name_ = name_.to_s
|
69
|
+
if @names.include?(name_)
|
70
|
+
raise Errors::FormatRedefinedError, name_
|
71
|
+
end
|
72
|
+
@names[name_] = format_
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
end
|
data/lib/versionomy/interface.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Versionomy convenience interface
|
4
4
|
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
|
-
# Copyright 2008 Daniel Azuma
|
6
|
+
# Copyright 2008-2009 Daniel Azuma
|
7
7
|
#
|
8
8
|
# All rights reserved.
|
9
9
|
#
|
@@ -41,46 +41,52 @@
|
|
41
41
|
|
42
42
|
module Versionomy
|
43
43
|
|
44
|
-
@
|
44
|
+
@default_format = nil
|
45
45
|
|
46
46
|
|
47
47
|
class << self
|
48
48
|
|
49
49
|
|
50
|
-
# Gets the current default
|
50
|
+
# Gets the current default format. Usually this is the "standard"
|
51
|
+
# format returned by Versionomy::Formats.standard.
|
51
52
|
|
52
|
-
def
|
53
|
-
@
|
53
|
+
def default_format
|
54
|
+
@default_format ||= Formats.standard
|
54
55
|
end
|
55
56
|
|
56
57
|
|
57
|
-
# Sets the default
|
58
|
+
# Sets the default format.
|
59
|
+
# Usually this should be left as the "standard" format returned by
|
60
|
+
# Versionomy::Formats.standard. To reset to that value, pass nil.
|
58
61
|
|
59
|
-
def
|
60
|
-
@
|
62
|
+
def default_format=(format_)
|
63
|
+
@default_format = format_
|
61
64
|
end
|
62
65
|
|
63
66
|
|
64
67
|
# Create a new version number given a hash or array of values, and an
|
65
|
-
# optional
|
68
|
+
# optional format.
|
66
69
|
#
|
67
70
|
# The values should either be a hash of field names and values, or an array
|
68
71
|
# of values that will be interpreted in field order.
|
69
72
|
#
|
70
|
-
# If
|
73
|
+
# If the format is omitted or set to nil, the default_format will be used.
|
74
|
+
#
|
75
|
+
# You can also optionally provide default unparsing parameters for the value.
|
71
76
|
|
72
|
-
def create(values_=nil,
|
73
|
-
(
|
77
|
+
def create(values_=[], format_=nil, unparse_params_=nil)
|
78
|
+
Value.new(values_, format_ || default_format, unparse_params_)
|
74
79
|
end
|
75
80
|
|
76
81
|
|
77
|
-
# Create a new version number given a string to parse, and optional
|
78
|
-
#
|
82
|
+
# Create a new version number given a string to parse, and an optional format.
|
83
|
+
#
|
84
|
+
# If the format is omitted or set to nil, the default_format will be used.
|
79
85
|
#
|
80
|
-
#
|
86
|
+
# The params, if present, will be passed as parsing parameters to the format.
|
81
87
|
|
82
|
-
def parse(str_,
|
83
|
-
(
|
88
|
+
def parse(str_, format_=nil, parse_params_=nil)
|
89
|
+
(format_ || default_format).parse(str_, parse_params_)
|
84
90
|
end
|
85
91
|
|
86
92
|
end
|