From: ptkwt@...1.aracnet.com (Phil Tomson) Date: 2003-04-09T06:36:25+09:00 Subject: Versioning prototype for discussion I was looking at the latest post on Rubygarden about versioning support in 'require' and I came up with a prototype. Actually, I came up with something called 'require_with_ver' which is used like: require_with_ver('foo') {|v| v >= '0.1.2'} (BTW: anyone know how I can get away from needing the parenthesis in the above? so that it would be: require_with_ver 'foo' {|v| v >= '0.1.2' } ) I'm including the implementation here in the hopes that it'll spark some discussion that will hopefully lead to some useful versioning support in 'require' (or a new 'require'). Here's the code (NOTE: I'm sure there are problems with this code, I wrote it in about 15 minutes and haven't had much chance to test it. Certainly there should be some exceptions raised for some conditions.): #####################################################33 # Version - takes a string in the form: 'X1.X2.X3...Xn' # (where 'Xn' is a number) # ##################################################### class Version include Comparable def initialize(str) @vs = str.split('.').map!{|i| i.to_i} end def [](i) @vs[i] end def to_s @vs.join('.') end def <=>(other) if other.class == String other = Version.new(other) end @vs.each_with_index { |v,i| unless v == other[i] return v <=> other[i] end } return 0 end end module Kernel def require_with_ver(file,&b) if b puts "block given" dir = "" files = [] $:.each {|dir| files = Dir[file+"*"] if files.length > 0 break end } p files files.each { |f| if b.call(Version.new(f.split('-')[1].split(/.rb/)[0])) puts "require '#{f}'" require f return end } else puts "require '#{file}'" require file end end end if $0 == __FILE__ $: << "./" require_with_ver('foo') { |v| v > '0.1.1' } # ^-----^ <- how to 'optionalize' the parens? # without them I get a syntax error end With foo-0.1.1.rb and foo-0.1.2.rb in the current directory, the output I get is: require 'foo-0.1.2.rb' The advantages I see to using this approach of taking a block and using it to determine which version to require: 1) It's easy to implement and because of the Version class there's no parsing to do (well, Version takes care of some simple parsing). 2) it's powerful because you could put just about any kind of expression you'd like in the block. 3) it's the Ruby way to do it ;-) Disadvantages? Phil