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.
- data/History.rdoc +4 -0
- data/Version +1 -1
- data/lib/versionomy.rb +19 -25
- data/lib/versionomy/conversion.rb +41 -41
- data/lib/versionomy/conversion/base.rb +31 -31
- data/lib/versionomy/conversion/parsing.rb +49 -49
- data/lib/versionomy/errors.rb +63 -63
- data/lib/versionomy/format.rb +51 -51
- data/lib/versionomy/format/base.rb +44 -44
- data/lib/versionomy/format/delimiter.rb +205 -205
- data/lib/versionomy/format_definitions/rubygems.rb +85 -85
- data/lib/versionomy/format_definitions/semver.rb +78 -78
- data/lib/versionomy/format_definitions/standard.rb +68 -68
- data/lib/versionomy/interface.rb +46 -46
- data/lib/versionomy/schema.rb +21 -21
- data/lib/versionomy/schema/field.rb +112 -112
- data/lib/versionomy/schema/wrapper.rb +91 -91
- data/lib/versionomy/value.rb +224 -180
- data/lib/versionomy/version.rb +9 -9
- data/test/tc_custom_format.rb +14 -14
- data/test/tc_readme_examples.rb +24 -24
- data/test/tc_rubygems_basic.rb +68 -68
- data/test/tc_rubygems_conversions.rb +46 -46
- data/test/tc_semver_basic.rb +62 -62
- data/test/tc_semver_conversions.rb +52 -52
- data/test/tc_standard_basic.rb +35 -35
- data/test/tc_standard_bump.rb +35 -35
- data/test/tc_standard_change.rb +20 -20
- data/test/tc_standard_comparison.rb +38 -38
- data/test/tc_standard_misc.rb +23 -23
- data/test/tc_standard_parse.rb +77 -77
- data/test/tc_standard_reset.rb +29 -29
- data/test/tc_version_of.rb +15 -15
- metadata +30 -34
@@ -1,15 +1,15 @@
|
|
1
1
|
# -----------------------------------------------------------------------------
|
2
|
-
#
|
2
|
+
#
|
3
3
|
# Versionomy delimiter format
|
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,28 +35,28 @@
|
|
35
35
|
|
36
36
|
|
37
37
|
module Versionomy
|
38
|
-
|
38
|
+
|
39
39
|
module Format
|
40
|
-
|
41
|
-
|
40
|
+
|
41
|
+
|
42
42
|
# The Delimiter format class provides a DSL for building formats that
|
43
43
|
# can handle most cases where the fields of a version number appear
|
44
44
|
# consecutively in order in the string formatting. We expect most
|
45
45
|
# version number schemes should fall into this category.
|
46
|
-
#
|
46
|
+
#
|
47
47
|
# In general, the strategy is to provide, for each field, a set of
|
48
48
|
# regular expressions that recognize different formats for that field.
|
49
49
|
# Every field must be of the form "(pre)(value)(post)"
|
50
50
|
# where (pre) and (post) are delimiters preceding and
|
51
51
|
# following the value. Either or both delimiters may be the empty string.
|
52
|
-
#
|
52
|
+
#
|
53
53
|
# To parse a string, the string is scanned from left to right and
|
54
54
|
# matched against the format for the fields in order. If the string
|
55
55
|
# matches, that part of the string is consumed and the field value is
|
56
56
|
# interpreted from it. If the string does not match, and the field is
|
57
57
|
# not marked as "required", then the field is set to its default value
|
58
58
|
# and the next field is tried.
|
59
|
-
#
|
59
|
+
#
|
60
60
|
# During parsing, the actual delimiters, along with other information
|
61
61
|
# such as whether or not fields are required, are saved into a default
|
62
62
|
# set of parameters for unparsing. These are saved in the unparse_params
|
@@ -64,26 +64,26 @@ module Versionomy
|
|
64
64
|
# generally the same form. If the version number value is modified, this
|
65
65
|
# allows the unparsing of the new value to generally follow the format
|
66
66
|
# of the original string.
|
67
|
-
#
|
67
|
+
#
|
68
68
|
# Formats that use the Delimiter mechanism also provide support for
|
69
69
|
# certain parsing and unparsing parameters. See the documentation for
|
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
73
|
# Versionomy::Format::Standard#create.
|
74
|
-
|
74
|
+
|
75
75
|
class Delimiter < Base
|
76
|
-
|
77
|
-
|
76
|
+
|
77
|
+
|
78
78
|
# Create a format using delimiter tools.
|
79
79
|
# You should provide the version number schema, a set of default
|
80
|
-
# options, and a block.
|
81
|
-
#
|
80
|
+
# options, and a block.
|
81
|
+
#
|
82
82
|
# Within the block, you can call methods of
|
83
83
|
# Versionomy::Format::Delimiter::Builder
|
84
84
|
# to provide parsers for the fields of the schema. Any fields you do
|
85
85
|
# not explicitly configure will get parsed in a default manner.
|
86
|
-
|
86
|
+
|
87
87
|
def initialize(schema_, default_opts_={}, &block_)
|
88
88
|
# Special case used by modified_copy
|
89
89
|
if schema_.kind_of?(Delimiter)
|
@@ -97,7 +97,7 @@ module Versionomy
|
|
97
97
|
::Blockenspiel.invoke(block_, builder_)
|
98
98
|
return
|
99
99
|
end
|
100
|
-
|
100
|
+
|
101
101
|
@schema = schema_
|
102
102
|
@field_handlers = {}
|
103
103
|
@default_parse_params = {}
|
@@ -110,22 +110,22 @@ module Versionomy
|
|
110
110
|
@field_handlers[name_] ||= Delimiter::FieldHandler.new(@schema.field_named(name_), default_opts_)
|
111
111
|
end
|
112
112
|
end
|
113
|
-
|
114
|
-
|
113
|
+
|
114
|
+
|
115
115
|
# Returns the schema understood by this format.
|
116
116
|
# This method is required by the Format contract.
|
117
|
-
|
117
|
+
|
118
118
|
def schema
|
119
119
|
@schema
|
120
120
|
end
|
121
|
-
|
122
|
-
|
121
|
+
|
122
|
+
|
123
123
|
# Parse the given string and return a value.
|
124
124
|
# This method is required by the Format contract.
|
125
|
-
#
|
125
|
+
#
|
126
126
|
# This method provides, out of the box, support for the following
|
127
127
|
# parse parameters:
|
128
|
-
#
|
128
|
+
#
|
129
129
|
# <tt>:extra_characters</tt>::
|
130
130
|
# Determines what to do if the entire string cannot be consumed by
|
131
131
|
# the parsing process. If set to <tt>:ignore</tt>, any extra
|
@@ -135,7 +135,7 @@ module Versionomy
|
|
135
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
|
+
|
139
139
|
def parse(string_, params_=nil)
|
140
140
|
parse_params_ = default_parse_params
|
141
141
|
parse_params_.merge!(params_) if params_
|
@@ -201,14 +201,14 @@ module Versionomy
|
|
201
201
|
end
|
202
202
|
Value.new(parse_state_[:values], self, unparse_params_)
|
203
203
|
end
|
204
|
-
|
205
|
-
|
204
|
+
|
205
|
+
|
206
206
|
# Unparse the given value and return a string.
|
207
207
|
# This method is required by the Format contract.
|
208
|
-
#
|
208
|
+
#
|
209
209
|
# This method provides, out of the box, support for the following
|
210
210
|
# unparse parameters:
|
211
|
-
#
|
211
|
+
#
|
212
212
|
# <tt>:suffix</tt>::
|
213
213
|
# A string to append to the unparsed string. Default is nothing.
|
214
214
|
# <tt>:required_fields</tt>::
|
@@ -241,7 +241,7 @@ module Versionomy
|
|
241
241
|
# This is used by letter-formatted integer fields only, and
|
242
242
|
# sets the case to use while unparsing. Recognized values are
|
243
243
|
# <tt>:lower</tt> (the default), and <tt>:upper</tt>.
|
244
|
-
|
244
|
+
|
245
245
|
def unparse(value_, params_=nil)
|
246
246
|
unparse_params_ = value_.unparse_params || default_unparse_params
|
247
247
|
_interpret_field_lists(unparse_params_)
|
@@ -280,42 +280,42 @@ module Versionomy
|
|
280
280
|
string_ << (unparse_params_[:suffix] || '')
|
281
281
|
string_
|
282
282
|
end
|
283
|
-
|
284
|
-
|
283
|
+
|
284
|
+
|
285
285
|
# Return a copy of the default parsing parameters used by this format.
|
286
286
|
# This hash cannot be edited in place. To modify the default parsing
|
287
287
|
# parameters, use modified_copy and call
|
288
288
|
# Versionomy::Format::Delimiter::Builder#default_parse_params in the block.
|
289
|
-
|
289
|
+
|
290
290
|
def default_parse_params
|
291
291
|
@default_parse_params.dup
|
292
292
|
end
|
293
|
-
|
294
|
-
|
293
|
+
|
294
|
+
|
295
295
|
# Return a copy of the default unparsing parameters used by this format.
|
296
296
|
# This hash cannot be edited in place. To modify the default unparsing
|
297
297
|
# parameters, use modified_copy and call
|
298
298
|
# Versionomy::Format::Delimiter::Builder#default_unparse_params in the block.
|
299
|
-
|
299
|
+
|
300
300
|
def default_unparse_params
|
301
301
|
@default_unparse_params.dup
|
302
302
|
end
|
303
|
-
|
304
|
-
|
303
|
+
|
304
|
+
|
305
305
|
# Create a copy of this format, with the modifications given in the
|
306
306
|
# provided block. You can call methods of Versionomy::Format::Delimiter::Builder
|
307
307
|
# in the block. Field handlers that you specify in that block will
|
308
308
|
# override and change the field handlers from the original. Any fields
|
309
309
|
# not specified in this block will use the handlers from the original.
|
310
|
-
|
310
|
+
|
311
311
|
def modified_copy(&block_)
|
312
312
|
Delimiter.new(self, &block_)
|
313
313
|
end
|
314
|
-
|
315
|
-
|
314
|
+
|
315
|
+
|
316
316
|
# A utility method that interprets required_fields and
|
317
317
|
# optional_fields parameters.
|
318
|
-
|
318
|
+
|
319
319
|
def _interpret_field_lists(unparse_params_) # :nodoc:
|
320
320
|
fields_ = unparse_params_.delete(:required_fields)
|
321
321
|
if fields_
|
@@ -333,34 +333,34 @@ module Versionomy
|
|
333
333
|
end
|
334
334
|
end
|
335
335
|
private :_interpret_field_lists
|
336
|
-
|
337
|
-
|
336
|
+
|
337
|
+
|
338
338
|
# This class defines methods that you can call within the DSL block
|
339
339
|
# passed to Versionomy::Format::Delimiter#new.
|
340
|
-
#
|
340
|
+
#
|
341
341
|
# Generally, you call the field method of this class a number of times
|
342
342
|
# to define the formatting for each field.
|
343
|
-
|
343
|
+
|
344
344
|
class Builder
|
345
|
-
|
345
|
+
|
346
346
|
include ::Blockenspiel::DSL
|
347
|
-
|
347
|
+
|
348
348
|
def initialize(schema_, field_handlers_, default_parse_params_, default_unparse_params_) # :nodoc:
|
349
349
|
@schema = schema_
|
350
350
|
@field_handlers = field_handlers_
|
351
351
|
@default_parse_params = default_parse_params_
|
352
352
|
@default_unparse_params = default_unparse_params_
|
353
353
|
end
|
354
|
-
|
355
|
-
|
354
|
+
|
355
|
+
|
356
356
|
# Specify how to handle a given field.
|
357
357
|
# You must pass the name of the field, a hash of options, and a
|
358
358
|
# block defining the handling of the field.
|
359
|
-
#
|
359
|
+
#
|
360
360
|
# Within the block, you set up "recognizers" for various regular
|
361
361
|
# expression patterns. These recognizers are tested in order when
|
362
362
|
# parsing a version number.
|
363
|
-
#
|
363
|
+
#
|
364
364
|
# The methods that can be called from the block are determined by
|
365
365
|
# the type of field. If the field is an integer field, the methods
|
366
366
|
# of Versionomy::Format::Delimiter::IntegerFieldBuilder can be
|
@@ -368,20 +368,20 @@ module Versionomy
|
|
368
368
|
# of Versionomy::Format::Delimiter::StringFieldBuilder can be
|
369
369
|
# called. If the field is a symbolic field, the methods of
|
370
370
|
# Versionomy::Format::Delimiter::SymbolFieldBuilder can be called.
|
371
|
-
#
|
371
|
+
#
|
372
372
|
# === Options
|
373
|
-
#
|
373
|
+
#
|
374
374
|
# The opts hash includes a number of options that control how the
|
375
375
|
# field is parsed.
|
376
|
-
#
|
376
|
+
#
|
377
377
|
# Some of these are regular expressions that indicate what patterns
|
378
378
|
# are recognized by the parser. Regular expressions should be passed
|
379
379
|
# in as the string representation of the regular expression, not a
|
380
380
|
# Regexp object itself. For example, use the string '-' rather than
|
381
381
|
# the Regexp /-/ to recognize a hyphen delimiter.
|
382
|
-
#
|
382
|
+
#
|
383
383
|
# The following options are recognized:
|
384
|
-
#
|
384
|
+
#
|
385
385
|
# <tt>:default_value_optional</tt>::
|
386
386
|
# If set to true, this the field may be omitted in the unparsed
|
387
387
|
# (formatted) version number, if the value is the default value
|
@@ -447,15 +447,15 @@ module Versionomy
|
|
447
447
|
# The default style for this field. This is the style used for
|
448
448
|
# unparsing if the value was not constructed by a parser or is
|
449
449
|
# otherwise missing the style for this field.
|
450
|
-
#
|
450
|
+
#
|
451
451
|
# === Styles
|
452
|
-
#
|
452
|
+
#
|
453
453
|
# A field may have different representation "styles". For example,
|
454
454
|
# you could represent a patchlevel of 1 as "1.0-1" or "1.0a".
|
455
455
|
# When a version number string is parsed, the parser and unparser
|
456
456
|
# work together to remember which style was parsed, and that style
|
457
457
|
# is used when the version number is unparsed.
|
458
|
-
#
|
458
|
+
#
|
459
459
|
# Specify styles as options to the calls made within the block that
|
460
460
|
# is passed to this method. In the above case, you could define the
|
461
461
|
# patchlevel field with a block that has two calls, one that uses
|
@@ -463,11 +463,11 @@ module Versionomy
|
|
463
463
|
# option <tt>:style => :number</tt>, and another that uses
|
464
464
|
# Delimiter::IntegerFieldBuilder#recognize_letter and passes the
|
465
465
|
# option <tt>:style => :letter</tt>.
|
466
|
-
#
|
466
|
+
#
|
467
467
|
# The standard format uses styles to preserve the different
|
468
468
|
# syntaxes for the release_type field. See the source code in
|
469
469
|
# Versionomy::Format::Standard#create for this example.
|
470
|
-
|
470
|
+
|
471
471
|
def field(name_, opts_={}, &block_)
|
472
472
|
name_ = name_.to_sym
|
473
473
|
field_ = @schema.field_named(name_)
|
@@ -476,193 +476,193 @@ module Versionomy
|
|
476
476
|
end
|
477
477
|
@field_handlers[name_] = Delimiter::FieldHandler.new(field_, opts_, &block_)
|
478
478
|
end
|
479
|
-
|
480
|
-
|
479
|
+
|
480
|
+
|
481
481
|
# Set or modify the default parameters used when parsing a value.
|
482
|
-
|
482
|
+
|
483
483
|
def default_parse_params(params_)
|
484
484
|
@default_parse_params.merge!(params_)
|
485
485
|
end
|
486
|
-
|
487
|
-
|
486
|
+
|
487
|
+
|
488
488
|
# Set or modify the default parameters used when unparsing a value.
|
489
|
-
|
489
|
+
|
490
490
|
def default_unparse_params(params_)
|
491
491
|
@default_unparse_params.merge!(params_)
|
492
492
|
end
|
493
|
-
|
493
|
+
|
494
494
|
end
|
495
|
-
|
496
|
-
|
495
|
+
|
496
|
+
|
497
497
|
# This class defines methods that can be called from the block passed
|
498
498
|
# to Versionomy::Format::Delimiter::Builder#field if the field is
|
499
499
|
# of integer type.
|
500
|
-
|
500
|
+
|
501
501
|
class IntegerFieldBuilder
|
502
|
-
|
502
|
+
|
503
503
|
include ::Blockenspiel::DSL
|
504
|
-
|
504
|
+
|
505
505
|
def initialize(recognizers_, field_, default_opts_) # :nodoc:
|
506
506
|
@recognizers = recognizers_
|
507
507
|
@field = field_
|
508
508
|
@default_opts = default_opts_
|
509
509
|
end
|
510
|
-
|
511
|
-
|
510
|
+
|
511
|
+
|
512
512
|
# Recognize a numeric-formatted integer field.
|
513
513
|
# Using the opts parameter, you can override any of the field's
|
514
514
|
# overall parsing options. You may also set the following additional
|
515
515
|
# options:
|
516
|
-
#
|
516
|
+
#
|
517
517
|
# <tt>:strip_leading_zeros</tt>::
|
518
518
|
# If false (the default), and a value has leading zeros, it is
|
519
519
|
# assumed that the field has a minimum width, and unparsing will
|
520
520
|
# always pad left with zeros to reach that minimum width. If set
|
521
521
|
# to true, leading zeros are stripped from a value, and this
|
522
522
|
# padding is never done.
|
523
|
-
|
523
|
+
|
524
524
|
def recognize_number(opts_={})
|
525
525
|
@recognizers << Delimiter::BasicIntegerRecognizer.new(@field, @default_opts.merge(opts_))
|
526
526
|
end
|
527
|
-
|
528
|
-
|
527
|
+
|
528
|
+
|
529
529
|
# Recognize a letter-formatted integer field. That is, the value is
|
530
530
|
# formatted as an alphabetic letter where "a" represents 1, up to
|
531
531
|
# "z" representing 26.
|
532
|
-
#
|
532
|
+
#
|
533
533
|
# Using the opts parameter, you can override any of the field's
|
534
534
|
# overall parsing options. You may also set the following additional
|
535
535
|
# options:
|
536
|
-
#
|
536
|
+
#
|
537
537
|
# <tt>:case</tt>::
|
538
538
|
# Case-sensitivity of the letter. Possible values are
|
539
539
|
# <tt>:upper</tt>, <tt>:lower</tt>, and <tt>:either</tt>.
|
540
540
|
# Default is <tt>:either</tt>.
|
541
|
-
|
541
|
+
|
542
542
|
def recognize_letter(opts_={})
|
543
543
|
@recognizers << Delimiter::AlphabeticIntegerRecognizer.new(@field, @default_opts.merge(opts_))
|
544
544
|
end
|
545
|
-
|
545
|
+
|
546
546
|
end
|
547
|
-
|
548
|
-
|
547
|
+
|
548
|
+
|
549
549
|
# This class defines methods that can be called from the block passed
|
550
550
|
# to Versionomy::Format::Delimiter::Builder#field if the field is
|
551
551
|
# of string type.
|
552
|
-
|
552
|
+
|
553
553
|
class StringFieldBuilder
|
554
|
-
|
554
|
+
|
555
555
|
include ::Blockenspiel::DSL
|
556
|
-
|
556
|
+
|
557
557
|
def initialize(recognizers_, field_, default_opts_) # :nodoc:
|
558
558
|
@recognizers = recognizers_
|
559
559
|
@field = field_
|
560
560
|
@default_opts = default_opts_
|
561
561
|
end
|
562
|
-
|
563
|
-
|
562
|
+
|
563
|
+
|
564
564
|
# Recognize a string field whose value matches a regular expression.
|
565
565
|
# The regular expression must be passed as a string. E.g. use
|
566
566
|
# "[a-z]+" instead of /[a-z]+/.
|
567
567
|
# Using the opts parameter, you can override any of the field's
|
568
568
|
# overall parsing options.
|
569
|
-
|
569
|
+
|
570
570
|
def recognize_regexp(regexp_, opts_={})
|
571
571
|
@recognizers << Delimiter::RegexpStringRecognizer.new(@field, regexp_, @default_opts.merge(opts_))
|
572
572
|
end
|
573
|
-
|
573
|
+
|
574
574
|
end
|
575
|
-
|
576
|
-
|
575
|
+
|
576
|
+
|
577
577
|
# This class defines methods that can be called from the block passed
|
578
578
|
# to Versionomy::Format::Delimiter::Builder#field if the field is
|
579
579
|
# of symbolic type.
|
580
|
-
|
580
|
+
|
581
581
|
class SymbolFieldBuilder
|
582
|
-
|
582
|
+
|
583
583
|
include ::Blockenspiel::DSL
|
584
|
-
|
584
|
+
|
585
585
|
def initialize(recognizers_, field_, default_opts_) # :nodoc:
|
586
586
|
@recognizers = recognizers_
|
587
587
|
@field = field_
|
588
588
|
@default_opts = default_opts_
|
589
589
|
end
|
590
|
-
|
591
|
-
|
590
|
+
|
591
|
+
|
592
592
|
# Recognize a symbolic value represented by a particular regular
|
593
593
|
# expression. The regular expression must be passed as a string.
|
594
594
|
# E.g. use "[a-z]+" instead of /[a-z]+/.
|
595
595
|
# The "canonical" parameter indicates the canonical syntax for the
|
596
596
|
# value, for use in unparsing.
|
597
|
-
#
|
597
|
+
#
|
598
598
|
# Using the opts parameter, you can override any of the field's
|
599
599
|
# overall parsing options.
|
600
|
-
|
600
|
+
|
601
601
|
def recognize_regexp(value_, regexp_, canonical_, opts_={}, &block_)
|
602
602
|
@recognizers << Delimiter::RegexpSymbolRecognizer.new(@field, value_, regexp_, canonical_, @default_opts.merge(opts_))
|
603
603
|
end
|
604
|
-
|
605
|
-
|
604
|
+
|
605
|
+
|
606
606
|
# Recognize a set of symbolic values, each represented by a
|
607
607
|
# particular regular expression, but all sharing the same delimiters
|
608
608
|
# and options. Use this instead of repeated calls to recognize_regexp
|
609
609
|
# for better performance.
|
610
|
-
#
|
610
|
+
#
|
611
611
|
# Using the opts parameter, you can override any of the field's
|
612
612
|
# overall parsing options.
|
613
|
-
#
|
613
|
+
#
|
614
614
|
# In the block, you should call methods of
|
615
615
|
# Versionomy::Format::Delimiter::MappingSymbolBuilder to map values
|
616
616
|
# to regular expression representations.
|
617
|
-
|
617
|
+
|
618
618
|
def recognize_regexp_map(opts_={}, &block_)
|
619
619
|
@recognizers << Delimiter::MappingSymbolRecognizer.new(@field, @default_opts.merge(opts_), &block_)
|
620
620
|
end
|
621
|
-
|
621
|
+
|
622
622
|
end
|
623
|
-
|
624
|
-
|
623
|
+
|
624
|
+
|
625
625
|
# Methods in this class can be called from the block passed to
|
626
626
|
# Versionomy::Format::Delimiter::SymbolFieldBuilder#recognize_regexp_map
|
627
627
|
# to define the mapping between the values of a symbolic field and
|
628
628
|
# the string representations of those values.
|
629
|
-
|
629
|
+
|
630
630
|
class MappingSymbolBuilder
|
631
|
-
|
631
|
+
|
632
632
|
include ::Blockenspiel::DSL
|
633
|
-
|
633
|
+
|
634
634
|
def initialize(mappings_in_order_, mappings_by_value_) # :nodoc:
|
635
635
|
@mappings_in_order = mappings_in_order_
|
636
636
|
@mappings_by_value = mappings_by_value_
|
637
637
|
end
|
638
|
-
|
639
|
-
|
638
|
+
|
639
|
+
|
640
640
|
# Map a value to a string representation.
|
641
641
|
# The optional regexp field, if specified, provides a regular
|
642
642
|
# expression pattern for matching the value representation. If it
|
643
643
|
# is omitted, the representation is used as the regexp.
|
644
|
-
|
644
|
+
|
645
645
|
def map(value_, representation_, regexp_=nil)
|
646
646
|
regexp_ ||= representation_
|
647
647
|
array_ = [regexp_, representation_, value_]
|
648
648
|
@mappings_by_value[value_] ||= array_
|
649
649
|
@mappings_in_order << array_
|
650
650
|
end
|
651
|
-
|
651
|
+
|
652
652
|
end
|
653
|
-
|
654
|
-
|
653
|
+
|
654
|
+
|
655
655
|
# This class handles the parsing and unparsing of a single field.
|
656
656
|
# It manages an ordered list of recognizers, each understanding a
|
657
657
|
# particular syntax. These recognizers are checked in order when
|
658
658
|
# parsing and unparsing.
|
659
|
-
|
659
|
+
|
660
660
|
class FieldHandler # :nodoc:
|
661
|
-
|
662
|
-
|
661
|
+
|
662
|
+
|
663
663
|
# Creates a FieldHandler, using a DSL block appropriate to the
|
664
664
|
# field type to configure the recognizers.
|
665
|
-
|
665
|
+
|
666
666
|
def initialize(field_, default_opts_={}, &block_)
|
667
667
|
@field = field_
|
668
668
|
@recognizers = []
|
@@ -682,45 +682,45 @@ module Versionomy
|
|
682
682
|
::Blockenspiel.invoke(block_, builder_)
|
683
683
|
end
|
684
684
|
end
|
685
|
-
|
686
|
-
|
685
|
+
|
686
|
+
|
687
687
|
# Returns true if this field can appear in an unparsed string only
|
688
688
|
# if the previous field also appears.
|
689
|
-
|
689
|
+
|
690
690
|
def requires_previous_field
|
691
691
|
@requires_previous_field
|
692
692
|
end
|
693
|
-
|
694
|
-
|
693
|
+
|
694
|
+
|
695
695
|
# Returns the default value set when this field is missing from a
|
696
696
|
# version string.
|
697
|
-
|
697
|
+
|
698
698
|
def default_value
|
699
699
|
@default_value
|
700
700
|
end
|
701
|
-
|
702
|
-
|
701
|
+
|
702
|
+
|
703
703
|
# Gets the given indexed recognizer. Returns nil if the index is out
|
704
704
|
# of range.
|
705
|
-
|
705
|
+
|
706
706
|
def get_recognizer(index_)
|
707
707
|
@recognizers[index_]
|
708
708
|
end
|
709
|
-
|
710
|
-
|
709
|
+
|
710
|
+
|
711
711
|
# Finishes up parsing by setting the appropriate style field in the
|
712
712
|
# unparse_params, if needed.
|
713
|
-
|
713
|
+
|
714
714
|
def set_style_unparse_param(style_, unparse_params_)
|
715
715
|
if style_ && style_ != @default_style
|
716
716
|
unparse_params_[@style_unparse_param_key] = style_
|
717
717
|
end
|
718
718
|
end
|
719
|
-
|
720
|
-
|
719
|
+
|
720
|
+
|
721
721
|
# Unparse a string from this field value.
|
722
722
|
# This may return nil if this field is not required.
|
723
|
-
|
723
|
+
|
724
724
|
def unparse(value_, unparse_params_, required_for_later_)
|
725
725
|
style_ = unparse_params_[@style_unparse_param_key] || @default_style
|
726
726
|
@recognizers.each do |recog_|
|
@@ -731,10 +731,10 @@ module Versionomy
|
|
731
731
|
end
|
732
732
|
required_for_later_ ? ['', false] : nil
|
733
733
|
end
|
734
|
-
|
734
|
+
|
735
735
|
end
|
736
|
-
|
737
|
-
|
736
|
+
|
737
|
+
|
738
738
|
# A recognizer handles both parsing and unparsing of a particular kind
|
739
739
|
# of syntax. During parsing, it recognizes the syntax based on regular
|
740
740
|
# expressions for the delimiters and the value. If the string matches
|
@@ -745,16 +745,16 @@ module Versionomy
|
|
745
745
|
# true, the unparse method should be called to actually generate a
|
746
746
|
# a string fragment, or return nil if the field is determined to be
|
747
747
|
# optional in the unparsed string.
|
748
|
-
#
|
748
|
+
#
|
749
749
|
# This is a base class. The actual classes should implement
|
750
750
|
# initialize, parsed_value, and unparsed_value, and may optionally
|
751
751
|
# override the should_unparse? method.
|
752
|
-
|
752
|
+
|
753
753
|
class RecognizerBase # :nodoc:
|
754
|
-
|
754
|
+
|
755
755
|
# Derived classes should call this from their initialize method
|
756
756
|
# to set up the recognizer's basic parameters.
|
757
|
-
|
757
|
+
|
758
758
|
def setup(field_, value_regexp_, opts_)
|
759
759
|
@style = opts_[:style]
|
760
760
|
@default_value_optional = opts_[:default_value_optional]
|
@@ -778,13 +778,13 @@ module Versionomy
|
|
778
778
|
@post_delim_unparse_param_key = "#{name_}_postdelim".to_sym
|
779
779
|
@required_unparse_param_key = "#{name_}_required".to_sym
|
780
780
|
end
|
781
|
-
|
782
|
-
|
781
|
+
|
782
|
+
|
783
783
|
# Attempt to parse the field from the string if the syntax matches
|
784
784
|
# this recognizer's configuration.
|
785
785
|
# Returns either nil, indicating that this recognizer doesn't match
|
786
786
|
# the given syntax, or a two element array of the value and style.
|
787
|
-
|
787
|
+
|
788
788
|
def parse(parse_state_, parse_params_)
|
789
789
|
return nil if @requires_previous_field && parse_state_[:previous_field_missing]
|
790
790
|
string_ = parse_state_[:string]
|
@@ -824,32 +824,32 @@ module Versionomy
|
|
824
824
|
unparse_params_[@required_unparse_param_key] = true if @default_value_optional
|
825
825
|
[parse_result_[0], @style, string_, unparse_params_]
|
826
826
|
end
|
827
|
-
|
828
|
-
|
827
|
+
|
828
|
+
|
829
829
|
# Returns true if this field can appear in an unparsed string only
|
830
830
|
# if the next field also appears.
|
831
|
-
|
831
|
+
|
832
832
|
def requires_next_field
|
833
833
|
@requires_next_field
|
834
834
|
end
|
835
|
-
|
836
|
-
|
835
|
+
|
836
|
+
|
837
837
|
# Returns true if this recognizer should be used to unparse the
|
838
838
|
# given value and style.
|
839
|
-
|
839
|
+
|
840
840
|
def should_unparse?(value_, style_)
|
841
841
|
style_ == @style
|
842
842
|
end
|
843
|
-
|
844
|
-
|
843
|
+
|
844
|
+
|
845
845
|
# Unparse the given value in the given style, and return a string
|
846
846
|
# fragment, or nil if the field is determined to be "optional" to
|
847
847
|
# unparse and isn't otherwise required (because a later field needs
|
848
848
|
# it to be present, for example).
|
849
|
-
#
|
849
|
+
#
|
850
850
|
# It is guaranteed that this will be called only if should_unparse?
|
851
851
|
# returns true.
|
852
|
-
|
852
|
+
|
853
853
|
def unparse(value_, style_, unparse_params_, required_for_later_)
|
854
854
|
str_ = nil
|
855
855
|
if !@default_value_optional || value_ != @default_value ||
|
@@ -880,20 +880,20 @@ module Versionomy
|
|
880
880
|
nil
|
881
881
|
end
|
882
882
|
end
|
883
|
-
|
883
|
+
|
884
884
|
end
|
885
|
-
|
886
|
-
|
885
|
+
|
886
|
+
|
887
887
|
# A recognizer for a numeric integer field
|
888
|
-
|
888
|
+
|
889
889
|
class BasicIntegerRecognizer < RecognizerBase #:nodoc:
|
890
|
-
|
890
|
+
|
891
891
|
def initialize(field_, opts_={})
|
892
892
|
@strip_leading_zeros = opts_[:strip_leading_zeros]
|
893
893
|
@width_unparse_param_key = "#{field_.name}_width".to_sym
|
894
894
|
setup(field_, '\d+', opts_)
|
895
895
|
end
|
896
|
-
|
896
|
+
|
897
897
|
def parsed_value(value_, parse_params_)
|
898
898
|
if !@strip_leading_zeros && value_ =~ /^0\d/
|
899
899
|
[value_.to_i, {@width_unparse_param_key => value_.length}]
|
@@ -901,7 +901,7 @@ module Versionomy
|
|
901
901
|
[value_.to_i, nil]
|
902
902
|
end
|
903
903
|
end
|
904
|
-
|
904
|
+
|
905
905
|
def unparsed_value(value_, style_, unparse_params_)
|
906
906
|
if !@strip_leading_zeros && (width_ = unparse_params_[@width_unparse_param_key])
|
907
907
|
"%0#{width_.to_i}d" % value_
|
@@ -909,15 +909,15 @@ module Versionomy
|
|
909
909
|
value_.to_s
|
910
910
|
end
|
911
911
|
end
|
912
|
-
|
912
|
+
|
913
913
|
end
|
914
|
-
|
915
|
-
|
914
|
+
|
915
|
+
|
916
916
|
# A recognizer for an alphabetic integer field. Such a field
|
917
917
|
# represents values 1-26 as letters of the English alphabet.
|
918
|
-
|
918
|
+
|
919
919
|
class AlphabeticIntegerRecognizer < RecognizerBase # :nodoc:
|
920
|
-
|
920
|
+
|
921
921
|
def initialize(field_, opts_={})
|
922
922
|
@case_unparse_param_key = "#{field_.name}_case".to_sym
|
923
923
|
@case = opts_[:case]
|
@@ -931,7 +931,7 @@ module Versionomy
|
|
931
931
|
end
|
932
932
|
setup(field_, value_regexp_, opts_)
|
933
933
|
end
|
934
|
-
|
934
|
+
|
935
935
|
def parsed_value(value_, parse_params_)
|
936
936
|
value_ = value_.unpack('c')[0] # Compatible with both 1.8 and 1.9
|
937
937
|
if value_ >= 97 && value_ <= 122
|
@@ -942,7 +942,7 @@ module Versionomy
|
|
942
942
|
[0, nil]
|
943
943
|
end
|
944
944
|
end
|
945
|
-
|
945
|
+
|
946
946
|
def unparsed_value(value_, style_, unparse_params_)
|
947
947
|
if value_ >= 1 && value_ <= 26
|
948
948
|
if unparse_params_[@case_unparse_param_key] == :upper
|
@@ -954,61 +954,61 @@ module Versionomy
|
|
954
954
|
value_.to_s
|
955
955
|
end
|
956
956
|
end
|
957
|
-
|
957
|
+
|
958
958
|
end
|
959
|
-
|
960
|
-
|
959
|
+
|
960
|
+
|
961
961
|
# A recognizer for strings that match a particular given regular
|
962
962
|
# expression, for use in string-valued fields.
|
963
|
-
|
963
|
+
|
964
964
|
class RegexpStringRecognizer < RecognizerBase # :nodoc:
|
965
|
-
|
965
|
+
|
966
966
|
def initialize(field_, regexp_='[a-zA-Z0-9]+', opts_={})
|
967
967
|
setup(field_, regexp_, opts_)
|
968
968
|
end
|
969
|
-
|
969
|
+
|
970
970
|
def parsed_value(value_, parse_params_)
|
971
971
|
[value_, nil]
|
972
972
|
end
|
973
|
-
|
973
|
+
|
974
974
|
def unparsed_value(value_, style_, unparse_params_)
|
975
975
|
value_.to_s
|
976
976
|
end
|
977
|
-
|
977
|
+
|
978
978
|
end
|
979
|
-
|
980
|
-
|
979
|
+
|
980
|
+
|
981
981
|
# A recognizer for symbolic fields that recognizes a single regular
|
982
982
|
# expression and maps it to a single particular value.
|
983
|
-
|
983
|
+
|
984
984
|
class RegexpSymbolRecognizer < RecognizerBase # :nodoc:
|
985
|
-
|
985
|
+
|
986
986
|
def initialize(field_, value_, regexp_, canonical_, opts_={})
|
987
987
|
setup(field_, regexp_, opts_)
|
988
988
|
@value = value_
|
989
989
|
@canonical = canonical_
|
990
990
|
end
|
991
|
-
|
991
|
+
|
992
992
|
def parsed_value(value_, parse_params_)
|
993
993
|
[@value, nil]
|
994
994
|
end
|
995
|
-
|
995
|
+
|
996
996
|
def unparsed_value(value_, style_, unparse_params_)
|
997
997
|
@canonical
|
998
998
|
end
|
999
|
-
|
999
|
+
|
1000
1000
|
def should_unparse?(value_, style_)
|
1001
1001
|
style_ == @style && value_ == @value
|
1002
1002
|
end
|
1003
|
-
|
1003
|
+
|
1004
1004
|
end
|
1005
|
-
|
1006
|
-
|
1005
|
+
|
1006
|
+
|
1007
1007
|
# A recognizer for symbolic fields that recognizes a mapping of values
|
1008
1008
|
# to regular expressions.
|
1009
|
-
|
1009
|
+
|
1010
1010
|
class MappingSymbolRecognizer < RecognizerBase # :nodoc:
|
1011
|
-
|
1011
|
+
|
1012
1012
|
def initialize(field_, opts_={}, &block_)
|
1013
1013
|
@mappings_in_order = []
|
1014
1014
|
@mappings_by_value = {}
|
@@ -1020,28 +1020,28 @@ module Versionomy
|
|
1020
1020
|
map_[0] = ::Regexp.new("\\A(#{map_[0]})", @regexp_options)
|
1021
1021
|
end
|
1022
1022
|
end
|
1023
|
-
|
1023
|
+
|
1024
1024
|
def parsed_value(value_, parse_params_)
|
1025
1025
|
@mappings_in_order.each do |map_|
|
1026
1026
|
return [map_[2], nil] if map_[0].match(value_)
|
1027
1027
|
end
|
1028
1028
|
nil
|
1029
1029
|
end
|
1030
|
-
|
1030
|
+
|
1031
1031
|
def unparsed_value(value_, style_, unparse_params_)
|
1032
1032
|
@mappings_by_value[value_][1]
|
1033
1033
|
end
|
1034
|
-
|
1034
|
+
|
1035
1035
|
def should_unparse?(value_, style_)
|
1036
1036
|
style_ == @style && @mappings_by_value.include?(value_)
|
1037
1037
|
end
|
1038
|
-
|
1038
|
+
|
1039
1039
|
end
|
1040
|
-
|
1041
|
-
|
1040
|
+
|
1041
|
+
|
1042
1042
|
end
|
1043
|
-
|
1044
|
-
|
1043
|
+
|
1044
|
+
|
1045
1045
|
end
|
1046
|
-
|
1046
|
+
|
1047
1047
|
end
|