module Rubinius class CodeLoader def self.registry Rubinius.synchronize(self) { @registry ||= [] } end def self.loading?(path) feature = nil resource = Feature.new path if resource.loadable? or resource.search feature = resource.feature end unless feature resource = Library.new path if resource.loadable? or resource.search feature = resource.feature end end if feature Rubinius.synchronize(registry) do return true if registry.include? feature end end false end class Resource attr_reader :feature def initialize(stem, ext) stem = Type.coerce_to_path stem stem = "#{stem}#{ext}" unless stem.suffix? ext @relative = false if stem[0] == ?~ @prefix = "" stem = File.expand_path stem elsif stem[0] == ?/ @prefix = "" elsif stem[0] == ?. and (stem[1] == ?/ or (stem[1] == ?. and stem[2] == ?/)) @relative = true @prefix = Dir.pwd else @prefix = nil end @stem = stem @feature = nil @record = true end private :initialize def resolve return true if loadable? return true if search return false end def search return false if @relative $LOAD_PATH.each do |dir| if dir[-1] == ?/ @prefix = dir[0...-1] else @prefix = dir end return true if loadable? end return false end def loadable? feature = "#{@prefix}/#{@stem}" stat = File::Stat.stat feature if stat and stat.file? and stat.readable? @feature = File.expand_path feature return true else return false end end def unload_feature Rubinius.synchronize($LOADED_FEATURES) do $LOADED_FEATURES.delete_if { |f| f == @feature } end end end class Source < Resource def initialize(stem, ext) super stem, ext @code = nil end private :initialize def load if @code @feature = @code.file.to_s else @code = ToolSets::Runtime::Compiler.compile_file @feature CoreDB.store @code, @stem, @prefix, @feature, @record end run_script return true end def make_script script = @code.create_script @wrap script.file_path = script.data_path = @code.file.to_s script end def run_script make_script Rubinius.run_script @code rescue Object unload_feature raise end end class Feature < Source def initialize(stem) super stem, CodeLoader.source_extension end private :initialize def resolve @code = CoreDB.load_feature @stem, CodeLoader.source_extension, false, @record return true if @code or false.equal? @code return true if loadable? return true if search return false end def load return false if false.equal? @code super() end end class CodeModule < Source def initialize(stem, wrap) super stem, "" @wrap = wrap @record = false end private :initialize def resolve @code = CoreDB.load_feature @stem, CodeLoader.source_extension, true, @record return true if @code return true if loadable? return true if search @prefix = Dir.pwd return true if loadable? return false end end class Script < Source def initialize(stem) super File.expand_path(stem), "" @file = stem @record = false end private :initialize def resolve @code = CoreDB.load_feature @stem, "", true, @record return true if @code return true if loadable? return false end def make_script script = super() script.file_path = @file script.make_main! end end class Library < Resource def initialize(stem) if stem.suffix? ".so" super stem[0...-3], CodeLoader.library_extension else super stem, CodeLoader.library_extension end end private :initialize def load CoreDB.store nil, @stem, @prefix, @feature, @record name = File.basename @feature, CodeLoader.library_extension NativeMethod.load_extension(@feature, name) return true rescue Object unload_feature raise end end def self.source_extension ".rb" end def self.library_extension LIBSUFFIX end # Loads rubygems using the bootstrap standard library files. def self.load_rubygems require "rubygems" end # Loads the pre-compiled bytecode compiler. Sets up paths needed by the # compiler to find dependencies like the parser. def self.load_compiler begin require "rubinius/code/toolset" ToolSets.create :runtime do begin require "rubinius/code/melbourne" rescue LoadError STDERR.puts "Melbourne failed to load, Ruby source parsing disabled" end require "rubinius/code/processor" require "rubinius/code/compiler" require "rubinius/code/ast" end rescue Object => e raise LoadError, "Unable to load the bytecode compiler", e end end def initialize(stem) @stem = stem end private :initialize def load_script resource = Script.new @stem load_error unless resource.resolve resource.load end def load(wrap) resource = CodeModule.new @stem, wrap load_error unless resource.resolve resource.load end def require resource = Feature.new @stem if resource.resolve register_file resource.feature return resource.load end resource = Library.new @stem if resource.resolve register_file resource.feature return resource.load end load_error ensure unregister_file resource.feature if resource end def require_relative(scope) script = scope.current_script if script if script.data_path path = File.dirname(File.realdirpath(script.data_path)) else path = Dir.pwd end @stem = File.expand_path(@stem, path) require else raise LoadError.new "unable to get relative path" end end def register_file(path) registry = self.class.registry Rubinius.synchronize(registry) do registry << path end end def unregister_file(path) registry = self.class.registry Rubinius.synchronize(registry) do registry.delete_if { |x| x == path } end end def load_error # Some versions of Rails override LoadError.new but do NOT override # LoadError.exception, so we must use LoadError.new here to match MRI # behavior. raise LoadError.new("no such file to load -- #{@stem}", path: @stem) end end end