versionomy 0.4.1 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|