From: Hugh Sasse Date: 2005-12-20T00:16:20+09:00 Subject: Re: 1.8.x, YAML, and release management On Mon, 19 Dec 2005, URABE Shyouhei wrote: > Hi. > > Hugh Sasse wrote: > > > Where is this constraint set? > > > > In matz himself. He announced that in, for instance, [ruby-dev:9366]. I see. I wonder what would change his mind... > > > Modifying the code that handles > > version numbers to support larger minor versions would seem to be > > useful. > > > > That's true. I agree. > > Sad thing is that requires a reconstruction of very low-level C infrastructure > in ruby source code. You can grep *.c files with RUBY_VERSION_CODE to see how Does it need to be C? Does it happen so often that we'd need the speed? I suggest a ruby implementation below. > ruby itself implies its version number being three-digit decimal numbers. As > 1.8 is a stable branch, I don't think it's a good idea to touch such a > fundamental point. > > > It would also help integration of gem version number > > handling within ruby. > > > > So what? That's another story. Not entirely -- I'm thinking about code re-use. > > > Such a change should not break existing > > assumptions, > > > > Yes it does. You can see how string comparisons are used in ruby version > checking in: > > http://raa.ruby-lang.org/gonzui/search?q=RUBY_VERSION&fm=all > > It's almost an idiom. Well, yes, but there are some odd possibly flawed cases where a integer is used and when the whole version number is treated as a float. > What are your thoughts about this: (Uses Runit because it dates back to 2000). #!/usr/local/bin/ruby -w # Revision class # Designed to function in version comparisons, where the # version number matches /\d+(\.\d+)*/ # Author: Hugh Sasse, De Montfort University # Created: 06-OCT-2000 # Last Modified: 19-OCT-2005 # $Id: revision.rb,v 1.3 2000-10-09 10:40:39+01 hgs Exp hgs $ class RevisionComparisonError < RuntimeError; end class Revision include Comparable DEBUG = false attr :contents def to_i @contents.join('').to_i end def to_s astring = @contents.collect { |j| j.to_s }.join(".") end # Convert the Major.Minor to float. MinorMinor version number # is difficult to handle because it depends on the size of Minor # to determine how far right to shift it. Bacwards # compatibility would necessitate 1 decimal place per revision, # but if Ruby reaches 1.10.1 this will break. Therefore float # comparisons should be deprecated. def to_f (@contents[0].to_s + '.' + contents[1]..to_s).to_f end def [](i) return @contents[i] end def <=>(x) puts "Revision(#{self}).<=> called with (#{x})" if DEBUG case x when String result = self <=> Revision.new(x) when Float f = self.to_f puts "#{f} <=> #{x}" if DEBUG result = self.to_f <=> x when Revision len = [@contents.size, x.contents.size].max puts "len is #{len}" if DEBUG result = 0 (0..(len-1)).each do |index| puts "result is #{result}" if DEBUG if result == 0 result = ((@contents[index] || 0) <=> (x.contents[index] || 0)) else break end end puts " finally result is #{result}" if DEBUG result else raise RevisionComparisonError.new("self is #{self}, other is #{x}") end result end def initialize(thing) if thing.class == Revision @contents = thing.contents.dup # dup so we get a new copy, not a pointer to it. elsif thing.class == String result = thing.split(".").collect {|j| j.to_i} @contents = result elsif thing.class == Float @contents = thing.to_s.split(".").collect {|j| j.to_i} else raise "cannot initialise to #{thing}" end puts "initialize(#{thing}) => @contents is #{@contents}" if DEBUG end end if __FILE__ == $0 # Perform RubyUnit tests require "runit/testcase" require 'runit/cui/testrunner' require 'runit/testsuite' class Testing_class < RUNIT::TestCase def test_constructor a = Revision.new("1.2.3") assert_equal([1,2,3], a.contents, "initialize failed #{a.contents}") a = Revision.new("2.4.8") b = Revision.new(a) assert_equal([2,4,8], b.contents, "initialize failed #{a.contents}") a = Revision.new(2.3) assert_equal([2,3], a.contents, "initialize failed #{a.contents}") end def test_equal a = Revision.new("1.2.1") b = Revision.new("1.2.1") assert(a == b, "supposedly identical Revisions #{a} and #{b} are not.") a = Revision.new("2.2.2") b = Revision.new("2.2.1") assert(!(a == b), "supposedly noninidentical Revisions #{a} and #{b} are.") end def test_less_than a = Revision.new("1.2.1") b = Revision.new("1.2.2") assert(a < b, " 1.2.1 not less that 1.2.2 ") a = Revision.new("1.2.2") b = Revision.new("1.3.2") assert(a < b, " 1.2.2 not less that 1.3.2 ") a = Revision.new("1.2.2") b = Revision.new("2.2.2") assert(a < b, " 1.2.2 not less that 2.2.2 ") a = Revision.new("1.2.3.4") b = Revision.new("1.2.3.5") assert(a < b, " 1.2.3.4 not less that 1.2.3.5 ") a = Revision.new("1.2.3") b = Revision.new("1.2.3.5") assert(a < b, " 1.2.3 not less that 1.2.3.5 ") # check comparison is numeric, not lexical a = Revision.new("1.2.3") b = Revision.new("1.12.3") assert(a < b, " 1.2.3 not less that 1.2.3.5 ") end def test_greater_than a = Revision.new("1.2.2") b = Revision.new("1.2.1") assert(a > b, " 1.2.1 not less that 1.2.2 ") a = Revision.new("1.3.2") b = Revision.new("1.2.2") assert(a > b, " 1.2.2 not less that 1.3.2 ") a = Revision.new("2.2.2") b = Revision.new("1.2.2") assert(a > b, " 1.2.2 not less that 2.2.2 ") a = Revision.new("1.2.3.5") b = Revision.new("1.2.3.4") assert(a > b, " 1.2.3.4 not less that 1.2.3.5 ") a = Revision.new("1.2.3.5") b = Revision.new("1.2.3") assert(a > b, " 1.2.3 not less that 1.2.3.5 ") # check comparison is numeric, not lexical a = Revision.new("1.12.3") b = Revision.new("1.2.3") assert(a > b, " 1.2.3 not less that 1.2.3.5 ") end end RUNIT::CUI::TestRunner.run(Testing_class.suite) end which gives me: brains hgs 94 %> ./!$ ./revision.rb Testing_class#test_constructor . Testing_class#test_equal . Testing_class#test_greater_than . Testing_class#test_less_than . Time: 0.027547 OK (4/4 tests 17 asserts) brains hgs 95 %> Hugh