38ae064b8a
Sam Ruby has been doing a bang-up job fixing the bugs in REXML. Who knows when these improvements will trickle down to vendor distributions of Ruby. In the meantime, let's bundle the latest version of REXML with Instiki. We check the version number of the bundled REXML against that of the System REXML, and use whichever is later.
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
|