168 lines
6.9 KiB
Ruby
168 lines
6.9 KiB
Ruby
|
# FUNDAMENTAL FLAWS:
|
||
|
# The order of $: must be preserved. Therefore, there are two sort
|
||
|
# criteria: Versioned files are sorted high; after that, the sort order
|
||
|
# is the order of $:.
|
||
|
# We must preserve the load path; if rexml-2.4 is required in one place,
|
||
|
# all rexml/* packages should be loaded from there.
|
||
|
############################################################################
|
||
|
# #
|
||
|
# This is based on Phil Tomson's #
|
||
|
# ("ptkwt!shell1#aracnet#com".tr("!#","@.")) #
|
||
|
# code. The changes I made are: #
|
||
|
# 1) The Version class is now a member of the Kernel module, to avoid #
|
||
|
# name space conflicts. #
|
||
|
# 2) Version::to_s() returns the original string, not a comma-separated #
|
||
|
# string. #
|
||
|
# 3) The versioning is package based, not file based. In fact, with #
|
||
|
# this, you can't version individual files. AFAIC, this is better, #
|
||
|
# since versioning on individual files is much more tedious than #
|
||
|
# package-based versioning, and it is arguably less useful and less #
|
||
|
# commonly desired. #
|
||
|
# 4) Versions can have arbitrary length. EG: 2.7 < 2.7.1, and "2" #
|
||
|
# matches any version that starts with "2", such as "2.5.2.6.7" #
|
||
|
# #
|
||
|
# The rules are these: #
|
||
|
# 1) All of the locations in $: will be searched #
|
||
|
# 2) The highest version of the package found that satisfies the #
|
||
|
# requirements will be used. #
|
||
|
# 3) If there is no versioned package, or no version matches, we default #
|
||
|
# to the normal Ruby require mechanism. This maintains backward #
|
||
|
# compatible behavior. #
|
||
|
# 4) The packages must be installed as foo-x.y.z. The cardinality of #
|
||
|
# the version is not significant, and packages that do not match this #
|
||
|
# naming pattern match by default. #
|
||
|
# #
|
||
|
# Rule (1) and (2) mean that the highest matching version anywhere in #
|
||
|
# the search path will be used. Rule (3) and (4) mean that even if #
|
||
|
# packages are not installed with this naming convention, programs that #
|
||
|
# use require_version will still work. #
|
||
|
# #
|
||
|
# Usage: #
|
||
|
# To use this, require this module. Then use require_with_ver, instead #
|
||
|
# of require in your files. #
|
||
|
# #
|
||
|
# Examples: #
|
||
|
# require_version('rexml/document'){|v| v > '2.0' and v < '2.5'} #
|
||
|
# require_version('rexml/document'){|v| v > '2.0'} #
|
||
|
# require_version('rexml/document') #
|
||
|
# require_version('rexml/document'){|v| v > '2.0'} #
|
||
|
# require_version('rexml/document'){|v| v >= '1.0' and v < '2.0'} #
|
||
|
# require_version('rexml/document'){|v| v >= '1.0' and v < '2.0' and #
|
||
|
# v != '1.7'} #
|
||
|
# require_version('rexml/document'){|v| (v >= '1.0' and #
|
||
|
# v < '2.0' and #
|
||
|
# v != '1.7') or #
|
||
|
# v == '3.0.1'} #
|
||
|
# require_version('rexml/document'){|v| v.to_s =~ /^2.[02468]/} #
|
||
|
# #
|
||
|
############################################################################
|
||
|
|
||
|
module Kernel
|
||
|
#########################################################
|
||
|
# 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|
|
||
|
return 1 unless other[i]
|
||
|
unless v == other[i]
|
||
|
return v <=> other[i]
|
||
|
end
|
||
|
}
|
||
|
return 0
|
||
|
end
|
||
|
end
|
||
|
|
||
|
alias :old_require :require
|
||
|
|
||
|
@@__versioned__ = {}
|
||
|
def require(file,&b)
|
||
|
path = file.split('/')
|
||
|
root = path[0]
|
||
|
rest = path[1..-1].join('/')
|
||
|
unless @@__versioned__[root]
|
||
|
package = File.dirname( file )
|
||
|
files = []
|
||
|
$:.each {|dir|
|
||
|
if File.exists? dir
|
||
|
fileset = Dir.new(dir).entries.delete_if {|f|
|
||
|
fpath = File.join( dir, f )
|
||
|
!(File.directory?(fpath) and f =~ /^#{root}(-\d(\.\d)*)?$/)
|
||
|
}
|
||
|
fileset.collect!{ |f| File.join( dir, f ) }
|
||
|
files += fileset
|
||
|
end
|
||
|
}
|
||
|
if files.size > 0
|
||
|
@@__versioned__[root] = files.uniq.sort{|x,y|
|
||
|
File.basename(x) <=> File.basename(y)
|
||
|
}
|
||
|
@@__versioned__[root].reverse!
|
||
|
else
|
||
|
@@__versioned__[root] = [root]
|
||
|
end
|
||
|
end
|
||
|
base = @@__versioned__[root][0]
|
||
|
if b #block_given?
|
||
|
p @@__versioned__[root]
|
||
|
base = @@__versioned__[root].delete_if { |f|
|
||
|
l = File.basename(f)
|
||
|
l.include?('-') and yield( Version.new( l.split('-')[1] ) ) and
|
||
|
Dir.new(f).entries.include?( rest+".rb" ) ? false : true
|
||
|
}
|
||
|
p base
|
||
|
base = base[0]
|
||
|
end
|
||
|
#old_require "#{base}/#{rest}"
|
||
|
puts <<-EOL
|
||
|
old_require "#{base}/#{rest}"
|
||
|
EOL
|
||
|
end
|
||
|
end
|
||
|
|
||
|
#=begin
|
||
|
# For testing
|
||
|
if $0 == __FILE__
|
||
|
$: << "./"
|
||
|
puts "\n\nv > '2.0' and v < '2.5'"
|
||
|
require('rexml/document'){|v| v > '2.0' and v < '2.5'}
|
||
|
puts "\n\nv > '2.0' and v < '3'"
|
||
|
require('rexml/document'){|v| v > '2.0' and v < '3'}
|
||
|
=begin
|
||
|
puts "\n\nv > '2.0'"
|
||
|
require('rexml/document'){|v| v > '2.0'}
|
||
|
require('rexml/document')
|
||
|
puts "\n\nv > '2.0'"
|
||
|
require('rexml/document'){|v| v > '2.0'}
|
||
|
puts "\n\nv >= '1.0' and v < '2.0'"
|
||
|
require('rexml/document'){|v| v >= '1.0' and v < '2.0'}
|
||
|
puts "\n\nv >= '1.0' and v < '2.0' and v != '1.7'"
|
||
|
require('rexml/document'){|v| v >= '1.0' and v < '2.0' and v != '1.7'}
|
||
|
require('rexml/document'){|v| (v >= '1.0' and
|
||
|
v < '2.0' and
|
||
|
v != '1.7') or
|
||
|
v == '3.0.1'}
|
||
|
puts "\n\nv.to_s =~ /^2.[02468]/"
|
||
|
require('rexml/document'){|v| v.to_s =~ /^2.[02468]/}
|
||
|
require('rexml/parsers/baseparser' )
|
||
|
=end
|
||
|
end
|
||
|
#=end
|