Skip to content
Browse files

Add rubygems format; support adding methods to value objects

  • Loading branch information...
1 parent f839b96 commit 42093b5932ea3327a3bb47812b2038e7e4b68523 @dazuma dazuma committed Nov 3, 2009
View
8 History.rdoc
@@ -1,6 +1,12 @@
+=== 0.2.0 / 2009-??-??
+
+* Schemas can now add custom methods to value objects.
+* Added default field settings to schema DSL.
+* Added Rubygems format.
+
=== 0.1.3 / 2009-10-29
-* Fixed an issue with parsing the "-p" patchlevel delimiter (e.g. "1.9.1-p243").
+* Fixed an issue with parsing the "-p" patchlevel delimiter, e.g. "1.9.1-p243". (Reported by Luis Lavena.)
=== 0.1.2 / 2009-10-28
View
1 lib/versionomy.rb
@@ -54,6 +54,7 @@
'format/delimiter',
'formats',
'formats/standard',
+ 'formats/rubygems',
'value',
'interface',
'version',
View
2 lib/versionomy/format/delimiter.rb
@@ -876,7 +876,7 @@ def parsed_value(value_, parse_params_, unparse_params_)
end
def unparsed_value(value_, style_, unparse_params_)
- value_
+ value_.to_s
end
end
View
200 lib/versionomy/formats/rubygems.rb
@@ -0,0 +1,200 @@
+# -----------------------------------------------------------------------------
+#
+# 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 Formats
+
+
+ # Get the rubygems 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.
+ #
+ # For the exact annotated definition of the standard schema and format,
+ # see the source code for Versionomy::Formats::Rubygems#_create.
+
+ def self.rubygems
+ get('rubygems')
+ end
+
+
+ module Rubygems
+
+
+ # Extra methods added to version values that use the rubygems schema.
+
+ module ExtraMethods
+
+
+ # Returns true if the version is a prerelease version
+
+ def prerelease?
+ values_array.any?{ |val_| val_.kind_of?(String) }
+ end
+
+
+ end
+
+
+ # Create the 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 schema and format
+ # definition DSLs.
+
+ def self._create
+
+ # The following is the definition of the rubygems schema
+ schema_ = Schema.create do
+
+ # Global comparison function
+ to_compare_type(:string) do |a_, b_|
+ if a_.kind_of?(::Integer)
+ if b_.kind_of?(::Integer)
+ a_ - b_
+ else
+ 1
+ end
+ else
+ if b_.kind_of?(::Integer)
+ -1
+ else
+ a_ <=> b_
+ end
+ end
+ end
+
+ # Global canonicalization function
+ to_canonicalize_type(:string) do |val_|
+ if val_.kind_of?(::Integer)
+ val_
+ else
+ val_ = val_.to_s
+ if val_ =~ /^\d*$/
+ val_.to_i
+ else
+ val_
+ end
+ end
+ end
+
+ # The first field has the default value of 1. All other fields
+ # have a default value of 0. Thus, the default version number
+ # overall is "1.0".
+ field(:field0, :type => :string, :default_value => 1) do
+ field(:field1, :type => :string) do
+ field(:field2, :type => :string) do
+ field(:field3, :type => :string) do
+ field(:field4, :type => :string) do
+ field(:field5, :type => :string) do
+ field(:field6, :type => :string) do
+ field(:field7, :type => :string)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ # Add the methods in this module to each value
+ add_module(Formats::Rubygems::ExtraMethods)
+ end
+
+ # The following is the definition of the standard format. It
+ # understands the standard schema defined above.
+ format_ = Format::Delimiter.new(schema_) do
+
+ # All version number strings must start with the major version.
+ # Unlike other fields, it is not preceded by any delimiter.
+ field(:field0) do
+ recognize_regexp('[0-9a-zA-Z]+', :delimiter_regexp => '', :default_delimiter => '')
+ end
+
+ # The remainder of the version number are represented as strings
+ # or integers delimited by periods by default. Each is also
+ # dependent on the presence of the previous field, so
+ # :requires_previous_field retains its default value of true.
+ # Finally, they can be optional in an unparsed string if they are
+ # set to the default value of 0.
+ field(:field1) do
+ recognize_regexp('[0-9a-zA-Z]+', :delimiter_regexp => '[^0-9a-zA-Z]+',
+ :default_value_optional => true)
+ end
+ field(:field2) do
+ recognize_regexp('[0-9a-zA-Z]+', :delimiter_regexp => '[^0-9a-zA-Z]+',
+ :default_value_optional => true)
+ end
+ field(:field3) do
+ recognize_regexp('[0-9a-zA-Z]+', :delimiter_regexp => '[^0-9a-zA-Z]+',
+ :default_value_optional => true)
+ end
+ field(:field4) do
+ recognize_regexp('[0-9a-zA-Z]+', :delimiter_regexp => '[^0-9a-zA-Z]+',
+ :default_value_optional => true)
+ end
+ field(:field5) do
+ recognize_regexp('[0-9a-zA-Z]+', :delimiter_regexp => '[^0-9a-zA-Z]+',
+ :default_value_optional => true)
+ end
+ field(:field6) do
+ recognize_regexp('[0-9a-zA-Z]+', :delimiter_regexp => '[^0-9a-zA-Z]+',
+ :default_value_optional => true)
+ end
+ field(:field7) do
+ recognize_regexp('[0-9a-zA-Z]+', :delimiter_regexp => '[^0-9a-zA-Z]+',
+ :default_value_optional => true)
+ end
+
+ # By default, we require that at least the first two fields
+ # appear in an unparsed version string.
+ default_unparse_params(:required_fields => [:field1])
+ end
+ end
+
+
+ end
+
+
+ register('rubygems', Rubygems._create) unless get('rubygems')
+
+
+ end
+
+end
View
470 lib/versionomy/formats/standard.rb
@@ -93,252 +93,276 @@ module Formats
# unparsing as well.
#
# For the exact annotated definition of the standard schema and format,
- # see the source code for the _create_standard method.
+ # see the source code for Versionomy::Formats::Standard#_create.
def self.standard
get('standard')
end
- # Create the 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 schema and format
- # definition DSLs.
-
- def self._create_standard
+ module Standard
+
+
+ # Extra methods added to version values that use the standard schema.
- # The following is the definition of the standard schema
- schema_ = Schema.create do
+ module ExtraMethods
- # The major field has the default value of 1. Most other fields
- # have a default value of 0. Thus, the default version number
- # overall is "1.0".
- # We first create the core version fields "major.minor.tiny.tiny2".
- field(:major, :default_value => 1) do
- field(:minor) do
- field(:tiny) do
- field(:tiny2) do
-
- # The next field is a symbolic field that specifies the
- # release type: e.g. beta, release candidate, release, etc.
- field(:release_type, :type => :symbol) do
-
- # Development releases are typically expressed like
- # "1.0d3" and are intended for unstable development
- # progress. Bumping the release type will change it to
- # alpha.
- symbol(:development, :bump => :alpha)
-
- # Alpha releases are typically expressed like "1.0a2" and
- # are intended for internal testing.
- # Bumping the release type advances to beta.
- symbol(:alpha, :bump => :beta)
-
- # Beta releases are typically expressed like "1.0b2" and
- # are intended for external or public testing.
- # Bumping the release type advances to release candidate.
- symbol(:beta, :bump => :release_candidate)
-
- # Release candidate releases are typically expressed like
- # "1.0rc2" and are intended for final public testing
- # prior to release.
- # Bumping the release type advances to final release.
- symbol(:release_candidate, :bump => :final)
-
- # Preview releases represent an alternative release type
- # progression, and are typically used for public testing
- # similar to beta or release candidate.
- # Bumping the release type advances to final release.
- symbol(:preview, :bump => :final)
-
- # This type represents a final release. This is the
- # default value for the release_type field if no value is
- # explicitly provided.
- # Bumping the release type has no effect.
- symbol(:final, :bump => :final)
- default_value(:final)
-
- # If the release type is development, these fields are
- # made available to indicate which development release
- # is being represented.
- field(:development_version, :only => :development,
- :default_value => 1) do
- field(:development_minor)
- end
-
- # If the release type is alpha, these fields are made
- # available to indicate which alpha release is being
- # represented.
- field(:alpha_version, :only => :alpha, :default_value => 1) do
- field(:alpha_minor)
- end
-
- # If the release type is beta, these fields are made
- # available to indicate which beta release is being
- # represented.
- field(:beta_version, :only => :beta, :default_value => 1) do
- field(:beta_minor)
- end
-
- # If the release type is release candidate, these fields
- # are made available to indicate which release candidate
- # is being represented.
- field(:release_candidate_version, :only => :release_candidate,
- :default_value => 1) do
- field(:release_candidate_minor)
- end
-
- # If the release type is preview, these fields are made
- # available to indicate which preview release is being
- # represented.
- field(:preview_version, :only => :preview, :default_value => 1) do
- field(:preview_minor)
- end
+
+ # Returns true if the version is a prerelease version
+
+ def prerelease?
+ self.release_type != :final
+ end
+
+
+ end
+
+
+ # Create the 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 schema and format
+ # definition DSLs.
+
+ def self._create
+
+ # The following is the definition of the standard schema
+ schema_ = Schema.create do
+
+ # The major field has the default value of 1. Most other fields
+ # have a default value of 0. Thus, the default version number
+ # overall is "1.0".
+ # We first create the core version fields "major.minor.tiny.tiny2".
+ field(:major, :default_value => 1) do
+ field(:minor) do
+ field(:tiny) do
+ field(:tiny2) do
- # If the release type is final, these fields are made
- # available to indicate an optional patchlevel.
- field(:patchlevel, :only => :final) do
- field(:patchlevel_minor)
+ # The next field is a symbolic field that specifies the
+ # release type: e.g. beta, release candidate, release, etc.
+ field(:release_type, :type => :symbol) do
+
+ # Development releases are typically expressed like
+ # "1.0d3" and are intended for unstable development
+ # progress. Bumping the release type will change it to
+ # alpha.
+ symbol(:development, :bump => :alpha)
+
+ # Alpha releases are typically expressed like "1.0a2" and
+ # are intended for internal testing.
+ # Bumping the release type advances to beta.
+ symbol(:alpha, :bump => :beta)
+
+ # Beta releases are typically expressed like "1.0b2" and
+ # are intended for external or public testing.
+ # Bumping the release type advances to release candidate.
+ symbol(:beta, :bump => :release_candidate)
+
+ # Release candidate releases are typically expressed like
+ # "1.0rc2" and are intended for final public testing
+ # prior to release.
+ # Bumping the release type advances to final release.
+ symbol(:release_candidate, :bump => :final)
+
+ # Preview releases represent an alternative release type
+ # progression, and are typically used for public testing
+ # similar to beta or release candidate.
+ # Bumping the release type advances to final release.
+ symbol(:preview, :bump => :final)
+
+ # This type represents a final release. This is the
+ # default value for the release_type field if no value is
+ # explicitly provided.
+ # Bumping the release type has no effect.
+ symbol(:final, :bump => :final)
+ default_value(:final)
+
+ # If the release type is development, these fields are
+ # made available to indicate which development release
+ # is being represented.
+ field(:development_version, :only => :development,
+ :default_value => 1) do
+ field(:development_minor)
+ end
+
+ # If the release type is alpha, these fields are made
+ # available to indicate which alpha release is being
+ # represented.
+ field(:alpha_version, :only => :alpha, :default_value => 1) do
+ field(:alpha_minor)
+ end
+
+ # If the release type is beta, these fields are made
+ # available to indicate which beta release is being
+ # represented.
+ field(:beta_version, :only => :beta, :default_value => 1) do
+ field(:beta_minor)
+ end
+
+ # If the release type is release candidate, these fields
+ # are made available to indicate which release candidate
+ # is being represented.
+ field(:release_candidate_version, :only => :release_candidate,
+ :default_value => 1) do
+ field(:release_candidate_minor)
+ end
+
+ # If the release type is preview, these fields are made
+ # available to indicate which preview release is being
+ # represented.
+ field(:preview_version, :only => :preview, :default_value => 1) do
+ field(:preview_minor)
+ end
+
+ # If the release type is final, these fields are made
+ # available to indicate an optional patchlevel.
+ field(:patchlevel, :only => :final) do
+ field(:patchlevel_minor)
+ end
end
end
end
end
end
+
+ # Add the methods in this module to each value
+ add_module(Formats::Standard::ExtraMethods)
end
- end
-
- # The following is the definition of the standard format. It
- # understands the standard schema defined above.
- format_ = Format::Delimiter.new(schema_) do
- # All version number strings must start with the major version.
- # Unlike other fields, it is not preceded by any delimiter.
- field(:major) do
- recognize_number(:delimiter_regexp => '', :default_delimiter => '')
- end
-
- # The remainder of the core version number are represented as
- # integers delimited by periods by default. Each is also dependent
- # on the presence of the previous field, so :requires_previous_field
- # retains its default value of true. Finally, they can be optional
- # in an unparsed string if they are set to the default value of 0.
- field(:minor) do
- recognize_number(:default_value_optional => true)
- end
- field(:tiny) do
- recognize_number(:default_value_optional => true)
- end
- field(:tiny2) do
- recognize_number(:default_value_optional => true)
- end
-
- # The release type field is the most complex field because of the
- # variety of syntaxes we support. The basic strategy is to map
- # a few specific sets of characters as signaling particular release
- # types. For example, the "a" in "1.0a5" signals an alpha release.
- # If no such release type marker is found, it defaults to the final
- # release type.
- # We set up two styles, a short style and a long style. Short style
- # syntax looks like "1.0a5". Long syntax looks more like
- # "1.0 Alpha 5". The parsed value retains knowledge of which style
- # it came from so it can be reconstructed when the value is unparsed.
- # Finally, we turn requires_previous_field off because the release
- # type syntax markers don't require any particular set of the core
- # version number fields to be present. "1.0a5" and "1.0.0.0a5" are
- # both valid version numbers.
- field(:release_type, :requires_previous_field => false,
- :default_style => :short) do
- # First check for "short form" syntax. Not that we support post-
- # delimiters; that is, we recognize "1.0 pre-2" where the hyphen
- # is a post-delimiter. Also notice that we expect prerelease types
- # to be followed by a numeric prerelease version number.
- recognize_regexp_map(:style => :short, :default_delimiter => '',
- :delimiter_regexp => '-|\.|\s?',
- :post_delimiter_regexp => '\s?|-',
- :expected_follower_regexp => '\d') do
- map(:development, 'd')
- map(:alpha, 'a')
- map(:beta, 'b')
- map(:release_candidate, 'rc')
- map(:preview, 'pre')
- # Note that we omit the value <tt>:final</tt>. This is because
- # that value is signaled by the absence of any syntax in the
- # version string, including the absence of any delimiters. So we
- # just allow it to fall through to the default.
+ # The following is the definition of the standard format. It
+ # understands the standard schema defined above.
+ format_ = Format::Delimiter.new(schema_) do
+
+ # All version number strings must start with the major version.
+ # Unlike other fields, it is not preceded by any delimiter.
+ field(:major) do
+ recognize_number(:delimiter_regexp => '', :default_delimiter => '')
end
- # Check for "long form" syntax. Note again that we omit :final.
- recognize_regexp_map(:style => :long, :default_delimiter => '',
- :delimiter_regexp => '-|\.|\s?',
- :post_delimiter_regexp => '\s?|-',
- :expected_follower_regexp => '\d') do
- map(:development, 'dev')
- map(:alpha, 'alpha')
- map(:beta, 'beta')
- map(:release_candidate, 'rc')
- map(:preview, 'preview')
+
+ # The remainder of the core version number are represented as
+ # integers delimited by periods by default. Each is also dependent
+ # on the presence of the previous field, so :requires_previous_field
+ # retains its default value of true. Finally, they can be optional
+ # in an unparsed string if they are set to the default value of 0.
+ field(:minor) do
+ recognize_number(:default_value_optional => true)
end
+ field(:tiny) do
+ recognize_number(:default_value_optional => true)
+ end
+ field(:tiny2) do
+ recognize_number(:default_value_optional => true)
+ end
+
+ # The release type field is the most complex field because of the
+ # variety of syntaxes we support. The basic strategy is to map
+ # a few specific sets of characters as signaling particular release
+ # types. For example, the "a" in "1.0a5" signals an alpha release.
+ # If no such release type marker is found, it defaults to the final
+ # release type.
+ # We set up two styles, a short style and a long style. Short style
+ # syntax looks like "1.0a5". Long syntax looks more like
+ # "1.0 Alpha 5". The parsed value retains knowledge of which style
+ # it came from so it can be reconstructed when the value is unparsed.
+ # Finally, we turn requires_previous_field off because the release
+ # type syntax markers don't require any particular set of the core
+ # version number fields to be present. "1.0a5" and "1.0.0.0a5" are
+ # both valid version numbers.
+ field(:release_type, :requires_previous_field => false,
+ :default_style => :short) do
+ # First check for "short form" syntax. Not that we support post-
+ # delimiters; that is, we recognize "1.0 pre-2" where the hyphen
+ # is a post-delimiter. Also notice that we expect prerelease types
+ # to be followed by a numeric prerelease version number.
+ recognize_regexp_map(:style => :short, :default_delimiter => '',
+ :delimiter_regexp => '-|\.|\s?',
+ :post_delimiter_regexp => '\s?|-',
+ :expected_follower_regexp => '\d') do
+ map(:development, 'd')
+ map(:alpha, 'a')
+ map(:beta, 'b')
+ map(:release_candidate, 'rc')
+ map(:preview, 'pre')
+ # Note that we omit the value <tt>:final</tt>. This is because
+ # that value is signaled by the absence of any syntax in the
+ # version string, including the absence of any delimiters. So we
+ # just allow it to fall through to the default.
+ end
+ # Check for "long form" syntax. Note again that we omit :final.
+ recognize_regexp_map(:style => :long, :default_delimiter => '',
+ :delimiter_regexp => '-|\.|\s?',
+ :post_delimiter_regexp => '\s?|-',
+ :expected_follower_regexp => '\d') do
+ map(:development, 'dev')
+ map(:alpha, 'alpha')
+ map(:beta, 'beta')
+ map(:release_candidate, 'rc')
+ map(:preview, 'preview')
+ end
+ end
+
+ # The development version must appear in the string if it is present
+ # in the value, even if the value is 0. Similar for all the other
+ # prerelease version numbers: alpha, beta, release candidate, and
+ # preview. However, the minor fields are optional.
+ field(:development_version) do
+ recognize_number(:delimiter_regexp => '', :default_delimiter => '')
+ end
+ field(:development_minor) do
+ recognize_number(:default_value_optional => true)
+ end
+ field(:alpha_version) do
+ recognize_number(:delimiter_regexp => '', :default_delimiter => '')
+ end
+ field(:alpha_minor) do
+ recognize_number(:default_value_optional => true)
+ end
+ field(:beta_version) do
+ recognize_number(:delimiter_regexp => '', :default_delimiter => '')
+ end
+ field(:beta_minor) do
+ recognize_number(:default_value_optional => true)
+ end
+ field(:release_candidate_version) do
+ recognize_number(:delimiter_regexp => '', :default_delimiter => '')
+ end
+ field(:release_candidate_minor) do
+ recognize_number(:default_value_optional => true)
+ end
+ field(:preview_version) do
+ recognize_number(:delimiter_regexp => '', :default_delimiter => '')
+ end
+ field(:preview_minor) do
+ recognize_number(:default_value_optional => true)
+ end
+
+ # The patchlevel field does not require the previous field (which is
+ # release_type). Here we also set up two styles: a numeric style and
+ # a letter style. So "1.0a" and "1.0-1" are equivalent.
+ field(:patchlevel, :requires_previous_field => false,
+ :default_value_optional => true, :default_style => :number) do
+ recognize_number(:style => :number, :default_delimiter => '-',
+ :delimiter_regexp => '(-|\.|\s?)p|-')
+ recognize_letter(:style => :letter, :default_delimiter => '',
+ :delimiter_regexp => '-|\.|\s?',
+ :expected_follower_regexp => '$')
+ end
+ field(:patchlevel_minor) do
+ recognize_number(:default_value_optional => true)
+ end
+
+ # By default, we require that at least the major and minor fields
+ # appear in an unparsed version string.
+ default_unparse_params(:required_fields => [:minor])
end
-
- # The development version must appear in the string if it is present
- # in the value, even if the value is 0. Similar for all the other
- # prerelease version numbers: alpha, beta, release candidate, and
- # preview. However, the minor fields are optional.
- field(:development_version) do
- recognize_number(:delimiter_regexp => '', :default_delimiter => '')
- end
- field(:development_minor) do
- recognize_number(:default_value_optional => true)
- end
- field(:alpha_version) do
- recognize_number(:delimiter_regexp => '', :default_delimiter => '')
- end
- field(:alpha_minor) do
- recognize_number(:default_value_optional => true)
- end
- field(:beta_version) do
- recognize_number(:delimiter_regexp => '', :default_delimiter => '')
- end
- field(:beta_minor) do
- recognize_number(:default_value_optional => true)
- end
- field(:release_candidate_version) do
- recognize_number(:delimiter_regexp => '', :default_delimiter => '')
- end
- field(:release_candidate_minor) do
- recognize_number(:default_value_optional => true)
- end
- field(:preview_version) do
- recognize_number(:delimiter_regexp => '', :default_delimiter => '')
- end
- field(:preview_minor) do
- recognize_number(:default_value_optional => true)
- end
-
- # The patchlevel field does not require the previous field (which is
- # release_type). Here we also set up two styles: a numeric style and
- # a letter style. So "1.0a" and "1.0-1" are equivalent.
- field(:patchlevel, :requires_previous_field => false,
- :default_value_optional => true, :default_style => :number) do
- recognize_number(:style => :number, :default_delimiter => '-',
- :delimiter_regexp => '(-|\.|\s?)p|-')
- recognize_letter(:style => :letter, :default_delimiter => '',
- :delimiter_regexp => '-|\.|\s?',
- :expected_follower_regexp => '$')
- end
- field(:patchlevel_minor) do
- recognize_number(:default_value_optional => true)
- end
-
- # By default, we require that at least the major and minor fields
- # appear in an unparsed version string.
- default_unparse_params(:required_fields => [:minor])
end
+
+
end
- register('standard', _create_standard) unless get('standard')
+ register('standard', Standard._create) unless get('standard')
end
View
4 lib/versionomy/interface.rb
@@ -90,12 +90,12 @@ def default_format=(format_)
# Raises Versionomy::Errors::UnknownFormatError if a name is given that
# is not registered.
- def create(values_=[], format_=nil, unparse_params_=nil)
+ def create(values_=nil, format_=nil, unparse_params_=nil)
if format_.kind_of?(String) || format_.kind_of?(Symbol)
format_ = Formats.get(format_, true)
end
format_ ||= default_format
- Value.new(values_, format_, unparse_params_)
+ Value.new(values_ || [], format_, unparse_params_)
end
View
15 lib/versionomy/schema/field.rb
@@ -69,21 +69,28 @@ class Field
def initialize(name_, opts_={}, &block_)
@name = name_.to_sym
@type = opts_[:type] || :integer
- @default_value = opts_[:default_value]
if @type == :symbol
@symbol_info = ::Hash.new
@symbol_order = ::Array.new
else
@symbol_info = nil
@symbol_order = nil
end
+ @default_value = opts_[:default_value]
@bump_proc = nil
@compare_proc = nil
@canonicalize_proc = nil
+ master_builder_ = opts_[:master_builder]
+ if master_builder_
+ @bump_proc = master_builder_._get_default_setting(@type, :bump)
+ @compare_proc = master_builder_._get_default_setting(@type, :compare)
+ @canonicalize_proc = master_builder_._get_default_setting(@type, :canonicalize)
+ @default_value ||= master_builder_._get_default_setting(@type, :value)
+ end
@ranges = nil
@default_child = nil
@children = []
- ::Blockenspiel.invoke(block_, Schema::FieldBuilder.new(self)) if block_
+ ::Blockenspiel.invoke(block_, Schema::FieldBuilder.new(self, master_builder_)) if block_
@default_value = canonicalize_value(@default_value)
end
@@ -371,8 +378,9 @@ class FieldBuilder
include ::Blockenspiel::DSL
- def initialize(field_) # :nodoc:
+ def initialize(field_, master_builder_) # :nodoc:
@field = field_
+ @master_builder = master_builder_
end
@@ -474,6 +482,7 @@ def to_canonicalize(&block_)
def field(name_, opts_={}, &block_)
only_ = opts_.delete(:only)
+ opts_.merge!(:master_builder => @master_builder)
@field.add_child(Schema::Field.new(name_, opts_, &block_), only_)
end
View
59 lib/versionomy/schema/wrapper.rb
@@ -46,16 +46,19 @@ module Schema
# fields. If you provide a block, you must use the methods in
# Versionomy::Schema::Builder in the block to create the root field.
- def self.create(field_=nil, &block_)
+ def self.create(field_=nil, opts_={}, &block_)
if field_ && block_
raise ::ArgumentError, 'You may provide either a root field or block but not both'
end
if block_
builder_ = Schema::Builder.new
::Blockenspiel.invoke(block_, builder_)
field_ = builder_._get_field
+ modules_ = builder_._get_modules
+ else
+ modules_ = opts_[:modules] || []
end
- Schema::Wrapper.new(field_)
+ Schema::Wrapper.new(field_, modules_)
end
@@ -68,9 +71,10 @@ class Wrapper
# This is a low-level method. Usually you should call
# Versionomy::Schema#create instead.
- def initialize(field_)
+ def initialize(field_, modules_=[])
@root_field = field_
@names = @root_field._descendants_by_name
+ @modules = modules_
end
@@ -80,7 +84,7 @@ def initialize(field_)
def eql?(obj_)
return false unless obj_.kind_of?(Schema::Wrapper)
- return @root_field == obj_.root_field
+ return @root_field == obj_.root_field && @modules == obj_.modules
end
@@ -121,6 +125,14 @@ def names
end
+ # Returns an array of modules that should be included in values that
+ # use this schema.
+
+ def modules
+ @modules.dup
+ end
+
+
end
@@ -133,6 +145,8 @@ class Builder
def initialize() # :nodoc:
@field = nil
+ @modules = []
+ @defaults = { :integer => {}, :string => {}, :symbol => {} }
end
@@ -161,14 +175,49 @@ def field(name_, opts_={}, &block_)
if @field
raise Errors::RangeOverlapError, "Root field already defined"
end
- @field = Schema::Field.new(name_, opts_, &block_)
+ @field = Schema::Field.new(name_, opts_.merge(:master_builder => self), &block_)
+ end
+
+
+ # Add a module to values that use this schema.
+
+ def add_module(mod_)
+ @modules << mod_
+ end
+
+
+ def to_bump_type(type_, &block_)
+ @defaults[type_][:bump] = block_
+ end
+
+
+ def to_compare_type(type_, &block_)
+ @defaults[type_][:compare] = block_
+ end
+
+
+ def to_canonicalize_type(type_, &block_)
+ @defaults[type_][:canonicalize] = block_
+ end
+
+
+ def default_value_for_type(type_, value_)
+ @defaults[type_][:value] = value_
end
def _get_field # :nodoc:
@field
end
+ def _get_modules # :nodoc:
+ @modules
+ end
+
+ def _get_default_setting(type_, setting_) # :nodoc:
+ @defaults[type_][setting_]
+ end
+
end
View
5 lib/versionomy/value.rb
@@ -68,14 +68,17 @@ def initialize(values_, format_, unparse_params_=nil)
@unparse_params = unparse_params_
@field_path = []
@values = {}
- field_ = @format.schema.root_field
+ schema_ = @format.schema
+ field_ = schema_.root_field
while field_
value_ = values_.kind_of?(Hash) ? values_[field_.name] : values_.shift
value_ = value_ ? field_.canonicalize_value(value_) : field_.default_value
@field_path << field_
@values[field_.name] = value_
field_ = field_.child(value_)
end
+ modules_ = schema_.modules
+ extend(*modules_) if modules_.size > 0
end
View
2 lib/versionomy/version.rb
@@ -37,7 +37,7 @@
module Versionomy
# Current gem version, as a frozen string.
- VERSION_STRING = '0.1.3'.freeze
+ VERSION_STRING = '0.2.0'.freeze
# Current gem version, as a Versionomy::Value.
VERSION = ::Versionomy.parse(VERSION_STRING, :standard)
View
168 tests/tc_rubygems_basic.rb
@@ -0,0 +1,168 @@
+# -----------------------------------------------------------------------------
+#
+# Versionomy basic tests on standard schema
+#
+# This file contains tests for the basic use cases 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 'test/unit'
+require File.expand_path("#{File.dirname(__FILE__)}/../lib/versionomy.rb")
+
+
+module Versionomy
+ module Tests # :nodoc:
+
+ class TestRubygemsBasic < Test::Unit::TestCase # :nodoc:
+
+
+ # Test the default version value.
+
+ def test_default_value
+ value_ = Versionomy.create(nil, :rubygems)
+ assert_equal(1, value_.field0)
+ assert_equal(0, value_.field1)
+ assert_equal(0, value_.field2)
+ assert_equal(0, value_.field3)
+ assert_equal(0, value_.field4)
+ assert_equal(0, value_.field5)
+ assert_equal(0, value_.field6)
+ assert_equal(0, value_.field7)
+ end
+
+
+ # Test an arbitrary value.
+
+ def test_arbitrary_value
+ value_ = Versionomy.create([1, 9, 2, 'pre', 2], :rubygems)
+ assert_equal(1, value_.field0)
+ assert_equal(9, value_.field1)
+ assert_equal(2, value_.field2)
+ assert_equal('pre', value_.field3)
+ assert_equal(2, value_.field4)
+ assert_equal(0, value_.field5)
+ assert_equal(0, value_.field6)
+ assert_equal(0, value_.field7)
+ end
+
+
+ # Test comparison of numeric values.
+
+ def test_numeric_comparison
+ value1_ = Versionomy.create([1, 9, 2], :rubygems)
+ value2_ = Versionomy.create([1, 9], :rubygems)
+ assert(value2_ < value1_)
+ value1_ = Versionomy.create([1, 9, 0], :rubygems)
+ value2_ = Versionomy.create([1, 9], :rubygems)
+ assert(value2_ == value1_)
+ end
+
+
+ # Test comparison of string values.
+
+ def test_string_comparison
+ value1_ = Versionomy.create([1, 9, 2, 'a', 2], :rubygems)
+ value2_ = Versionomy.create([1, 9, 2, 'b', 1], :rubygems)
+ assert(value2_ > value1_)
+ end
+
+
+ # Test comparison of numeric and string values.
+
+ def test_numeric_and_string_comparison
+ value1_ = Versionomy.create([1, 9, 2, 'a', 2], :rubygems)
+ value2_ = Versionomy.create([1, 9, 2, 1], :rubygems)
+ assert(value2_ > value1_)
+ end
+
+
+ # Test parsing numeric.
+
+ def test_parsing_numeric
+ value_ = Versionomy.parse('2.0.1.1-4.6', :rubygems)
+ assert_equal([2, 0, 1, 1, 4, 6, 0, 0], value_.values_array)
+ assert_equal('2.0.1.1-4.6', value_.unparse)
+ end
+
+
+ # Test parsing with a string.
+
+ def test_parsing_with_string
+ value_ = Versionomy.parse('1.9.2 pre-2', :rubygems)
+ assert_equal([1, 9, 2, 'pre', 2, 0, 0, 0], value_.values_array)
+ assert_equal('1.9.2 pre-2', value_.unparse)
+ end
+
+
+ # Test parsing with trailing zeros.
+
+ def test_parsing_trailing_zeros
+ value_ = Versionomy.parse('2.0.0', :rubygems)
+ assert_equal([2, 0, 0, 0, 0, 0, 0, 0], value_.values_array)
+ assert_equal('2.0.0', value_.unparse)
+ assert_equal('2.0.0.0.0', value_.unparse(:required_fields => [:field4]))
+ assert_equal('2.0', value_.unparse(:optional_fields => [:field2]))
+ end
+
+
+ # Test bumping a numeric field.
+
+ def test_bump_numeric
+ value_ = Versionomy.create([1, 9, 2, 'a', 2], :rubygems)
+ value_ = value_.bump(:field2)
+ assert_equal([1, 9, 3, 0, 0, 0, 0, 0], value_.values_array)
+ end
+
+
+ # Test bumping a string field.
+
+ def test_bump_string
+ value_ = Versionomy.create([1, 9, 2, 'a', 2], :rubygems)
+ value_ = value_.bump(:field3)
+ assert_equal([1, 9, 2, 'b', 0, 0, 0, 0], value_.values_array)
+ end
+
+
+ # Test "prerelase?" custom method
+
+ def test_prereleasep
+ value_ = Versionomy.create([1, 9, 2, 'a', 2], :rubygems)
+ assert_equal(true, value_.prerelease?)
+ value_ = Versionomy.create([1, 9, 2, 2], :rubygems)
+ assert_equal(false, value_.prerelease?)
+ end
+
+
+ end
+
+ end
+end
View
12 tests/tc_standard_basic.rb
@@ -169,6 +169,18 @@ def test_field_get_name
end
+ # Test "prerelase?" custom method
+
+ def test_prereleasep
+ value_ = Versionomy.create(:major => 2, :tiny => 1, :release_type => :beta, :beta_version => 3)
+ assert_equal(true, value_.prerelease?)
+ value_ = Versionomy.create(:major => 2, :tiny => 1, :release_type => :final, :patchlevel => 1)
+ assert_equal(false, value_.prerelease?)
+ value_ = Versionomy.create(:major => 2, :tiny => 1)
+ assert_equal(false, value_.prerelease?)
+ end
+
+
end
end

0 comments on commit 42093b5

Please sign in to comment.
Something went wrong with that request. Please try again.