Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Initial changes for 0.3.0 alpha release

  • Loading branch information...
commit 57c5ebe3c514b942687fc15aff0b8ea59027c417 1 parent 4c3f102
@dazuma authored
View
9 History.rdoc
@@ -1,3 +1,12 @@
+=== 0.3.0 / 2009-12-??
+
+* Alpha release, opened for public feedback
+* Autoloading of format definitions using a load path.
+* Format and conversion registry/lookup is now thread-safe.
+* Implemented resetting a particular field in the value.
+* Implemented aliases for field names.
+* Documentation updates
+
=== 0.2.5 / 2009-11-24
* Preserve minimum width of a field, if the field has leading zeros. For example, "2.01".
View
3  lib/versionomy.rb
@@ -47,13 +47,10 @@
'format',
'format/base',
'format/delimiter',
- 'format/standard',
- 'format/rubygems',
'value',
'conversion',
'conversion/base',
'conversion/parsing',
- 'conversion/rubygems',
'interface',
'version',
]
View
21 lib/versionomy/conversion.rb
@@ -34,6 +34,9 @@
;
+require 'thread'
+
+
module Versionomy
@@ -60,7 +63,8 @@ module Versionomy
module Conversion
- @registry = ::Hash.new
+ @registry = {}
+ @mutex = ::Mutex.new
class << self
@@ -95,7 +99,7 @@ def convert(value_, format_, convert_params_=nil)
def get(from_schema_, to_schema_, strict_=false)
key_ = _get_key(from_schema_, to_schema_)
- conversion_ = @registry[key_]
+ conversion_ = @mutex.synchronize{ @registry[key_] }
if strict_ && conversion_.nil?
raise Errors::UnknownConversionError
end
@@ -114,12 +118,17 @@ def get(from_schema_, to_schema_, strict_=false)
# Raises Versionomy::Errors::UnknownFormatError if a format was
# specified by name but the name is not known.
- def register(from_schema_, to_schema_, conversion_)
+ def register(from_schema_, to_schema_, conversion_, silent_=false)
key_ = _get_key(from_schema_, to_schema_)
- if @registry.include?(key_)
- raise Errors::ConversionRedefinedError
+ @mutex.synchronize do
+ if @registry.include?(key_)
+ unless silent_
+ raise Errors::ConversionRedefinedError
+ end
+ else
+ @registry[key_] = conversion_
+ end
end
- @registry[key_] = conversion_
end
View
146 lib/versionomy/conversion/rubygems.rb
@@ -1,146 +0,0 @@
-# -----------------------------------------------------------------------------
-#
-# Versionomy standard format implementation
-#
-# -----------------------------------------------------------------------------
-# Copyright 2008-2009 Daniel Azuma
-#
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions are met:
-#
-# * Redistributions of source code must retain the above copyright notice,
-# this list of conditions and the following disclaimer.
-# * Redistributions in binary form must reproduce the above copyright notice,
-# this list of conditions and the following disclaimer in the documentation
-# and/or other materials provided with the distribution.
-# * Neither the name of the copyright holder, nor the names of any other
-# contributors to this software, may be used to endorse or promote products
-# derived from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-# -----------------------------------------------------------------------------
-;
-
-
-module Versionomy
-
- module Conversion
-
-
- # This is a namespace for the implementation of the conversion between
- # the rubygems and standard formats.
-
- module Rubygems
-
-
- # Create the conversion from standard to rubygems format.
- # This method is called internally when Versionomy initializes itself,
- # and you should not need to call it again. It is documented, however,
- # so that you can inspect its source code from RDoc, since the source
- # contains useful examples of how to use the conversion DSLs.
-
- def self.create_standard_to_rubygems
-
- # We'll use a parsing conversion.
- Conversion::Parsing.new do
-
- # We're going to modify how the standard format version is
- # unparsed, so the rubygems format will have a better chance
- # of parsing it.
- to_modify_unparse_params do |params_, convert_params_|
-
- params_ ||= {}
-
- # If the standard format version has a prerelease notation,
- # make sure it is set off using a delimiter that the rubygems
- # format can recognize. So instead of "1.0b2", we force the
- # unparsing to generate "1.0.b.2".
- params_[:release_type_delim] = '.'
- params_[:development_version_delim] = '.'
- params_[:alpha_version_delim] = '.'
- params_[:beta_version_delim] = '.'
- params_[:release_candidate_version_delim] = '.'
- params_[:preview_version_delim] = '.'
-
- # If the standard format version has a patchlevel notation,
- # force it to use the default number rather than letter style.
- # So instead of "1.2c", we force the unparsing to generate
- # "1.2-3".
- params_[:patchlevel_style] = nil
-
- # If the standard format version has a patchlevel notation,
- # force it to use the default delimiter of "-" so the rubygems
- # format will recognize it. So instead of "1.9.1p243", we force
- # the unparsing to generate "1.9.1-243".
- params_[:patchlevel_delim] = nil
-
- # If the standard format version includes a "v" prefix, strip
- # it because rubygems doesn't like it.
- params_[:major_delim] = nil
-
- params_
- end
-
- # Standard formats sometimes allow hyphens and spaces in field
- # delimiters, but the rubygems format requires periods. So modify
- # the unparsed string to conform to rubygems's expectations.
- to_modify_string do |str_, convert_params_|
- str_.gsub(/[\.\s-]+/, '.')
- end
-
- end
-
- end
-
-
- # Create the conversion from rubygems to standard format.
- # This method is called internally when Versionomy initializes itself,
- # and you should not need to call it again. It is documented, however,
- # so that you can inspect its source code from RDoc, since the source
- # contains useful examples of how to use the conversion DSLs.
-
- def self.create_rubygems_to_standard
-
- # We'll use a parsing conversion.
- Conversion::Parsing.new do
-
- # Handle the case where the rubygems version ends with a string
- # field, e.g. "1.0.b". We want to treat this like "1.0b0" rather
- # than "1.0-2" since the rubygems semantic states that this is a
- # prerelease version. So we add 0 to the end of the parsed string
- # if it ends in a letter.
- to_modify_string do |str_, convert_params_|
- str_.gsub(/([[:alpha:]])\z/, '\10')
- end
-
- end
-
- end
-
-
- unless Conversion.get(:standard, :rubygems)
- Conversion.register(:standard, :rubygems, create_standard_to_rubygems)
- end
- unless Conversion.get(:rubygems, :standard)
- Conversion.register(:rubygems, :standard, create_rubygems_to_standard)
- end
-
-
- end
-
-
- end
-
-end
View
130 lib/versionomy/format.rb
@@ -34,6 +34,10 @@
;
+require 'thread'
+require 'monitor'
+
+
module Versionomy
@@ -57,28 +61,96 @@ module Versionomy
# Versionomy::Format::Delimiter tool, which can be used to construct
# parsers for many version number formats.
#
+ # === Format registry
+ #
# Formats may be registered with Versionomy and given a name using the
# methods of this module. This allows version numbers to be serialized
- # with their format.
+ # with their format. When a version number is serialized, its format
+ # name is written to the stream, along with the version number's string
+ # representation. When the version number is reconstructed, its format
+ # is looked up by name so versionomy can determine how to parse the
+ # string.
+ #
+ # Format names are strings that may include letters, numerals, dashes,
+ # underscores, and periods. By convention, periods are used as namespace
+ # delimiters. Format names without a namespace (that is, with no periods)
+ # are considered reserved for standard versionomy formats. If you define
+ # your own format, you should use a name that includes a namespace (e.g.
+ # "mycompany.LibraryVersion") to reduce the chance of name collisions.
#
- # Finally, this module serves as a namespace for format implementations.
+ # You may register formats directly using the register method, or set it
+ # up to be autoloaded on demand. When a format is requested, if it has
+ # not been registered explicitly, Versionomy looks for a format definition
+ # file for that format. Such a file has the name of the format, with the
+ # ".rb" extension for ruby (e.g. "mycompany.LibraryVersion.rb") and must
+ # be located in a directory in versionomy's format lookup path. By
+ # default, the directory containing versionomy's predefined formats
+ # (such as "standard") is in this path. However, you may add your own
+ # directories using the add_directory method. This lets you autoload your
+ # own formats. A format definition file itself must contain ruby code
+ # that defines the format and registers it using the correct name. See
+ # the files in the "lib/versionomy/format_definitions/" directory for
+ # examples.
module Format
- @names_to_formats = ::Hash.new
- @formats_to_names = ::Hash.new
+ @mutex = ::Mutex.new
+ @load_mutex = ::Monitor.new
+ @directories = [::File.expand_path(::File.dirname(__FILE__)+'/format_definitions')]
+ @names_to_formats = {}
+ @formats_to_names = {}
class << self
+ # Add a directory to the format path.
+ #
+ # The format path is an array of directory paths. These directories
+ # are searched for format definitions if a format name that has not
+ # been registered is requested.
+ #
+ # If high_priority_ is set to true, the directory is added to the
+ # front of the lookup path; otherwise it is added to the back.
+
+ def add_directory(path_, high_priority_=false)
+ path_ = ::File.expand_path(path_)
+ @mutex.synchronize do
+ unless @directories.include?(path_)
+ if high_priority_
+ @directories.unshift(path_)
+ else
+ @directories.push(path_)
+ end
+ end
+ end
+ end
+
+
# Get the format with the given name.
#
- # If the given name has not been defined, and strict is set to true,
- # raises Versionomy::Errors::UnknownFormatError. If strict is set to
- # false, returns nil if the given name has not been defined.
+ # If the given name has not been defined, attempts to autoload it from
+ # a format definition file. See the description of the Format module
+ # for details on this procedure.
+ #
+ # If the given name still cannot be resolved, and strict is set to
+ # true, raises Versionomy::Errors::UnknownFormatError. If strict is
+ # set to false, returns nil if the given name cannot be resolved.
def get(name_, strict_=false)
- format_ = @names_to_formats[name_.to_s]
+ name_ = _check_name(name_)
+ format_ = @mutex.synchronize{ @names_to_formats[name_] }
+ if format_.nil?
+ # Attempt to find the format in the directory path
+ dirs_ = @mutex.synchronize{ @directories.dup }
+ dirs_.each do |dir_|
+ path_ = "#{dir_}/#{name_}.rb"
+ if ::File.readable?(path_)
+ @load_mutex.synchronize{ ::Kernel.load(path_) }
+ end
+ format_ = @mutex.synchronize{ @names_to_formats[name_] }
+ break unless format_.nil?
+ end
+ end
if format_.nil? && strict_
raise Errors::UnknownFormatError, name_
end
@@ -86,6 +158,15 @@ def get(name_, strict_=false)
end
+ # Determines whether a format with the given name has been registered
+ # explicitly. Does not attempt to autoload the format.
+
+ def registered?(name_)
+ name_ = _check_name(name_)
+ @mutex.synchronize{ @names_to_formats.include?(name_) }
+ end
+
+
# Register the given format under the given name.
#
# Valid names may contain only letters, digits, underscores, dashes,
@@ -94,16 +175,18 @@ def get(name_, strict_=false)
# Raises Versionomy::Errors::FormatRedefinedError if the name has
# already been defined.
- def register(name_, format_)
- name_ = name_.to_s
- unless name_ =~ /\A[\w.-]+\z/
- raise ::ArgumentError, "Illegal name: #{name_.inspect}"
- end
- if @names_to_formats.include?(name_)
- raise Errors::FormatRedefinedError, name_
+ def register(name_, format_, silent_=false)
+ name_ = _check_name(name_)
+ @mutex.synchronize do
+ if @names_to_formats.include?(name_)
+ unless silent_
+ raise Errors::FormatRedefinedError, name_
+ end
+ else
+ @names_to_formats[name_] = format_
+ @formats_to_names[format_.object_id] = name_
+ end
end
- @names_to_formats[name_] = format_
- @formats_to_names[format_.object_id] = name_
end
@@ -115,7 +198,7 @@ def register(name_, format_)
# false, returns nil if the given format was never registered.
def canonical_name_for(format_, strict_=false)
- name_ = @formats_to_names[format_.object_id]
+ name_ = @mutex.synchronize{ @formats_to_names[format_.object_id] }
if name_.nil? && strict_
raise Errors::UnknownFormatError
end
@@ -123,6 +206,17 @@ def canonical_name_for(format_, strict_=false)
end
+ private
+
+ def _check_name(name_) # :nodoc:
+ name_ = name_.to_s
+ unless name_ =~ /\A[\w.-]+\z/
+ raise ::ArgumentError, "Illegal name: #{name_.inspect}"
+ end
+ name_
+ end
+
+
end
end
View
113 lib/versionomy/format/rubygems.rb → ...versionomy/format_definitions/rubygems.rb
@@ -128,7 +128,7 @@ def self.create
to_compare_type(:string) do |a_, b_|
if a_.kind_of?(::Integer)
if b_.kind_of?(::Integer)
- a_ - b_
+ a_ <=> b_
else
1
end
@@ -174,6 +174,10 @@ def self.create
end
end
+ # Some field aliases providing alternate names for major fields
+ alias_field(:major, :field0)
+ alias_field(:minor, :field1)
+
# Add the methods in this module to each value
add_module(Format::Rubygems::ExtraMethods)
end
@@ -226,9 +230,114 @@ def self.create
end
- register('rubygems', Format::Rubygems.create) unless get('rubygems')
+ register('rubygems', Format::Rubygems.create, true)
end
+
+ module Conversion
+
+
+ # This is a namespace for the implementation of the conversion between
+ # the rubygems and standard formats.
+
+ module Rubygems
+
+
+ # Create the conversion from standard to rubygems format.
+ # This method is called internally when Versionomy initializes itself,
+ # and you should not need to call it again. It is documented, however,
+ # so that you can inspect its source code from RDoc, since the source
+ # contains useful examples of how to use the conversion DSLs.
+
+ def self.create_standard_to_rubygems
+
+ # We'll use a parsing conversion.
+ Conversion::Parsing.new do
+
+ # We're going to modify how the standard format version is
+ # unparsed, so the rubygems format will have a better chance
+ # of parsing it.
+ to_modify_unparse_params do |params_, convert_params_|
+
+ params_ ||= {}
+
+ # If the standard format version has a prerelease notation,
+ # make sure it is set off using a delimiter that the rubygems
+ # format can recognize. So instead of "1.0b2", we force the
+ # unparsing to generate "1.0.b.2".
+ params_[:release_type_delim] = '.'
+ params_[:development_version_delim] = '.'
+ params_[:alpha_version_delim] = '.'
+ params_[:beta_version_delim] = '.'
+ params_[:release_candidate_version_delim] = '.'
+ params_[:preview_version_delim] = '.'
+
+ # If the standard format version has a patchlevel notation,
+ # force it to use the default number rather than letter style.
+ # So instead of "1.2c", we force the unparsing to generate
+ # "1.2-3".
+ params_[:patchlevel_style] = nil
+
+ # If the standard format version has a patchlevel notation,
+ # force it to use the default delimiter of "-" so the rubygems
+ # format will recognize it. So instead of "1.9.1p243", we force
+ # the unparsing to generate "1.9.1-243".
+ params_[:patchlevel_delim] = nil
+
+ # If the standard format version includes a "v" prefix, strip
+ # it because rubygems doesn't like it.
+ params_[:major_delim] = nil
+
+ params_
+ end
+
+ # Standard formats sometimes allow hyphens and spaces in field
+ # delimiters, but the rubygems format requires periods. So modify
+ # the unparsed string to conform to rubygems's expectations.
+ to_modify_string do |str_, convert_params_|
+ str_.gsub(/[\.\s-]+/, '.')
+ end
+
+ end
+
+ end
+
+
+ # Create the conversion from rubygems to standard format.
+ # This method is called internally when Versionomy initializes itself,
+ # and you should not need to call it again. It is documented, however,
+ # so that you can inspect its source code from RDoc, since the source
+ # contains useful examples of how to use the conversion DSLs.
+
+ def self.create_rubygems_to_standard
+
+ # We'll use a parsing conversion.
+ Conversion::Parsing.new do
+
+ # Handle the case where the rubygems version ends with a string
+ # field, e.g. "1.0.b". We want to treat this like "1.0b0" rather
+ # than "1.0-2" since the rubygems semantic states that this is a
+ # prerelease version. So we add 0 to the end of the parsed string
+ # if it ends in a letter.
+ to_modify_string do |str_, convert_params_|
+ str_.gsub(/([[:alpha:]])\z/, '\10')
+ end
+
+ end
+
+ end
+
+
+ end
+
+
+ register(:standard, :rubygems, Conversion::Rubygems.create_standard_to_rubygems, true)
+ register(:rubygems, :standard, Conversion::Rubygems.create_rubygems_to_standard, true)
+
+
+ end
+
+
end
View
2  lib/versionomy/format/standard.rb → ...versionomy/format_definitions/standard.rb
@@ -390,7 +390,7 @@ def self.create
end
- register('standard', Format::Standard.create) unless get('standard')
+ register('standard', Format::Standard.create, true)
end
View
10 lib/versionomy/interface.rb
@@ -158,14 +158,14 @@ def version_of(mod_)
# constants RUBY_VERSION and RUBY_PATCHLEVEL.
def ruby_version
- unless @ruby_version
- @ruby_version = parse(::RUBY_VERSION, :standard)
- if @ruby_version.release_type == :final
- @ruby_version = @ruby_version.change({:patchlevel => ::RUBY_PATCHLEVEL},
+ @ruby_version ||= begin
+ version_ = parse(::RUBY_VERSION, :standard)
+ if version_.release_type == :final
+ version_ = version_.change({:patchlevel => ::RUBY_PATCHLEVEL},
:patchlevel_required => true, :patchlevel_delim => '-p')
end
+ version_
end
- @ruby_version
end
View
86 lib/versionomy/schema/wrapper.rb
@@ -55,10 +55,11 @@ def self.create(field_=nil, opts_={}, &block_)
::Blockenspiel.invoke(block_, builder_)
field_ = builder_._get_field
modules_ = builder_._get_modules
+ aliases_ = builder_._get_aliases
else
modules_ = opts_[:modules] || []
end
- Schema::Wrapper.new(field_, modules_)
+ Schema::Wrapper.new(field_, modules_, aliases_)
end
@@ -71,10 +72,18 @@ class Wrapper
# This is a low-level method. Usually you should call
# Versionomy::Schema#create instead.
- def initialize(field_, modules_=[])
+ def initialize(field_, modules_=[], aliases_={})
@root_field = field_
@names = @root_field._descendants_by_name
@modules = modules_
+ @aliases = {}
+ aliases_.each do |k_,v_|
+ k_ = k_.to_sym
+ v_ = v_.to_sym
+ if @names.include?(v_) && !@names.include?(k_)
+ @aliases[k_] = v_
+ end
+ end
end
@@ -95,7 +104,7 @@ def to_s # :nodoc:
def eql?(obj_)
return false unless obj_.kind_of?(Schema::Wrapper)
- return @root_field == obj_.root_field && @modules == obj_.modules
+ return @root_field == obj_.root_field && @modules == obj_.modules && @aliases == obj_.aliases
end
@@ -134,16 +143,29 @@ def root_field
end
+ # Return the canonical field name given a name, or nil if the name
+ # is not recognized.
+
+ def canonical_name(name_)
+ name_ = name_.to_sym
+ name_ = @aliases[name_] || name_
+ @names.include?(name_) ? name_ : nil
+ end
+
+
# Return the field with the given name, or nil if the given name
- # is not found in this schema.
+ # is not found in this schema. If include_aliases_ is set to true,
+ # this also supports lookup by alias.
- def field_named(name_)
- @names[name_.to_sym]
+ def field_named(name_, include_aliases_=false)
+ name_ = name_.to_sym
+ name_ = @aliases[name_] || name_ if include_aliases_
+ field_ = @names[name_]
end
# Returns an array of names present in this schema, in no particular
- # order.
+ # order. Does not include aliases.
def names
@names.keys
@@ -158,6 +180,13 @@ def modules
end
+ # Returns a hash of field name aliases.
+
+ def aliases
+ @aliases.dup
+ end
+
+
end
@@ -171,6 +200,7 @@ class Builder
def initialize() # :nodoc:
@field = nil
@modules = []
+ @aliases = {}
@defaults = { :integer => {}, :string => {}, :symbol => {} }
end
@@ -204,28 +234,64 @@ def field(name_, opts_={}, &block_)
end
- # Add a module to values that use this schema.
+ # Create a field alias.
+
+ def alias_field(alias_name_, field_name_)
+ @aliases[alias_name_.to_sym] = field_name_.to_sym
+ end
+
+
+ # Add a module to the schema. All values that use this schema will
+ # include this module. This provides a way to add schema-specific
+ # capabilities to version numbers.
def add_module(mod_)
@modules << mod_
end
+ # Provide a default bump procedure for the given type.
+ # The type should be <tt>:integer</tt>, <tt>:string</tt>, or
+ # <tt>:symbol</tt>. You must provide a block that takes a field value
+ # and returns the "bumped" value. This procedure will be used for
+ # all fields of this type, unless explicitly overridden by the field.
+
def to_bump_type(type_, &block_)
@defaults[type_][:bump] = block_
end
+ # Provide a default compare procedure for the given type.
+ # The type should be <tt>:integer</tt>, <tt>:string</tt>, or
+ # <tt>:symbol</tt>. You must provide a block that takes two values
+ # and returns a standard comparison result-- that is, a negative
+ # integer if the first value is less, 0 if the values are equal, or a
+ # positive integer if the first value is greater. This procedure will
+ # be used for all fields of this type, unless explicitly overridden
+ # by the field.
+
def to_compare_type(type_, &block_)
@defaults[type_][:compare] = block_
end
+ # Provide a default canonicalization procedure for the given type.
+ # The type should be <tt>:integer</tt>, <tt>:string</tt>, or
+ # <tt>:symbol</tt>. You must provide a block that takes a field value
+ # and returns the canonical value. This procedure will be used for
+ # all fields of this type, unless explicitly overridden by the field.
+
def to_canonicalize_type(type_, &block_)
@defaults[type_][:canonicalize] = block_
end
+ # Provide a default value for the given type.
+ # The type should be <tt>:integer</tt>, <tt>:string</tt>, or
+ # <tt>:symbol</tt>. You must provide a default value that will be
+ # used for all fields of this type, unless explicitly overridden by
+ # the field.
+
def default_value_for_type(type_, value_)
@defaults[type_][:value] = value_
end
@@ -239,6 +305,10 @@ def _get_modules # :nodoc:
@modules
end
+ def _get_aliases # :nodoc:
+ @aliases
+ end
+
def _get_default_setting(type_, setting_) # :nodoc:
@defaults[type_][setting_]
end
View
78 lib/versionomy/value.rb
@@ -71,8 +71,8 @@ def initialize(values_, format_, unparse_params_=nil)
@_unparse_params = unparse_params_
@_field_path = []
@_values = {}
- schema_ = @_format.schema
- field_ = schema_.root_field
+ values_ = _canonicalize_values_hash(values_) if values_.kind_of?(::Hash)
+ field_ = @_format.schema.root_field
while field_
value_ = values_.kind_of?(::Hash) ? values_[field_.name] : values_.shift
value_ = value_ ? field_.canonicalize_value(value_) : field_.default_value
@@ -80,7 +80,7 @@ def initialize(values_, format_, unparse_params_=nil)
@_values[field_.name] = value_
field_ = field_.child(value_)
end
- modules_ = schema_.modules
+ modules_ = @_format.schema.modules
extend(*modules_) if modules_.size > 0
end
@@ -259,7 +259,7 @@ def has_field?(field_)
when ::Integer
@_field_path.size > field_ && field_ >= 0
when ::String, ::Symbol
- @_values.has_key?(field_.to_sym)
+ @_values.has_key?(@_format.schema.canonical_name(field_))
else
raise ::ArgumentError
end
@@ -271,9 +271,7 @@ def has_field?(field_)
# or field index.
def [](field_)
- field_ = @_field_path[field_] if field_.kind_of?(::Integer)
- field_ = field_.name if field_.kind_of?(Schema::Field)
- field_ ? @_values[field_.to_sym] : nil
+ @_values[_interpret_field(field_)]
end
@@ -298,17 +296,14 @@ def values_hash
# 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 self unless name_
- name_ = name_.to_sym
- return self unless @_values.include?(name_)
+ def bump(field_)
+ name_ = _interpret_field(field_)
+ return self unless name_ && @_values.include?(name_)
values_ = []
- @_field_path.each do |field_|
- oldval_ = @_values[field_.name]
- if field_.name == name_
- newval_ = field_.bump_value(oldval_)
+ @_field_path.each do |fld_|
+ oldval_ = @_values[fld_.name]
+ if fld_.name == name_
+ newval_ = fld_.bump_value(oldval_)
return self if newval_ == oldval_
values_ << newval_
return Value.new(values_, @_format, @_unparse_params)
@@ -320,6 +315,28 @@ def bump(name_)
end
+ # Returns a new version number created by resetting the given field. The
+ # field may be specified as a field object, field name, or field index.
+ # Returns self unchanged if the field was not recognized or could not
+ # be modified.
+
+ def reset(field_)
+ name_ = _interpret_field(field_)
+ return self unless name_ && @_values.include?(name_)
+ values_ = []
+ @_field_path.each do |fld_|
+ oldval_ = @_values[fld_.name]
+ if fld_.name == name_
+ values_ << fld_.default_value
+ return Value.new(values_, @_format, @_unparse_params)
+ else
+ values_ << oldval_
+ end
+ end
+ self
+ end
+
+
# Returns a new version number created by cloning this version number
# and changing the given field values.
#
@@ -334,6 +351,7 @@ def bump(name_)
def change(values_={}, unparse_params_={})
unparse_params_ = @_unparse_params.merge(unparse_params_) if @_unparse_params
+ values_ = _canonicalize_values_hash(values_)
Value.new(@_values.merge(values_), @_format, unparse_params_)
end
@@ -456,6 +474,32 @@ def method_missing(symbol_)
end
+ private
+
+ def _interpret_field(field_) # :nodoc:
+ case field_
+ when Schema::Field
+ @_format.schema.canonical_name(field_.name)
+ when ::Integer
+ field_ = @_field_path[field_]
+ field_ ? field_.name : nil
+ when ::String, ::Symbol
+ @_format.schema.canonical_name(field_)
+ end
+ end
+
+
+ def _canonicalize_values_hash(values_) # :nodoc:
+ schema_ = @_format.schema
+ new_values_ = {}
+ values_.each do |k_,v_|
+ k_ = schema_.canonical_name(k_)
+ new_values_[k_] = v_ if k_
+ end
+ new_values_
+ end
+
+
end
View
2  lib/versionomy/version.rb
@@ -37,7 +37,7 @@
module Versionomy
# Current gem version, as a frozen string.
- VERSION_STRING = '0.2.5'.freeze
+ VERSION_STRING = '0.3.0'.freeze
# Current gem version, as a Versionomy::Value.
VERSION = ::Versionomy.parse(VERSION_STRING, :standard)
View
35 tests/tc_rubygems_basic.rb
@@ -76,6 +76,23 @@ def test_arbitrary_value
end
+ # Test aliases
+
+ def test_alias_fields
+ value_ = ::Versionomy.create([1, 9, 2, 'a', 2], :rubygems)
+ assert_equal(1, value_.major)
+ assert_equal(9, value_.minor)
+ end
+
+
+ # Test construction using aliases
+
+ def test_alias_field_construction
+ value_ = ::Versionomy.create({:major => 1, :minor => 9, :field2 => 2}, :rubygems)
+ assert_equal([1, 9, 2, 0, 0, 0, 0, 0], value_.values_array)
+ end
+
+
# Test comparison of numeric values.
def test_numeric_comparison
@@ -153,6 +170,24 @@ def test_bump_string
end
+ # Test bumping an alias field.
+
+ def test_bump_alias
+ value_ = ::Versionomy.create([1, 9, 2, 'a', 2], :rubygems)
+ value_ = value_.bump(:minor)
+ assert_equal([1, 10, 0, 0, 0, 0, 0, 0], value_.values_array)
+ end
+
+
+ # Test changing an alias field.
+
+ def test_change_alias
+ value_ = ::Versionomy.create([1, 8, 7, 'a', 2], :rubygems)
+ value_ = value_.change(:minor => 9)
+ assert_equal([1, 9, 7, 'a', 2, 0, 0, 0], value_.values_array)
+ end
+
+
# Test "prerelase?" custom method
def test_method_prereleasep
View
106 tests/tc_standard_reset.rb
@@ -0,0 +1,106 @@
+# -----------------------------------------------------------------------------
+#
+# Versionomy bump tests on standard schema
+#
+# This file contains tests for the bump function on the standard schema
+#
+# -----------------------------------------------------------------------------
+# Copyright 2008-2009 Daniel Azuma
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+# * Neither the name of the copyright holder, nor the names of any other
+# contributors to this software, may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+# -----------------------------------------------------------------------------
+
+
+require 'rubygems'
+require 'test/unit'
+require ::File.expand_path("#{::File.dirname(__FILE__)}/../lib/versionomy.rb")
+
+
+module Versionomy
+ module Tests # :nodoc:
+
+ class TestStandardReset < ::Test::Unit::TestCase # :nodoc:
+
+
+ # Test resetting a minor patchlevel.
+
+ def test_reset_patchlevel_minor
+ value_ = ::Versionomy.create(:major => 2, :tiny => 1, :patchlevel => 3, :patchlevel_minor => 1)
+ value_ = value_.reset(:patchlevel_minor)
+ assert_equal([2,0,1,0,:final,3,0], value_.values_array)
+ end
+
+
+ # Test resetting a major patchlevel.
+
+ def test_reset_patchlevel
+ value_ = ::Versionomy.create(:major => 2, :tiny => 1, :patchlevel => 3, :patchlevel_minor => 1)
+ value_ = value_.reset(:patchlevel)
+ assert_equal([2,0,1,0,:final,0,0], value_.values_array)
+ end
+
+
+ # Test resetting a beta release type.
+
+ def test_reset_beta_release_type
+ value_ = ::Versionomy.create(:major => 2, :tiny => 1, :release_type => :beta, :beta_version => 2)
+ value_ = value_.reset(:release_type)
+ assert_equal([2,0,1,0,:final,0,0], value_.values_array)
+ end
+
+
+ # Test resetting a final release type.
+
+ def test_reset_final_release_type
+ value_ = ::Versionomy.create(:major => 2, :tiny => 1, :patchlevel => 2)
+ value_ = value_.reset(:release_type)
+ assert_equal([2,0,1,0,:final,0,0], value_.values_array)
+ end
+
+
+ # Test resetting tiny.
+
+ def test_reset_tiny
+ value_ = ::Versionomy.create(:major => 2, :tiny => 1, :tiny2 => 3, :release_type => :release_candidate, :release_candidate_version => 2)
+ value_ = value_.reset(:tiny)
+ assert_equal([2,0,0,0,:final,0,0], value_.values_array)
+ end
+
+
+ # Test resetting major.
+
+ def test_reset_major
+ value_ = ::Versionomy.create(:major => 2, :tiny => 1, :tiny2 => 3, :release_type => :release_candidate, :release_candidate_version => 2)
+ value_ = value_.reset(:major)
+ assert_equal([1,0,0,0,:final,0,0], value_.values_array)
+ end
+
+
+ end
+
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.