Consider the following code:
a.rb: puts "a"
b.rb: require 'a' puts "b"
test.rb: require './a' require './b'
This will print:
a a bbecause a.rb is loaded first by the name 'a.rb' and then by the name './a.rb'. This is probably not what is intended, and the only workarounds are:
The above code is probably not a good idea to begin with (requring files from the current directory is bad, in case the user runs from a different directory than expected), but it is a simple way to demonstrate the problem.
def find_file_in_path(file, path=$:, extensions=['', '.so', '.rb']) path.each do |dir| pathname = File.join(dir, file) extensions.each do |ext| filename = pathname + ext if File.exists?(filename) then return File.expand_path(filename) end end end return file end def realpath(file) if not File.respond_to?(:readlink) then return file end total = '' File.expand_path(file).split(File::SEPARATOR).each do |piece| next if piece == "" if File.symlink?(total + File::SEPARATOR + piece) then total += File::SEPARATOR + piece begin total = File.expand_path( File.readlink(total), File.dirname(total)) end while File.symlink?(total) else total << File::SEPARATOR + piece end end return total end $__old_require__ = method(:require) def require(file) file_to_require = find_file_in_path(file) $__old_require__.call(realpath(file_to_require)) end
I'd also like to see __FILE__ normalised in this way. While researching an RCR that I'm preparing, I found the following:
I have C:/home/x/x.rb:
require "y/x.rb" puts "In x.rb, __FILE__ = #{FILE}"
I also have C:/home/x/y/x.rb:
puts "In y/x.rb, __FILE__ = #{FILE}"
If I run from C:/home/x, I get:
In y/x.rb, __FILE__ = ./y/x.rb In x.rb, __FILE__ = \C:/home/x/x.rb
Changing the require in C:/home/x/x.rb to "x/y/x.rb" and running from C:/home, I get:
In y/x.rb, __FILE__ = ./x/y/x.rb In x.rb, __FILE__ = \C:/home/x/x.rb
Restoring the require to "y/x.rb" and running from C:/home with "ruby -Ic:/home/x" shows:
In y/x.rb, __FILE__ = x/y/x.rb In x.rb, __FILE__ = x/x.rb
Same, but from C:\Windows ("ruby -I\home\x \home\x\x.rb"):
In y/x.rb, __FILE__ = \home\x/y/x.rb In x.rb, __FILE__ = /home/x/x.rb
This seems a bit ... ugly. I'm not completely sure that __FILE__ itself should be fully resolved, but it seems that there's something odd here.
--Austin
The API for "require" is
require <feature>
not <filename>.
Although the implementation concatenate the feature name and path in $LOAD_PATH variable to find loading library file, it does not stop being feature name. When you require two libraries "a" and "./a", they might be different just because you're requiring two different features.
But I'm going to store full path used to load a library in the $" variable (but no normalization), to implement requiring libraries relative from __FILE__.
-- matz.
Back to RCRchive.
RCR Submission page and RCRchive powered by Ruby, Apache, RuWiki (modified), and RubLog