versionomy 0.0.4 → 0.1.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.
- 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/value.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Versionomy value
|
4
4
|
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
|
-
# Copyright 2008 Daniel Azuma
|
6
|
+
# Copyright 2008-2009 Daniel Azuma
|
7
7
|
#
|
8
8
|
# All rights reserved.
|
9
9
|
#
|
@@ -45,32 +45,36 @@ module Versionomy
|
|
45
45
|
# number "1.4.2" would have the values <tt>[1, 4, 2]</tt> in that order,
|
46
46
|
# corresponding to the fields <tt>[:major, :minor, :tiny]</tt>.
|
47
47
|
#
|
48
|
-
# Version number values are comparable with other values that have
|
49
|
-
#
|
48
|
+
# Version number values are comparable with other values that have an
|
49
|
+
# equivalent schema.
|
50
50
|
|
51
51
|
class Value
|
52
52
|
|
53
53
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
54
|
+
# Create a value, given a hash or array of values, and a format. Both
|
55
|
+
# these parameters are required.
|
56
|
+
#
|
57
|
+
# The values should either be a hash of field names and values, or an
|
58
|
+
# array of values that will be interpreted in field order.
|
59
|
+
#
|
60
|
+
# You can also optionally provide default unparsing parameters for the
|
61
|
+
# value.
|
62
|
+
|
63
|
+
def initialize(values_, format_, unparse_params_=nil)
|
64
|
+
unless values_.kind_of?(::Hash) || values_.kind_of?(::Array)
|
65
|
+
raise ::ArgumentError, "Expected hash or array but got #{values_.class}"
|
66
66
|
end
|
67
|
-
@
|
68
|
-
@
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
67
|
+
@format = format_
|
68
|
+
@unparse_params = unparse_params_
|
69
|
+
@field_path = []
|
70
|
+
@values = {}
|
71
|
+
field_ = @format.schema.root_field
|
72
|
+
while field_
|
73
|
+
value_ = values_.kind_of?(Hash) ? values_[field_.name] : values_.shift
|
74
|
+
value_ = value_ ? field_.canonicalize_value(value_) : field_.default_value
|
75
|
+
@field_path << field_
|
76
|
+
@values[field_.name] = value_
|
77
|
+
field_ = field_.child(value_)
|
74
78
|
end
|
75
79
|
end
|
76
80
|
|
@@ -79,42 +83,25 @@ module Versionomy
|
|
79
83
|
begin
|
80
84
|
str_ = unparse
|
81
85
|
"#<#{self.class}:0x#{object_id.to_s(16)} #{str_.inspect}>"
|
82
|
-
rescue
|
86
|
+
rescue Errors::UnparseError
|
83
87
|
_inspect
|
84
88
|
end
|
85
89
|
end
|
86
90
|
|
87
91
|
def _inspect # :nodoc:
|
88
|
-
"#<#{self.class}:0x#{object_id.to_s(16)}
|
89
|
-
|
90
|
-
|
91
|
-
def _inspect2 # :nodoc:
|
92
|
-
" #{@schema.name}=#{@value.inspect}#{@subvalue ? @subvalue._inspect2 : ''}"
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
# Get the value of the most significant field
|
97
|
-
|
98
|
-
def _toplevel_value # :nodoc:
|
99
|
-
@value
|
100
|
-
end
|
101
|
-
|
102
|
-
|
103
|
-
# Get a value representing all fields except the most significant field
|
104
|
-
|
105
|
-
def _subvalue # :nodoc:
|
106
|
-
@subvalue
|
92
|
+
"#<#{self.class}:0x#{object_id.to_s(16)} " +
|
93
|
+
@field_path.map{ |field_| "#{field_.name}=#{@values[field_.name].inspect}" }.join(' ')
|
107
94
|
end
|
108
95
|
|
109
96
|
|
110
97
|
# Returns a string representation generated by unparsing.
|
111
|
-
# If unparsing fails, does not raise Versionomy::Errors::
|
98
|
+
# If unparsing fails, does not raise Versionomy::Errors::UnparseError,
|
112
99
|
# but instead returns the string generated by +inspect+.
|
113
100
|
|
114
101
|
def to_s
|
115
102
|
begin
|
116
103
|
unparse
|
117
|
-
rescue
|
104
|
+
rescue Errors::UnparseError
|
118
105
|
_inspect
|
119
106
|
end
|
120
107
|
end
|
@@ -122,151 +109,152 @@ module Versionomy
|
|
122
109
|
|
123
110
|
# Unparse this version number.
|
124
111
|
#
|
125
|
-
# Raises Versionomy::Errors::
|
112
|
+
# Raises Versionomy::Errors::UnparseError if unparsing failed.
|
126
113
|
|
127
|
-
def unparse(params_=
|
128
|
-
|
129
|
-
if format_.nil?
|
130
|
-
raise Versionomy::Errors::UnknownFormatError
|
131
|
-
end
|
132
|
-
format_.unparse(@schema, self, params_)
|
114
|
+
def unparse(params_=nil)
|
115
|
+
@format.unparse(self, params_)
|
133
116
|
end
|
134
117
|
|
135
118
|
|
136
|
-
#
|
137
|
-
# as this value, subject to the given modifications.
|
119
|
+
# Return the schema defining the form of this version number
|
138
120
|
|
139
|
-
def
|
140
|
-
@schema
|
121
|
+
def schema
|
122
|
+
@format.schema
|
141
123
|
end
|
142
124
|
|
143
125
|
|
144
|
-
# Return the
|
126
|
+
# Return the format defining the form of this version number
|
145
127
|
|
146
|
-
def
|
147
|
-
@
|
128
|
+
def format
|
129
|
+
@format
|
148
130
|
end
|
149
131
|
|
150
132
|
|
151
|
-
# Return the
|
133
|
+
# Return the unparsing parameters for this value.
|
134
|
+
# Returns nil if this value was not created using a parser.
|
152
135
|
|
153
|
-
def
|
154
|
-
@
|
136
|
+
def unparse_params
|
137
|
+
@unparse_params ? @unparse_params.dup : nil
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
# Iterates over each field, in field order, yielding the field name and value.
|
142
|
+
|
143
|
+
def each_field
|
144
|
+
@field_path.each do |field_|
|
145
|
+
yield(field_, @values[field_.name])
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
# Iterates over each field, in field order, yielding the
|
151
|
+
# Versionomy::Schema::Field object and value.
|
152
|
+
|
153
|
+
def each_field_object # :nodoc:
|
154
|
+
@field_path.each do |field_|
|
155
|
+
yield(field_, @values[field_.name])
|
156
|
+
end
|
155
157
|
end
|
156
158
|
|
157
159
|
|
158
160
|
# Returns an array of recognized field names for this value, in field order.
|
159
161
|
|
160
|
-
def
|
161
|
-
@
|
162
|
+
def field_names
|
163
|
+
@field_path.map{ |field_| field_.name }
|
162
164
|
end
|
163
165
|
|
164
166
|
|
165
|
-
# Returns true if this value contains the given field
|
167
|
+
# Returns true if this value contains the given field, which may be specified
|
168
|
+
# as a field object or name.
|
166
169
|
|
167
|
-
def has_field?(
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
@
|
170
|
+
def has_field?(field_)
|
171
|
+
case field_
|
172
|
+
when Schema::Field
|
173
|
+
@field_path.include?(field_)
|
174
|
+
when ::String, ::Symbol
|
175
|
+
@values.has_key?(field_.to_sym)
|
173
176
|
else
|
174
|
-
|
177
|
+
raise ::ArgumentError
|
175
178
|
end
|
176
179
|
end
|
177
180
|
|
178
181
|
|
179
182
|
# Returns the value of the given field, or nil if the field is not recognized.
|
183
|
+
# The field may be specified as a field object or field name.
|
180
184
|
|
181
|
-
def [](
|
182
|
-
|
183
|
-
|
184
|
-
@value
|
185
|
-
elsif @subvalue
|
186
|
-
@subvalue[symbol_]
|
187
|
-
else
|
188
|
-
nil
|
189
|
-
end
|
185
|
+
def [](field_)
|
186
|
+
field_ = field_.name if field_.kind_of?(Schema::Field)
|
187
|
+
@values[field_.to_sym]
|
190
188
|
end
|
191
189
|
|
192
190
|
|
193
191
|
# Returns the value as an array of field values, in field order.
|
194
192
|
|
195
|
-
def
|
196
|
-
@
|
193
|
+
def values_array
|
194
|
+
@field_path.map{ |field_| @values[field_.name] }
|
197
195
|
end
|
198
196
|
|
199
197
|
|
200
198
|
# Returns the value as a hash of values keyed by field name.
|
201
199
|
|
202
|
-
def
|
203
|
-
|
204
|
-
@subvalue ? @subvalue.value_hash.merge(hash_) : hash_
|
200
|
+
def values_hash
|
201
|
+
@values.dup
|
205
202
|
end
|
206
203
|
|
207
204
|
|
208
205
|
# Returns a new version number created by bumping the given field.
|
209
206
|
|
210
|
-
def bump(
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
if @subvalue.equal?(bumped_)
|
222
|
-
self
|
223
|
-
else
|
224
|
-
Versionomy::Value._new(@schema, @value, @parse_params, bumped_)
|
225
|
-
end
|
207
|
+
def bump(name_)
|
208
|
+
name_ = name_.name if name_.kind_of?(Schema::Field)
|
209
|
+
name_ = name_.to_sym
|
210
|
+
values_ = []
|
211
|
+
@field_path.each do |field_|
|
212
|
+
oldval_ = @values[field_.name]
|
213
|
+
if field_.name == name_
|
214
|
+
newval_ = field_.bump_value(oldval_)
|
215
|
+
return self if newval_ == oldval_
|
216
|
+
values_ << newval_
|
217
|
+
return Value.new(values_, @format, @unparse_params)
|
226
218
|
else
|
227
|
-
|
219
|
+
values_ << oldval_
|
228
220
|
end
|
229
221
|
end
|
222
|
+
self
|
230
223
|
end
|
231
224
|
|
232
225
|
|
233
226
|
# Returns a new version number created by changing the given field values.
|
234
227
|
|
235
|
-
def change(values_={})
|
236
|
-
|
228
|
+
def change(values_={}, unparse_params_={})
|
229
|
+
unparse_params_ = @unparse_params.merge(unparse_params_) if @unparse_params
|
230
|
+
Value.new(@values.merge(values_), @format, unparse_params_)
|
237
231
|
end
|
238
232
|
|
239
233
|
|
240
234
|
def hash # :nodoc:
|
241
|
-
@hash ||= @
|
235
|
+
@hash ||= @values.hash
|
242
236
|
end
|
243
237
|
|
244
238
|
|
245
239
|
# Returns true if this version number is equal to the given verison number.
|
246
|
-
# Equality means the
|
247
|
-
# schemas may actually be different.
|
240
|
+
# Equality means the schemas and values are the same.
|
248
241
|
|
249
242
|
def eql?(obj_)
|
250
|
-
if obj_.kind_of?(String)
|
251
|
-
obj_ = parse(obj_) rescue nil
|
243
|
+
if obj_.kind_of?(::String)
|
244
|
+
obj_ = @format.parse(obj_) rescue nil
|
252
245
|
end
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
else
|
259
|
-
true
|
260
|
-
end
|
261
|
-
else
|
262
|
-
false
|
246
|
+
return false unless obj_.kind_of?(Value)
|
247
|
+
index_ = 0
|
248
|
+
obj_.each_field_object do |field_, value_|
|
249
|
+
return false if field_ != @field_path[index_] || value_ != @values[field_.name]
|
250
|
+
index_ += 1
|
263
251
|
end
|
252
|
+
true
|
264
253
|
end
|
265
254
|
|
266
255
|
|
267
256
|
# Returns true if this version number is equal to the given verison number.
|
268
|
-
# Equality means the
|
269
|
-
# are different.
|
257
|
+
# Equality means the schemas and values are the same.
|
270
258
|
|
271
259
|
def ==(obj_)
|
272
260
|
eql?(obj_)
|
@@ -274,49 +262,42 @@ module Versionomy
|
|
274
262
|
|
275
263
|
|
276
264
|
# Compare this version number with the given version number.
|
277
|
-
# Version numbers with the same field names and types are comparable,
|
278
|
-
# even if the schemas are different.
|
279
265
|
|
280
266
|
def <=>(obj_)
|
281
|
-
if obj_.kind_of?(String)
|
282
|
-
obj_ = parse(obj_)
|
283
|
-
end
|
284
|
-
if !obj_.kind_of?(Versionomy::Value)
|
285
|
-
raise ArgumentError, "comparison of Versionomy::Value with #{obj_.class} failed"
|
267
|
+
if obj_.kind_of?(::String)
|
268
|
+
obj_ = @format.parse(obj_)
|
286
269
|
end
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
if
|
293
|
-
|
294
|
-
elsif !@subvalue.nil? && !obj_._subvalue.nil?
|
295
|
-
@subvalue <=> obj_._subvalue
|
296
|
-
else
|
297
|
-
raise SchemaMismatchError
|
298
|
-
end
|
299
|
-
else
|
300
|
-
val_
|
270
|
+
return nil unless obj_.kind_of?(Value)
|
271
|
+
index_ = 0
|
272
|
+
obj_.each_field_object do |field_, value_|
|
273
|
+
return nil unless field_ == @field_path[index_]
|
274
|
+
val_ = field_.compare_values(@values[field_.name], value_)
|
275
|
+
return val_ if val_ != 0
|
276
|
+
index_ += 1
|
301
277
|
end
|
278
|
+
0
|
302
279
|
end
|
303
280
|
|
304
281
|
|
305
282
|
# Compare this version number with the given version number.
|
306
|
-
# Version numbers with the same field names and types are comparable,
|
307
|
-
# even if the schemas are different.
|
308
283
|
|
309
284
|
def <(obj_)
|
310
|
-
(self <=> obj_)
|
285
|
+
val_ = (self <=> obj_)
|
286
|
+
unless val_
|
287
|
+
raise Errors::SchemaMismatchError
|
288
|
+
end
|
289
|
+
val_ < 0
|
311
290
|
end
|
312
291
|
|
313
292
|
|
314
293
|
# Compare this version number with the given version number.
|
315
|
-
# Version numbers with the same field names and types are comparable,
|
316
|
-
# even if the schemas are different.
|
317
294
|
|
318
295
|
def >(obj_)
|
319
|
-
(self <=> obj_)
|
296
|
+
val_ = (self <=> obj_)
|
297
|
+
unless val_
|
298
|
+
raise Errors::SchemaMismatchError
|
299
|
+
end
|
300
|
+
val_ > 0
|
320
301
|
end
|
321
302
|
|
322
303
|
|
@@ -327,15 +308,6 @@ module Versionomy
|
|
327
308
|
end
|
328
309
|
|
329
310
|
|
330
|
-
class << self
|
331
|
-
|
332
|
-
# :stopdoc:
|
333
|
-
alias_method :_new, :new
|
334
|
-
private :new
|
335
|
-
# :startdoc:
|
336
|
-
|
337
|
-
end
|
338
|
-
|
339
311
|
end
|
340
312
|
|
341
313
|
|
data/lib/versionomy/version.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Versionomy version
|
4
4
|
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
|
-
# Copyright 2008 Daniel Azuma
|
6
|
+
# Copyright 2008-2009 Daniel Azuma
|
7
7
|
#
|
8
8
|
# All rights reserved.
|
9
9
|
#
|
@@ -36,14 +36,14 @@
|
|
36
36
|
|
37
37
|
module Versionomy
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
# Current gem version, as a frozen string.
|
40
|
+
VERSION_STRING = '0.1.0'.freeze
|
41
|
+
|
42
|
+
# Current gem version, as a Versionomy::Value.
|
43
|
+
VERSION = ::Versionomy.parse(VERSION_STRING, ::Versionomy::Formats.standard)
|
41
44
|
|
42
45
|
end
|
43
46
|
|
44
47
|
|
45
|
-
|
46
|
-
|
47
|
-
VERSION = Versionomy.parse(VERSION_STRING)
|
48
|
-
|
49
|
-
end
|
48
|
+
::Blockenspiel.const_set(:VERSION,
|
49
|
+
::Versionomy.parse(::Blockenspiel::VERSION_STRING, ::Versionomy::Formats.standard))
|
data/lib/versionomy.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
# Versionomy entry point
|
4
4
|
#
|
5
5
|
# -----------------------------------------------------------------------------
|
6
|
-
# Copyright 2008 Daniel Azuma
|
6
|
+
# Copyright 2008-2009 Daniel Azuma
|
7
7
|
#
|
8
8
|
# All rights reserved.
|
9
9
|
#
|
@@ -34,13 +34,28 @@
|
|
34
34
|
;
|
35
35
|
|
36
36
|
|
37
|
-
|
38
|
-
require 'blockenspiel'
|
37
|
+
begin
|
38
|
+
require 'blockenspiel'
|
39
|
+
rescue LoadError
|
40
|
+
require 'rubygems'
|
41
|
+
require 'blockenspiel'
|
42
|
+
end
|
39
43
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
|
45
|
+
dir_ = File.expand_path('versionomy', File.dirname(__FILE__))
|
46
|
+
|
47
|
+
includes_ = [
|
48
|
+
'errors',
|
49
|
+
'schema',
|
50
|
+
'schema/field',
|
51
|
+
'schema/wrapper',
|
52
|
+
'format',
|
53
|
+
'format/base',
|
54
|
+
'format/delimiter',
|
55
|
+
'formats',
|
56
|
+
'formats/standard',
|
57
|
+
'value',
|
58
|
+
'interface',
|
59
|
+
'version',
|
60
|
+
]
|
61
|
+
includes_.each{ |file_| require "#{dir_}/#{file_}" }
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Versionomy parsing tests on standard schema
|
4
|
+
#
|
5
|
+
# This file contains tests for parsing on the standard schema
|
6
|
+
#
|
7
|
+
# -----------------------------------------------------------------------------
|
8
|
+
# Copyright 2008-2009 Daniel Azuma
|
9
|
+
#
|
10
|
+
# All rights reserved.
|
11
|
+
#
|
12
|
+
# Redistribution and use in source and binary forms, with or without
|
13
|
+
# modification, are permitted provided that the following conditions are met:
|
14
|
+
#
|
15
|
+
# * Redistributions of source code must retain the above copyright notice,
|
16
|
+
# this list of conditions and the following disclaimer.
|
17
|
+
# * Redistributions in binary form must reproduce the above copyright notice,
|
18
|
+
# this list of conditions and the following disclaimer in the documentation
|
19
|
+
# and/or other materials provided with the distribution.
|
20
|
+
# * Neither the name of the copyright holder, nor the names of any other
|
21
|
+
# contributors to this software, may be used to endorse or promote products
|
22
|
+
# derived from this software without specific prior written permission.
|
23
|
+
#
|
24
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
25
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
26
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
27
|
+
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
28
|
+
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
29
|
+
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
30
|
+
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
31
|
+
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
32
|
+
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
33
|
+
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
34
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
35
|
+
# -----------------------------------------------------------------------------
|
36
|
+
|
37
|
+
|
38
|
+
require 'test/unit'
|
39
|
+
require File.expand_path("#{File.dirname(__FILE__)}/../lib/versionomy.rb")
|
40
|
+
|
41
|
+
|
42
|
+
module Versionomy
|
43
|
+
module Tests # :nodoc:
|
44
|
+
|
45
|
+
class TestCustomFormat < Test::Unit::TestCase # :nodoc:
|
46
|
+
|
47
|
+
|
48
|
+
# Test parsing with custom format for patchlevel
|
49
|
+
|
50
|
+
def test_parsing_custom_patchlevel_format
|
51
|
+
format_ = Versionomy.default_format.modified_copy do
|
52
|
+
field(:patchlevel, :requires_previous_field => false) do
|
53
|
+
recognize_number(:delimiter_regexp => '\s?sp', :default_delimiter => ' SP')
|
54
|
+
end
|
55
|
+
end
|
56
|
+
value1_ = Versionomy.parse('2008 SP2', format_)
|
57
|
+
assert_equal(2, value1_.patchlevel)
|
58
|
+
value2_ = value1_.format.parse('2008 sp3')
|
59
|
+
assert_equal(3, value2_.patchlevel)
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
end
|