instiki/vendor/plugins/rexml/lib/require_with_version.rb

168 lines
6.9 KiB
Ruby
Raw Normal View History

# 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