Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Documentation updates

  • Loading branch information...
commit 014f6c931cb116763e4184c909ac89f7b37aa427 1 parent 175d88d
@dazuma authored
View
93 README.rdoc
@@ -8,36 +8,42 @@ numbers in the wide variety of versioning schemes in use.
Let's be honest. Version numbers are not easy to deal with, and very
seldom seem to be done right.
-Imagine the common case of testing the ruby version. Most of us, if we
+Imagine the common case of testing the Ruby version. Most of us, if we
need to worry about Ruby VM compatibility, will do something like:
do_something if RUBY_VERSION >= "1.8.7"
-Treating the version number as a string is all well and good, until it
-isn't. The above code works for Ruby 1.8.6, 1.8.7, 1.8.8, and 1.9.1. But
-it will fail if the version is "1.8.10".
+Treating the version number as a string works well enough, until it
+doesn't. The above code will do the right thing for Ruby 1.8.6, 1.8.7,
+1.8.8, and 1.9.1. But it will fail if the version is "1.8.10".
There are a few version number classes out there that do better than
-treating version numbers as plain strings. Perhaps the most well known and
-often used is Gem::Version, part of rubygems. This class separates the
-version into fields and lets you manipulate and compare version numbers
-more robustly. It provides limited support for "prerelease" versions
-through using string-valued fields. However, it's still a little clumsy.
-A prerelease version has to be represented like this: "1.9.2.b.1" or
-"1.9.2.preview.2". Wouldn't it be nice to be able to parse more typical
-version number formats such as "1.9.2b1" and "1.9.2 preview-2"?
-
-Yes you can!
+treating version numbers as plain strings. One well-known class is
+Gem::Version, part of rubygems. This class separates the version into
+fields and lets you manipulate and compare version numbers more robustly.
+It provides limited support for "prerelease" versions through using
+string-valued fields as a bit of a hack. However, it's still a little
+clumsy. A prerelease version has to be represented like this: "1.9.2.b.1"
+or "1.9.2.preview.2". Wouldn't it be nice to be able to parse more typical
+version number formats such as "1.9.2b1" and "1.9.2 preview-2"? Wouldn't
+it be nice for a version like "1.9.2b1" to _understand_ that it's a "beta"
+version and behave accordingly?
+
+With Versionomy, you can!
=== Some examples
require 'versionomy'
- v1 = Versionomy.parse('1.3.2')
+ # Create version numbers that understand their own semantics
+ v1 = Versionomy.create(:major => 1, :minor => 3, :tiny => 2)
v1.major # => 1
v1.minor # => 3
v1.tiny # => 2
+ v1.release_type # => :final
+ v1.patchlevel # => 0
+ # Parse version numbers, including common prerelease syntax
v2 = Versionomy.parse('1.4a3')
v2.major # => 1
v2.minor # => 4
@@ -45,7 +51,9 @@ Yes you can!
v2.release_type # => :alpha
v2.alpha_version # => 3
v2 > v1 # => true
+ v2.to_s # => '1.4a3'
+ # Another parsing example.
v3 = Versionomy.parse('1.4.0b2')
v3.major # => 1
v3.minor # => 4
@@ -56,29 +64,44 @@ Yes you can!
v3 > v2 # => true
v3.to_s # => '1.4.0b2'
- v4 = v3.bump(:beta_version)
+ # You can bump any field
+ v4 = Versionomy.parse('1.4.0b2').bump(:beta_version)
v4.to_s # => '1.4.0b3'
+ v5 = v4.bump(:tiny)
+ v5.to_s # => '1.4.1'
- v5 = v4.bump(:release_type)
- v5.to_s # => '1.4.0rc1'
-
- v6 = v5.bump(:release_type)
- v6.to_s # => '1.4.0'
-
- v7 = v3.bump(:tiny)
- v7.to_s # => '1.4.1'
+ # Bumping the release type works as you would expect
+ v6 = Versionomy.parse('1.4.0b2').bump(:release_type)
+ v6.release_type # => :release_candidate
+ v6.to_s # => '1.4.0rc1'
+ v7 = v6.bump(:release_type)
+ v7.release_type # => :final
+ v7.to_s # => '1.4.0'
- v8 = v3.bump(:major)
+ # If a version has trailing zeros, it remembers how many fields to
+ # unparse; however, you can also change this.
+ v8 = Versionomy.parse('1.4.0b2').bump(:major)
v8.to_s # => '2.0.0'
v8.unparse(:optional_fields => [:tiny]) # => '2.0'
+ v8.unparse(:required_fields => [:tiny2]) # => '2.0.0.0'
+ # Comparisons are semantic, so will behave as expected even if the
+ # formatting is set up differently.
v9 = Versionomy.parse('2.0.0.0')
v9.to_s # => '2.0.0.0'
- v9 == v8 # => true
+ v9 == Versionomy.parse('2') # => true
- v10 = v8.bump(:patchlevel)
+ # Patchlevels are supported when the release type is :final
+ v10 = Versionomy.parse('2.0.0').bump(:patchlevel)
+ v10.patchlevel # => 1
v10.to_s # => '2.0.0-1'
+ v11 = Versionomy.parse('2.0p1')
+ v11.patchlevel # => 1
+ v11.to_s # => '2.0p1'
+ v11 == v10 # => true
+ # You can create your own format from scratch or by modifying an
+ # existing format
microsoft_format = Versionomy.default_format.modified_copy do
field(:minor) do
recognize_number(:default_value_optional => true,
@@ -86,12 +109,12 @@ Yes you can!
:default_delimiter => ' SP')
end
end
- v11 = microsoft_format.parse('2008 SP2')
- v11.major # => 2008
- v11.minor # => 2
- v11.tiny # => 0
- v11.to_s # => '2008 SP2'
- v11 == Versionomy.parse('2008.2') # => true
+ v12 = microsoft_format.parse('2008 SP2')
+ v12.major # => 2008
+ v12.minor # => 2
+ v12.tiny # => 0
+ v12.to_s # => '2008 SP2'
+ v12 == Versionomy.parse('2008.2') # => true
=== Feature list
@@ -107,7 +130,9 @@ custom formats.
Finally, Versionomy also lets you to create alternate versioning "schemas".
You can define any number of version number fields, and provide your own
-semantics for comparing, parsing, and modifying version numbers.
+semantics for comparing, parsing, and modifying version numbers. You can
+provide conversions from one schema to another. As an example, Versionomy
+provides a schema and formatter/parser matching Gem::Version.
=== Requirements
View
4 lib/versionomy/format/rubygems.rb
@@ -43,7 +43,9 @@ module Format
# This is identical to calling <tt>get('rubygems')</tt>.
#
# The rubygems format is designed to be parse-compatible with the
- # Gem::Version class used in rubygems.
+ # Gem::Version class used in rubygems. The only caveat is, whereas
+ # Gem::Version handles an arbitrary number of fields, this format is
+ # limited to a maximum of 8.
#
# For the exact annotated definition of the rubygems schema and format,
# see the source code for Versionomy::Format::Rubygems#create.
View
15 lib/versionomy/schema.rb
@@ -43,17 +43,20 @@ module Versionomy
# The schema controls what fields are present in the version, how
# version numbers are compared, what the default values are, and how
# values can change. Version numbers with the same schema can be
- # compared with one another, and version numbers can be converted to
- # formats that share the same schema.
+ # compared with one another, and version numbers can be converted
+ # trivially to formats that share the same schema, without requiring a
+ # Conversion implementation.
#
# At its simplest, a version number is defined as a sequence of fields,
# each with a name and data type. These fields may be integer-valued,
# string-valued, or symbolic, though most will probably be integers.
- # Symbolic fields are useful, for example, if you want a field to specify
- # the type of prerelease (e.g. "alpha", "beta", or "release candidate").
+ # Symbolic fields are enumerated types that are useful, for example, if
+ # you want a field to specify the type of prerelease (e.g. "alpha",
+ # "beta", or "release candidate").
#
- # As a simple example, you could construct a schema for versions numbers
- # of the form "major.minor.tiny" like this:
+ # As a simple conceptual example, you could construct a schema for
+ # version numbers of the form "major.minor.tiny" like this. (This is a
+ # conceptual diagram, not actual syntax.)
#
# ("major": integer), ("minor": integer), ("tiny": integer)
#
View
7 lib/versionomy/schema/wrapper.rb
@@ -90,7 +90,7 @@ def to_s # :nodoc:
# Returns true if this schema is equivalent to the other schema.
# Two schemas are equivalent if their root fields are the same--
# which means that the entire field tree is the same-- and they
- # include the same modules.
+ # include the same value modules.
# Note that this is different from the definition of <tt>==</tt>.
def eql?(obj_)
@@ -100,8 +100,9 @@ def eql?(obj_)
# Returns true if this schema is compatible with the other schema.
- # Two schemas are equivalent if their root fields are the same--
- # which means that the entire field tree is the same.
+ # Two schemas are compatible if their root fields are the same--
+ # which means that the entire field tree is the same. They may,
+ # however, include different value modules.
# Note that this is different from the definition of <tt>eql?</tt>.
def ==(obj_)
View
63 lib/versionomy/value.rb
@@ -153,6 +153,8 @@ def marshal_load(data_) # :nodoc:
yaml_as "tag:danielazuma.com,2009:version"
+ # Deserialize a version number from YAML
+
def self.yaml_new(klass_, tag_, data_) # :nodoc:
unless data_.kind_of?(::Hash)
raise ::YAML::TypeError, "Invalid version format: #{val_.inspect}"
@@ -167,7 +169,9 @@ def self.yaml_new(klass_, tag_, data_) # :nodoc:
end
- def to_yaml(opts_={}) # :nodoc:
+ # Serialize this version number to YAML format.
+
+ def to_yaml(opts_={})
data_ = marshal_dump
::YAML::quick_emit(nil, opts_) do |out_|
out_.map(taguri, to_yaml_style) do |map_|
@@ -184,7 +188,7 @@ def to_yaml(opts_={}) # :nodoc:
end
- # Unparse this version number.
+ # Unparse this version number and return a string.
#
# Raises Versionomy::Errors::UnparseError if unparsing failed.
@@ -193,14 +197,16 @@ def unparse(params_=nil)
end
- # Return the schema defining the form of this version number
+ # Return the schema defining the structure and semantics of this
+ # version number.
def schema
@format.schema
end
- # Return the format defining the form of this version number
+ # Return the format defining the schema and formatting/parsing of
+ # this version number.
def format
@format
@@ -235,6 +241,8 @@ def each_field_object # :nodoc:
# Returns an array of recognized field names for this value, in field order.
+ # This is the order of the fields actually present in this value, in
+ # order from most to least significant.
def field_names
@field_path.map{ |field_| field_.name }
@@ -270,6 +278,8 @@ def [](field_)
# Returns the value as an array of field values, in field order.
+ # This is the order of the fields actually present in this value, in
+ # order from most to least significant.
def values_array
@field_path.map{ |field_| @values[field_.name] }
@@ -285,15 +295,15 @@ def values_hash
# Returns a new version number created by bumping the given field. The
# field may be specified as a field object, field name, or field index.
- # Returns self if value could not be changed.
- # Returns nil if the field was not recognized.
+ # Returns self unchanged if the field was not recognized or could not
+ # be modified.
def bump(name_)
name_ = @field_path[name_] if name_.kind_of?(::Integer)
name_ = name_.name if name_.kind_of?(Schema::Field)
- return nil unless name_
+ return self unless name_
name_ = name_.to_sym
- return nil unless @values.include?(name_)
+ return self unless @values.include?(name_)
values_ = []
@field_path.each do |field_|
oldval_ = @values[field_.name]
@@ -310,7 +320,17 @@ def bump(name_)
end
- # Returns a new version number created by changing the given field values.
+ # Returns a new version number created by cloning this version number
+ # and changing the given field values.
+ #
+ # You should pass in a hash of field names to values. These are the
+ # fields to modify; any other fields will be left alone, unless they
+ # are implicitly changed by the modifications you are making.
+ # For example, changing the :release_type on a value using the standard
+ # format, may change which fields are present in the resulting value.
+ #
+ # You may also pass a delta hash to modify the unparse params stored in
+ # the value.
def change(values_={}, unparse_params_={})
unparse_params_ = @unparse_params.merge(unparse_params_) if @unparse_params
@@ -318,7 +338,8 @@ def change(values_={}, unparse_params_={})
end
- # Returns this value converted to the given format.
+ # Attempts to convert this value to the given format, and returns the
+ # resulting value.
#
# Raises Versionomy::Errors::ConversionError if the value could not
# be converted.
@@ -343,8 +364,9 @@ def hash # :nodoc:
end
- # Returns true if this version number is equal to the given verison number.
- # This type of equality means the schemas and values are the same.
+ # Returns true if this version number is equivalent to the given number.
+ # This type of equality means their schemas are compatible and their
+ # field values are equal.
# Note that this is different from the definition of <tt>==</tt>.
def eql?(obj_)
@@ -361,9 +383,10 @@ def eql?(obj_)
end
- # Returns true if this version number is equal to the given verison number.
- # This type of equality means that the values are the same, possibly after
- # suitable automatic conversion of the RHS.
+ # Returns true if this version number is value-equal to the given number.
+ # This type of equality means that they are equivalent, or that it is
+ # possible to convert the RHS to the LHS's format, and that they would
+ # be equivalent after such a conversion has taken place.
# Note that this is different from the definition of <tt>eql?</tt>.
def ==(obj_)
@@ -371,7 +394,11 @@ def ==(obj_)
end
- # Compare this version number with the given version number.
+ # Compare this version number with the given version number,
+ # returning 0 if the two are value-equal, a negative number if the RHS
+ # is greater, or a positive number if the LHS is greater.
+ # The comparison may succeed even if the two have different schemas,
+ # if the RHS can be converted to the LHS's format.
def <=>(obj_)
if obj_.kind_of?(::String)
@@ -394,6 +421,8 @@ def <=>(obj_)
# Compare this version number with the given version number.
+ # The comparison may succeed even if the two have different schemas,
+ # if the RHS can be converted to the LHS's format.
def <(obj_)
val_ = (self <=> obj_)
@@ -405,6 +434,8 @@ def <(obj_)
# Compare this version number with the given version number.
+ # The comparison may succeed even if the two have different schemas,
+ # if the RHS can be converted to the LHS's format.
def >(obj_)
val_ = (self <=> obj_)
View
2  tests/tc_readme_examples.rb
@@ -68,7 +68,7 @@ def test_readme_file
# a buffer to run all at once, because it might be code that
# gets spread over multiple lines.
delim_index_ = line_.index(' # ')
- unless delim_index_
+ if !delim_index_ || line_[0, delim_index_].strip.length == 0
buffer_start_line_ ||= io_.lineno
buffer_ << line_
next
Please sign in to comment.
Something went wrong with that request. Please try again.