versionomy 0.0.1
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.txt +3 -0
- data/Manifest.txt +16 -0
- data/README.txt +134 -0
- data/Rakefile +49 -0
- data/lib/versionomy/errors.rb +107 -0
- data/lib/versionomy/format.rb +132 -0
- data/lib/versionomy/schema.rb +537 -0
- data/lib/versionomy/standard.rb +385 -0
- data/lib/versionomy/value.rb +291 -0
- data/lib/versionomy/version.rb +49 -0
- data/lib/versionomy.rb +46 -0
- data/tests/tc_standard_basic.rb +146 -0
- data/tests/tc_standard_bump.rb +170 -0
- data/tests/tc_standard_change.rb +97 -0
- data/tests/tc_standard_comparison.rb +77 -0
- data/tests/tc_standard_parse.rb +162 -0
- metadata +95 -0
@@ -0,0 +1,537 @@
|
|
1
|
+
# -----------------------------------------------------------------------------
|
2
|
+
#
|
3
|
+
# Versionomy schema
|
4
|
+
#
|
5
|
+
# -----------------------------------------------------------------------------
|
6
|
+
# Copyright 2008 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 schema.
|
41
|
+
#
|
42
|
+
# A schema is a set of field specifications that specify how a version
|
43
|
+
# number is structured. Each field has a name, a type, an initial value,
|
44
|
+
# and other properties.
|
45
|
+
#
|
46
|
+
# Schema fields may be integer-valued, string-valued, or symbolic.
|
47
|
+
# Symbolic fields are useful, for example, if you want a field to specify
|
48
|
+
# the type of prerelease (e.g. "alpha", "beta", or "release candidate").
|
49
|
+
#
|
50
|
+
# The Schema object itself actually represents only a single field, the
|
51
|
+
# "most significant" field. The next most significant field is specified
|
52
|
+
# by a child of this object, the next by a child of that child, and so
|
53
|
+
# forth down the line. You could therefore think of a simple schema as a
|
54
|
+
# chain of cons-cells.
|
55
|
+
#
|
56
|
+
# For example, you could construct a schema for versions numbers of
|
57
|
+
# the form "major.minor.tiny" like this:
|
58
|
+
#
|
59
|
+
# Schema(major) -> Schema(minor) -> Schema(tiny) -> nil
|
60
|
+
#
|
61
|
+
# Some schemas may be more complex than that, however. It is possible for
|
62
|
+
# the form of a schema's child to depend on the value of the field.
|
63
|
+
# For example, suppose we wanted a schema in which if the value of the
|
64
|
+
# "minor" field is 0, then the "tiny" field doesn't exist. It's possible
|
65
|
+
# to construct a schema of this form:
|
66
|
+
#
|
67
|
+
# Schema(major) -> Schema(minor) -> [value == 0] : nil
|
68
|
+
# [otherwise] : Schema(tiny) -> nil
|
69
|
+
|
70
|
+
class Schema
|
71
|
+
|
72
|
+
|
73
|
+
# Create a version number schema, with the given field name.
|
74
|
+
#
|
75
|
+
# Recognized options include:
|
76
|
+
#
|
77
|
+
# <tt>:type</tt>::
|
78
|
+
# Type of field. This should be <tt>:integer</tt>, <tt>:string</tt>, or <tt>:symbol</tt>.
|
79
|
+
# Default is <tt>:integer</tt>.
|
80
|
+
# <tt>:initial</tt>::
|
81
|
+
# Initial value. Default is 0 for an integer field, the empty string for a string field,
|
82
|
+
# or the first symbol added for a symbol field.
|
83
|
+
#
|
84
|
+
# You may provide an optional block. Within the block, you may call methods of
|
85
|
+
# Versionomy::Schema::Builder to further customize the field, or add subschemas.
|
86
|
+
#
|
87
|
+
# Raises Versionomy::Errors::IllegalValueError if the given initial value is not legal.
|
88
|
+
|
89
|
+
def initialize(name_, opts_={}, &block_)
|
90
|
+
@name = name_.to_sym
|
91
|
+
@type = opts_[:type] || :integer
|
92
|
+
@initial_value = opts_[:initial]
|
93
|
+
@symbol_info = nil
|
94
|
+
@symbol_order = nil
|
95
|
+
if @type == :symbol
|
96
|
+
@symbol_info = Hash.new
|
97
|
+
@symbol_order = Array.new
|
98
|
+
end
|
99
|
+
@bump_proc = nil
|
100
|
+
@compare_proc = nil
|
101
|
+
@canonicalize_proc = nil
|
102
|
+
@ranges = nil
|
103
|
+
@default_subschema = nil
|
104
|
+
@formats = Hash.new
|
105
|
+
@default_format_name = nil
|
106
|
+
Blockenspiel.invoke(block_, Versionomy::Schema::Builder.new(self))
|
107
|
+
@initial_value = canonicalize_value(@initial_value)
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
def _set_initial_value(value_) # :nodoc:
|
112
|
+
@initial_value = value_
|
113
|
+
end
|
114
|
+
|
115
|
+
def _add_symbol(symbol_, opts_={}) # :nodoc:
|
116
|
+
if @type != :symbol
|
117
|
+
raise Versionomy::Errors::TypeMismatchError
|
118
|
+
end
|
119
|
+
if @symbol_info.has_key?(symbol_)
|
120
|
+
raise Versionomy::Errors::SymbolRedefinedError
|
121
|
+
end
|
122
|
+
@symbol_info[symbol_] = [@symbol_order.size, opts_[:bump]]
|
123
|
+
@symbol_order << symbol_
|
124
|
+
if @initial_value.nil?
|
125
|
+
@initial_value = symbol_
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def _set_bump_proc(block_) # :nodoc:
|
130
|
+
@bump_proc = block_
|
131
|
+
end
|
132
|
+
|
133
|
+
def _set_canonicalize_proc(block_) # :nodoc:
|
134
|
+
@canonicalize_proc = block_
|
135
|
+
end
|
136
|
+
|
137
|
+
def _set_compare_proc(block_) # :nodoc:
|
138
|
+
@compare_proc = block_
|
139
|
+
end
|
140
|
+
|
141
|
+
|
142
|
+
# The name of the field.
|
143
|
+
|
144
|
+
def name
|
145
|
+
@name
|
146
|
+
end
|
147
|
+
|
148
|
+
|
149
|
+
# The type of the field.
|
150
|
+
# Possible values are <tt>:integer</tt>, <tt>:string</tt>, or <tt>:symbol</tt>.
|
151
|
+
|
152
|
+
def type
|
153
|
+
@type
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
# The initial value of the field
|
158
|
+
|
159
|
+
def initial_value
|
160
|
+
@initial_value
|
161
|
+
end
|
162
|
+
|
163
|
+
|
164
|
+
# Given a value, bump it to the "next" value.
|
165
|
+
# Utilizes a bump procedure if given;
|
166
|
+
# otherwise uses default behavior depending on the type.
|
167
|
+
|
168
|
+
def bump_value(value_)
|
169
|
+
if @bump_proc
|
170
|
+
nvalue_ = @bump_proc.call(value_)
|
171
|
+
nvalue_ || value_
|
172
|
+
elsif @type == :integer || @type == :string
|
173
|
+
value_.next
|
174
|
+
else
|
175
|
+
info_ = @symbol_info[value_]
|
176
|
+
info_ ? info_[1] || value_ : nil
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
|
181
|
+
# Perform a standard comparison on two values.
|
182
|
+
# Returns an integer that may be positive, negative, or 0.
|
183
|
+
# Utilizes a comparison procedure if given;
|
184
|
+
# otherwise uses default behavior depending on the type.
|
185
|
+
|
186
|
+
def compare_values(val1_, val2_)
|
187
|
+
if @compare_proc
|
188
|
+
@compare_proc.call(val1_, val2_)
|
189
|
+
elsif @type == :integer || @type == :string
|
190
|
+
val1_ <=> val2_
|
191
|
+
else
|
192
|
+
info1_ = @symbol_info[val1_]
|
193
|
+
info2_ = @symbol_info[val2_]
|
194
|
+
info1_ && info2_ ? info1_[0] <=> info2_[0] : nil
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
# Given a value, return a "canonical" value for this field.
|
200
|
+
# Utilizes a canonicalization procedure if given;
|
201
|
+
# otherwise uses default behavior depending on the type.
|
202
|
+
#
|
203
|
+
# Raises Versionomy::Errors::IllegalValueError if the given value is not legal.
|
204
|
+
|
205
|
+
def canonicalize_value(value_)
|
206
|
+
if @canonicalize_proc
|
207
|
+
value_ = @canonicalize_proc.call(value_)
|
208
|
+
else
|
209
|
+
case @type
|
210
|
+
when :integer
|
211
|
+
value_ = value_.to_i
|
212
|
+
when :string
|
213
|
+
value_ = value_.to_s
|
214
|
+
when :symbol
|
215
|
+
value_ = value_.to_sym
|
216
|
+
end
|
217
|
+
end
|
218
|
+
if value_.nil? || (@type == :symbol && !@symbol_info.has_key?(value_))
|
219
|
+
raise Versionomy::Errors::IllegalValueError
|
220
|
+
end
|
221
|
+
value_
|
222
|
+
end
|
223
|
+
|
224
|
+
|
225
|
+
# Define a formatter for this schema.
|
226
|
+
# You may either pass a formatter or provide a block
|
227
|
+
# that calls methods in Versionomy::Format::Builder.
|
228
|
+
|
229
|
+
def define_format(name_, formatter_=nil, &block_)
|
230
|
+
if block_
|
231
|
+
@formats[name_] = Versionomy::Format::Base.new(&block_)
|
232
|
+
else
|
233
|
+
@formats[name_] = formatter_
|
234
|
+
end
|
235
|
+
@default_format_name ||= name_
|
236
|
+
end
|
237
|
+
|
238
|
+
|
239
|
+
# Get the formatter with the given name.
|
240
|
+
# If the name is nil, returns the default formatter.
|
241
|
+
# If the name is not recognized, returns nil.
|
242
|
+
|
243
|
+
def get_format(name_)
|
244
|
+
@formats[name_ || @default_format_name]
|
245
|
+
end
|
246
|
+
|
247
|
+
|
248
|
+
# Returns the current default format name.
|
249
|
+
|
250
|
+
def default_format_name
|
251
|
+
@default_format_name
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
# Sets the default format by name.
|
256
|
+
|
257
|
+
def default_format_name=(name_)
|
258
|
+
if @formats[name_]
|
259
|
+
@default_format_name = name_
|
260
|
+
else
|
261
|
+
nil
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
|
266
|
+
# Create a new value with this schema.
|
267
|
+
#
|
268
|
+
# The values should either be a hash of field names and values, or an array
|
269
|
+
# of values that will be interpreted in field order.
|
270
|
+
|
271
|
+
def create(values_=nil)
|
272
|
+
Versionomy::Value._new(self, values_)
|
273
|
+
end
|
274
|
+
|
275
|
+
|
276
|
+
# Create a new value by parsing the given string.
|
277
|
+
#
|
278
|
+
# The optional parameters may include a <tt>:format</tt> parameter that
|
279
|
+
# specifies a format name. If no format is specified, the default format is used.
|
280
|
+
# The remaining parameters are passed into the formatter's parse method.
|
281
|
+
#
|
282
|
+
# Raises Versionomy::Errors::UnknownFormatError if the given format name is not recognized.
|
283
|
+
#
|
284
|
+
# Raises Versionomy::Errors::ParseError if parsing failed.
|
285
|
+
|
286
|
+
def parse(str_, params_={})
|
287
|
+
format_ = get_format(params_[:format])
|
288
|
+
if format_.nil?
|
289
|
+
raise Versionomy::Errors::UnknownFormatError
|
290
|
+
end
|
291
|
+
value_ = format_.parse(self, str_, params_)
|
292
|
+
end
|
293
|
+
|
294
|
+
|
295
|
+
# Returns the subschema associated with the given value.
|
296
|
+
|
297
|
+
def _subschema(value_) # :nodoc:
|
298
|
+
if @ranges
|
299
|
+
@ranges.each do |r_|
|
300
|
+
if !r_[0].nil?
|
301
|
+
cmp_ = compare_values(r_[0], value_)
|
302
|
+
next if cmp_.nil? || cmp_ > 0
|
303
|
+
end
|
304
|
+
if !r_[1].nil?
|
305
|
+
cmp_ = compare_values(r_[1], value_)
|
306
|
+
next if cmp_.nil? || cmp_ < 0
|
307
|
+
end
|
308
|
+
return r_[2]
|
309
|
+
end
|
310
|
+
end
|
311
|
+
@default_subschema
|
312
|
+
end
|
313
|
+
|
314
|
+
|
315
|
+
# Appends the given subschema for the given range
|
316
|
+
|
317
|
+
def _append_schema(schema_, ranges_=nil) # :nodoc:
|
318
|
+
if ranges_.nil?
|
319
|
+
if @default_subschema
|
320
|
+
raise Versionomy::Errors::RangeOverlapError
|
321
|
+
end
|
322
|
+
@default_subschema = schema_
|
323
|
+
return
|
324
|
+
end
|
325
|
+
if !ranges_.is_a?(Array) || range_.size == 2 &&
|
326
|
+
(range_[0].nil? || range_[0].is_a?(Symbol) ||
|
327
|
+
range_[0].kind_of?(Integer) || range_[0].is_a?(String)) &&
|
328
|
+
(range_[1].nil? || range_[1].is_a?(Symbol) ||
|
329
|
+
range_[1].kind_of?(Integer) || range_[1].is_a?(String))
|
330
|
+
then
|
331
|
+
ranges_ = [ranges_]
|
332
|
+
else
|
333
|
+
ranges_ = ranges_.dup
|
334
|
+
end
|
335
|
+
ranges_.each do |range_|
|
336
|
+
normalized_range_ = nil
|
337
|
+
if range_.kind_of?(Array) && range_.size != 2
|
338
|
+
raise Versionomy::Errors::RangeSpecificationError
|
339
|
+
end
|
340
|
+
case @type
|
341
|
+
when :integer
|
342
|
+
case range_
|
343
|
+
when Array
|
344
|
+
normalized_range_ = range_.map{ |elem_| elem_.nil? ? nil : elem_.to_i }
|
345
|
+
when Range
|
346
|
+
normalized_range_ = [range_.first, range_.exclude_end? ? range_.last-1 : range_.last]
|
347
|
+
when String, Symbol, Integer
|
348
|
+
range_ = range_.to_i
|
349
|
+
normalized_range_ = [range_, range_]
|
350
|
+
else
|
351
|
+
raise Versionomy::Errors::RangeSpecificationError
|
352
|
+
end
|
353
|
+
when :string
|
354
|
+
case range_
|
355
|
+
when Array
|
356
|
+
normalized_range_ = range_.map{ |elem_| elem_.nil? ? nil : elem_.to_s }
|
357
|
+
when Range
|
358
|
+
normalized_range_ = [range_.first.to_s,
|
359
|
+
range_.exclude_end? ? (range_.last-1).to_s : range_.last.to_s]
|
360
|
+
else
|
361
|
+
range_ = range_.to_s
|
362
|
+
normalized_range_ = [range_, range_]
|
363
|
+
end
|
364
|
+
when :symbol
|
365
|
+
case range_
|
366
|
+
when Array
|
367
|
+
normalized_range_ = range_.map do |elem_|
|
368
|
+
case elem_
|
369
|
+
when nil
|
370
|
+
nil
|
371
|
+
when Integer
|
372
|
+
elem_.to_s.to_sym
|
373
|
+
else
|
374
|
+
elem_.to_sym
|
375
|
+
end
|
376
|
+
end
|
377
|
+
when String, Integer
|
378
|
+
range_ = range_.to_s.to_sym
|
379
|
+
normalized_range_ = [range_, range_]
|
380
|
+
when Symbol
|
381
|
+
normalized_range_ = [range_, range_]
|
382
|
+
else
|
383
|
+
raise Versionomy::Errors::RangeSpecificationError
|
384
|
+
end
|
385
|
+
end
|
386
|
+
normalized_range_ << schema_
|
387
|
+
@ranges ||= Array.new
|
388
|
+
insert_index_ = @ranges.size
|
389
|
+
@ranges.each_with_index do |r_, i_|
|
390
|
+
if normalized_range_[0] && r_[1]
|
391
|
+
cmp_ = compare_values(normalized_range_[0], r_[1])
|
392
|
+
if cmp_.nil?
|
393
|
+
raise Versionomy::Errors::RangeSpecificationError
|
394
|
+
end
|
395
|
+
if cmp_ > 0
|
396
|
+
next
|
397
|
+
end
|
398
|
+
end
|
399
|
+
if normalized_range_[1] && r_[0]
|
400
|
+
cmp_ = compare_values(normalized_range_[1], r_[0])
|
401
|
+
if cmp_.nil?
|
402
|
+
raise Versionomy::Errors::RangeSpecificationError
|
403
|
+
end
|
404
|
+
if cmp_ < 0
|
405
|
+
insert_index_ = i_
|
406
|
+
break
|
407
|
+
end
|
408
|
+
end
|
409
|
+
raise Versionomy::Errors::RangeOverlapError
|
410
|
+
end
|
411
|
+
@ranges.insert(insert_index_, normalized_range_)
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
|
416
|
+
# These methods are available in a schema definition block.
|
417
|
+
|
418
|
+
class Builder
|
419
|
+
|
420
|
+
include Blockenspiel::DSL
|
421
|
+
|
422
|
+
def initialize(schema_) # :nodoc:
|
423
|
+
@schema = schema_
|
424
|
+
end
|
425
|
+
|
426
|
+
|
427
|
+
# Define the given symbol.
|
428
|
+
#
|
429
|
+
# Recognized options include:
|
430
|
+
#
|
431
|
+
# <tt>:bump</tt>::
|
432
|
+
# The symbol to transition to when "bump" is called.
|
433
|
+
# Default is to remain on the same value.
|
434
|
+
#
|
435
|
+
# Raises Versionomy::Errors::TypeMismatchError if called when the current schema
|
436
|
+
# is not of type <tt>:symbol</tt>.
|
437
|
+
#
|
438
|
+
# Raises Versionomy::Errors::SymbolRedefinedError if the given symbol name is
|
439
|
+
# already defined.
|
440
|
+
|
441
|
+
def symbol(symbol_, opts_={})
|
442
|
+
@schema._add_symbol(symbol_, opts_)
|
443
|
+
end
|
444
|
+
|
445
|
+
|
446
|
+
# Provide an initial value.
|
447
|
+
|
448
|
+
def initial_value(value_)
|
449
|
+
@schema._set_initial_value(value_)
|
450
|
+
end
|
451
|
+
|
452
|
+
|
453
|
+
# Provide a "bump" procedure.
|
454
|
+
# The given block should take a value, and return the value to transition to.
|
455
|
+
# If you return nil, the value will remain the same.
|
456
|
+
|
457
|
+
def to_bump(&block_)
|
458
|
+
@schema._set_bump_proc(block_)
|
459
|
+
end
|
460
|
+
|
461
|
+
|
462
|
+
# Provide a "compare" procedure.
|
463
|
+
# The given block should take two values and compare them.
|
464
|
+
# It should return a negative integer if the first is less than the second,
|
465
|
+
# a positive integer if the first is greater than the second, or 0 if the
|
466
|
+
# two values are equal. If the values cannot be compared, return nil.
|
467
|
+
|
468
|
+
def to_compare(&block_)
|
469
|
+
@schema._set_compare_proc(block_)
|
470
|
+
end
|
471
|
+
|
472
|
+
|
473
|
+
# Provide a "canonicalize" procedure.
|
474
|
+
# The given block should take a value and return a canonicalized value.
|
475
|
+
# Return nil if the given value is illegal.
|
476
|
+
|
477
|
+
def to_canonicalize(&block_)
|
478
|
+
@schema._set_canonicalize_proc(block_)
|
479
|
+
end
|
480
|
+
|
481
|
+
|
482
|
+
# Add a subschema.
|
483
|
+
#
|
484
|
+
# Recognized options include:
|
485
|
+
#
|
486
|
+
# <tt>:only</tt>::
|
487
|
+
# This subschema should be available only for the given values of this schema.
|
488
|
+
# See below for ways to specify this constraint.
|
489
|
+
# <tt>:type</tt>::
|
490
|
+
# Type of field. This should be <tt>:integer</tt>, <tt>:string</tt>, or <tt>:symbol</tt>.
|
491
|
+
# Default is <tt>:integer</tt>.
|
492
|
+
# <tt>:initial</tt>::
|
493
|
+
# Initial value. Default is 0 for an integer field, the empty string for a string field,
|
494
|
+
# or the first symbol added for a symbol field.
|
495
|
+
#
|
496
|
+
# You may provide an optional block. Within the block, you may call methods of this
|
497
|
+
# class again to customize the subschema.
|
498
|
+
#
|
499
|
+
# Raises Versionomy::Errors::IllegalValueError if the given initial value is not legal.
|
500
|
+
#
|
501
|
+
# The <tt>:only</tt> constraint may be specified in one of the following ways:
|
502
|
+
#
|
503
|
+
# * A single value (integer, string, or symbol)
|
504
|
+
# * A Range object defining a range of integers
|
505
|
+
# * A two-element array indicating a range of integers, strings, or symbols, inclusive.
|
506
|
+
# In this case, the ordering of symbols is defined by the order in which the symbols
|
507
|
+
# were added to this schema.
|
508
|
+
# If either element is nil, it is considered an open end of the range.
|
509
|
+
# * An array of arrays in the above form.
|
510
|
+
|
511
|
+
def schema(name_, opts_={}, &block_)
|
512
|
+
@schema._append_schema(Versionomy::Schema.new(name_, opts_, &block_), opts_.delete(:only))
|
513
|
+
end
|
514
|
+
|
515
|
+
|
516
|
+
# Define a formatter for this schema.
|
517
|
+
# You may either pass a formatter or provide a block
|
518
|
+
# that calls methods in Versionomy::Format::Builder.
|
519
|
+
|
520
|
+
def define_format(name_, formatter_=nil, &block_)
|
521
|
+
@schema.define_format(name_, formatter_, &block_)
|
522
|
+
end
|
523
|
+
|
524
|
+
|
525
|
+
# Sets the default format by name.
|
526
|
+
|
527
|
+
def set_default_format_name(name_)
|
528
|
+
@schema.default_format_name = name_
|
529
|
+
end
|
530
|
+
|
531
|
+
|
532
|
+
end
|
533
|
+
|
534
|
+
|
535
|
+
end
|
536
|
+
|
537
|
+
end
|