lib/fast_require.rb in fast_require-0.0.0 vs lib/fast_require.rb in fast_require-0.3.3
- old
+ new
@@ -1,63 +1,200 @@
module FastRequire
+ $FAST_REQUIRE_DEBUG ||= false
+ def self.setup
+ @@dir = File.expand_path('~/.ruby_fast_require_cache')
- @@loc = File.expand_path('~/.ruby_fast_require_location')
- if File.exist? (@@loc)
- @@require_locs = Marshal.restore( File.open(@@loc, 'rb') {|f| f.read})
+ Dir.mkdir @@dir unless File.directory?(@@dir)
+ @@loc = @@dir + '/' + RUBY_VERSION + '-' + RUBY_PLATFORM + '-' + sanitize(File.expand_path($0).gsub(/[\/:]/, '_')) + sanitize(Dir.pwd)
+ end
+
+ def self.sanitize filename
+ filename.gsub(/[\/:]/, '_')
+ end
+
+ FastRequire.setup
+
+ if File.exist?(@@loc)
+ @@require_locs = Marshal.restore( File.open(@@loc, 'rb') {|f| f.read})
else
@@require_locs = {}
end
@@already_loaded = {}
- $LOADED_FEATURES.each{|loaded| @@already_loaded[loaded] = true}
+ # try to see where this file was loaded from, from $:
+ # partial_name might be abc.rb, or might be abc
+ # partial_name might be a full path, too
+ def self.guess_discover partial_name, add_dot_rb = false
+
+ # test for full path first
+ # unfortunately it has to be a full separate test
+ # for windoze sake, as drive letter could be different than slapping a '/' on the dir to test list...
+ tests = [partial_name]
+
+ if add_dot_rb
+ tests << partial_name + '.rb'
+ tests << partial_name + '.so'
+ end
+
+ tests.each{|b|
+ # assume that .rb.rb is...valid...
+ if File.file?(b) && ((b[-3..-1] == '.rb') || (b[-3..-1] == '.so'))
+ return File.expand_path(b)
+ end
+ }
+
+ for dir in $:
+ if File.file?(b = (dir + '/' + partial_name))
+ # make sure we require a file that has the right suffix...
+ if (b[-3..-1] == '.rb') || (b[-3..-1] == '.so')
+ return File.expand_path(b)
+ end
+
+ end
+ end
+
+ if add_dot_rb && (partial_name[-3..-1] != '.rb') && (partial_name[-3..-1] != '.so')
+ guess_discover(partial_name + '.rb') || guess_discover(partial_name + '.so')
+ else
+ nil
+ end
+ end
+
+ $LOADED_FEATURES.each{|already_loaded|
+ # in 1.8 they might be partial paths
+ # in 1.9, they might be non collapsed paths
+ # so we have to sanitize them here...
+ # XXXX File.exist? is a bit too loose, here...
+ if File.exist?(already_loaded)
+ key = File.expand_path(already_loaded)
+ else
+ key = FastRequire.guess_discover(already_loaded) || already_loaded
+ end
+ @@already_loaded[key] = true
+ }
+
+ @@already_loaded[File.expand_path(__FILE__)] = true # this file itself isn't in loaded features, yet, but very soon will be..
+ # special case--I hope...
+
+ # disallow re-requiring $0
+ @@require_locs[$0] = File.expand_path($0) # so when we run into it on a require, we will skip it...
+ @@already_loaded[File.expand_path($0)] = true
+
+
+ # XXXX within a very long depth to require fast_require,
+ # require 'a' => 'b' => 'c' => 'd' & fast_require
+ # then
+ # => 'b.rb'
+ # it works always
+
+ def self.already_loaded
+ @@already_loaded
+ end
+
+ def self.require_locs
+ @@require_locs
+ end
+
+ def self.dir
+ @@dir
+ end
+
at_exit {
FastRequire.save
}
def self.save
File.open(@@loc, 'wb'){|f| f.write Marshal.dump(@@require_locs)}
end
- def self.clear!
+ def self.clear_all!
require 'fileutils'
- FileUtils.rm @@loc if File.exist? @@loc
+ FileUtils.rm_rf @@dir if File.exist? @@dir
@@require_locs.clear
+ setup
end
def require_cached lib
- if a = @@require_locs[lib]
- return if @@already_loaded[a]
- @@already_loaded[a] = true
- if a =~ /.so$/
- puts 'doing original require on full path' if $DEBUG
- original_non_cached_require a # not much we can do there...too bad...
+ lib = lib.to_s unless lib.is_a?(String) # might not be zactly 1.9 compat...
+ if known_loc = @@require_locs[lib]
+ return false if @@already_loaded[known_loc]
+ @@already_loaded[known_loc] = true
+ if known_loc =~ /.so$/
+ puts 'doing original_non_cached_require on .so full path ' + known_loc if $FAST_REQUIRE_DEBUG
+ original_non_cached_require known_loc # not much we can do there...too bad...
else
- puts 'doing eval on ' + lib + '=>' + a if $DEBUG
- eval(File.open(a, 'rb') {|f| f.read}, TOPLEVEL_BINDING, a) # note the b here--this means it's reading .rb files as binary, which *typically* works--if it breaks re-save the offending file in binary mode...
- $LOADED_FEATURES << a
- end
+ puts 'doing eval on ' + lib + '=>' + known_loc if $FAST_REQUIRE_DEBUG
+ $LOADED_FEATURES << known_loc # *must*
+ return eval(File.open(known_loc, 'rb') {|f| f.read}, TOPLEVEL_BINDING, known_loc) || true # note the b here--this means it's reading .rb files as binary, which *typically* works--if it breaks re-save the offending file in binary mode, or file an issue on the tracker...
+ end
else
+ # we don't know the location--let Ruby's original require do the heavy lifting for us here
old = $LOADED_FEATURES.dup
if(original_non_cached_require lib)
+ # debugger might land here the first time you run a script and it doesn't have a require
+ # cached yet...
new = $LOADED_FEATURES - old
- @@require_locs[lib] = new.last
- puts 'found new loc:' + lib + '=>' + @@require_locs[lib] if $DEBUG
- @@already_loaded[@@require_locs[lib]] = true
- end# how could this fail, though...
+ found = new.last
+
+ # incredibly, in 1.8.6, this doesn't always get set to a full path
+ if RUBY_VERSION < '1.9'
+ if !File.file?(found)
+ # discover the full path.
+ dir = $:.find{|path| File.file?(path + '/' + found)}
+ found = dir + '/' + found
+ end
+ found = File.expand_path(found);
+ end
+ puts 'found new loc:' + lib + '=>' + found if $FAST_REQUIRE_DEBUG
+ @@require_locs[lib] = found
+ @@already_loaded[found] = true
+ return true
+ else
+ puts 'already loaded, apparently' + lib if $FAST_REQUIRE_DEBUG
+ # this probably was something like
+ # the first pass was require 'regdeferred'
+ # now it's a different require 'regdeferred.rb'
+ # which fails (or vice versa)
+ # so figure out why
+ # calc location, expand, map back
+ where_found = FastRequire.guess_discover(lib, true)
+ if where_found
+ puts 'inferred ghost loc:' + lib + '=>' + where_found if $FAST_REQUIRE_DEBUG
+ @@require_locs[lib] = where_found
+ # unfortunately if it's our first pass
+ # and we are in the middle of a "real" require
+ # that is circular
+ # then $LOADED_FEATURES or (AFAIK) nothing will have been set
+ # for us to be able to assert that
+ # so...I think we'll end up
+ # just fudging for a bit
+ # raise 'not found' unless @@already_loaded[where_found] # should have already been set...I think...
+ else
+ if $FAST_REQUIRE_DEBUG
+ # happens for enumerator XXXX
+ puts 'unable to infer' + lib + ' in ' if $FAST_REQUIRE_DEBUG
+ end
+ end
+ return false # XXXX test all these return values
+ end
end
-
end
+
+ def self.resetup!
+ eval "module ::Kernel; alias :require :require_cached; end"
+ end
end
module Kernel
-
+
if(defined?(@already_using_fast_require))
- raise 'cant require it twice...'
+ raise 'twice not allowed...'
+ # *shouldn't* get here...unless I'm wrong...
else
@already_using_fast_require = true
+ include FastRequire
+ # overwrite old require...
+ alias :original_non_cached_require :require
+ FastRequire.resetup!
end
-
- include FastRequire
- # overwrite require...
- alias :original_non_cached_require :require
- alias :require :require_cached
-end
\ No newline at end of file
+
+end