The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Data::VString - Perl extension to handle v-strings (often used as version strings)

SYNOPSIS

  use Data::VString qw(parse_vstring format_vstring vstring_cmp vstring_satisfy);

  # going from '0.0.1' to "\x{0}\x{0}\x{1}" and back
  $i_vstring = parse_vstring($vstring);
  $vstring = format_vstring($i_vstring);

  print 'ok' if vstring_cmp($VERSION, '>=', '0.0.1');

  my $bool = vstring_satisfy($vstring, $predicate)

DESCRIPTION

Most of the time, the so-called version numbers are not really numbers, but tuples of integers like '0.2.3'. With this concept of version, '0.1' is the same as '0.01'. The ordering of such tuples is usually defined by comparing each part. And that makes

  '0.1' < '0.2' 
  '0.2.1' > '0.1.3'
  '0.11.10' > '0.10.10.10' 
  '10.0.0' > '9.9.9' # notice that '10.0.0' gt '9.9.9' is false

and also '0.1' < '0.1.0' (because the first one is shorter). There is also no need to define how many integers to accept in the tuple, with '0.0.1.2.34.4.580.20' being a nice version.

Perl had (and still has) this concept as v-strings. They had even deserved a syntax on their own: v1.20.300.4000 or 100.111.1111 (a literal with two or more dots). But their fate is sealed: in "Version Strings" in perldata of 5.8 we read:

  Note: Version Strings (v-strings) have been deprecated.  
  They will not be available after Perl 5.8.  The marginal 
  benefits of v-strings were greatly outweighed by the 
  potential for Surprise and Confusion.

This module revives them as a simple module implementation. Version strings are well suited in many version "numbering" schemes and straightforward (if you always remember they are not numbers). In Perl, most of the confusion lies in that 0.1 as a literal is a number and sorts like a number, while 0.1.0 is a v-string and sorts like a v-string. Also from "Version Strings" in perldata:

  A literal of the form "v1.20.300.4000" is parsed as a string composed
  of characters with the specified ordinals.  This form, known as
  v-strings, provides an alternative, more readable way to construct
  strings, rather than use the somewhat less readable interpolation form
  "\x{1}\x{14}\x{12c}\x{fa0}".  This is useful for representing Unicode
  strings, and for comparing version "numbers" using the string compari-
  son operators, "cmp", "gt", "lt" etc.  If there are two or more dots in
  the literal, the leading "v" may be omitted.

    print v9786;              # prints UTF-8 encoded SMILEY, "\x{263a}"
    print v102.111.111;       # prints "foo"
    print 102.111.111;        # same

This text reveals how this notion of version as tuple of integers can be represented efficiently if one agreeds that each part is limited to 16 bits (0-65565), which is more than enough for practical software versioning schemes. Converting each part to a Unicode character, the version string ends up like a Unicode string which can be compared with the usual string comparators.

Here, functions are provided for converting between v-strings (like '6.2.28') and their internal representation ("\x{6}\x{2}\x{1C}") and to test them against other v-strings.

parse_vstring
  $i_vstring = parse_vstring($vstring);

  parse_vstring('0.1.2') # return "\x{0}\x{1}\x{2}"

Converts a v-string into its internal representation (the string made up the Unicode characters given by the ordinals specified in v-string parts).

The syntax of a v-string can be defined by the following syntax rule (in P::RD style)

  <v-string>: /\d+/ ( /[._]/ /\d+/ )*

For the reverse operation, see format_vstring.

format_vstring
  $vstring = format_vstring($i_vstring)

Converts the internal representation of a v-string into a readable v-string. It does the reverse operation of parse_vstring.

vstring_satisfy
  vstring_satisfy($vstring, $predicate);

  vstring_satisfy('0.1.1', '0.1.1'); # true
  vstring_satisfy('0.1.1', '> 0, < 0.2, != 0.1.0'); # true
  vstring_satisfy('0.2.4', '0.2.5..0.3.4'); # false

Determines if a v-string satisfy a predicate. The predicate is a list of simple predicates, each one must be satisfied (that is, an and). Simple predicates takes one of three forms:

  '0.1.2'       - exact match 
  '>= 3.14.15'  - (relational operator) (v-string)
  '5.6 .. 10.8' - meaning '>= 5.6, <= 10.8'

A grammar for predicates in Parse::RecDescent-like syntax is:

  <p> : <p0> (',' <p>)*

  <p0>: <v-string>                  # the same as '==' <v-string>
      | <op> <v-string> 
      | <v-string> '..' <v-string>  # the same as ">= <v-string1>, <= <v-string2>"

  <op>: '==' | '!=' | '<=' | '>=' | '<' | '>'

Spaces are irrelevant in predicates.

vstring_cmp
  $ans = vstring_cmp($vs1, $op, $vs2)

  $eq = vstring_cmp('0.1.02', '==', '0.01.2'); # ok
  $le = vstring_cmp('1.2.3', '>=', '3.2.1'); # not ok

Makes a comparison between two v-strings. The supported operators are '==', '!=', '<=', '>=', '<', and '>'.

EXPORT

None by default. parse_vstring, format_vstring, vstring_cmp, and vstring_satisfy can be exported on demand.

SEE ALSO

"Version Strings" in perldata

version by John Peacock. That module is older and more famous. The main differences are:

  • version is OO, this module is a bunch of functions

  • version does not represents version as Unicode strings as we do (well, I think so after a quick glance of the code)

  • version is much more tolerant with numeric versions. This module is not concerned with backward compatibility. Use it versions as strings from the beginning, stay out of trouble with numeric versions.

  • version is also more tolerant with non-numeric versions. On the contrary, Data::VString is very strict about syntax.

  • we don't dare to redefine UNIVERSAL::VERSION.

  • v-strings are treated as data here and no attempt to force semantics as Perl module version was made. Indeed I started coding this module for handling JSAN distributions (which are data from the point of view of the Perl program).

This module is a companion for the JSAN module Data.VString. This one implements the Perl side while the other will implement the JavaScript side.

BUGS

There must be some. Because all trivial software must have at least one bug. This is the actual list of known bugs.

  • There is a bug with certain version parts which are illegal Unicode characters. So the full range (0..65535) is not actually usable.

Please report bugs via CPAN RT http://rt.cpan.org/NoAuth/Bugs.html?Dist=Data-VString.

AUTHOR

Adriano R. Ferreira, <ferreira@cpan.org>

COPYRIGHT AND LICENSE

Copyright (C) 2005, 2007 by Adriano R. Ferreira

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.