Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow setting different namespace root #3

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/im/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ def initialize
end
end

class SetupFinished < Error
end

class InvalidModuleName < Error
end
end
6 changes: 5 additions & 1 deletion lib/im/kernel.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@ def require(path)
if loaded = !$LOADED_FEATURES.include?(feature_path)
$LOADED_FEATURES << feature_path
begin
load path, loader
if loader.root == Object
load path
else
load path, loader.root
end
rescue => e
$LOADED_FEATURES.delete(feature_path)
raise e
Expand Down
18 changes: 14 additions & 4 deletions lib/im/loader.rb
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,11 @@ def pretty_print(q)
# @sig Mutex
attr_reader :mutex2

def initialize
# @private
# @sig Module
attr_reader :root

def initialize(root: self)
super

@module_prefix = "#{Im.cpath(self)}::"
Expand All @@ -125,13 +129,19 @@ def initialize
@module_cpaths = {}
@mutex = Mutex.new
@mutex2 = Mutex.new
@root = root
@setup = false
@eager_loaded = false

Registry.register_loader(self)
Registry.register_autoloaded_module(get_object_hash(self), nil, self)
end

def root=(root)
raise SetupFinished, "cannot set root after setup" if @setup
@root = root
end

# Sets autoloads in the root namespaces.
#
# @sig () -> void
Expand Down Expand Up @@ -351,7 +361,7 @@ def all_dirs
private # -------------------------------------------------------------------------------------

# @sig (String, Module?) -> void
def set_autoloads_in_dir(dir, parent = self)
def set_autoloads_in_dir(dir, parent = root)
ls(dir) do |basename, abspath|
begin
if ruby?(basename)
Expand Down Expand Up @@ -517,15 +527,15 @@ def raise_if_conflicting_directory(dir)

# @sig (Module, Symbol) -> String
def relative_cpath(parent, cname)
if self == parent
if root == parent
cname.to_s
elsif module_cpaths.key?(get_object_hash(parent))
"#{module_cpaths[get_object_hash(parent)]}::#{cname}"
else
# If an autoloaded file loads an autoloaded constant from another file, we need to deduce the module name
# before we can add the parent to module_cpaths. In this case, we have no choice but to work from to_s.
mod_name = Im.cpath(parent)
current_module_prefix = "#{Im.cpath(self)}::"
current_module_prefix = "#{Im.cpath(root)}::"
raise InvalidModuleName, "invalid module name for #{parent}" unless mod_name.start_with?(current_module_prefix)
"#{mod_name}::#{cname}".delete_prefix!(current_module_prefix)
end
Expand Down
2 changes: 1 addition & 1 deletion lib/im/loader/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ module Im::Loader::Config
attr_reader :on_unload_callbacks
private :on_unload_callbacks

def initialize
def initialize(root: self)
@inflector = Im::Inflector.new
@logger = self.class.default_logger
@tag = SecureRandom.hex(3)
Expand Down
26 changes: 26 additions & 0 deletions test/lib/im/test_different_root.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
require "test_helper"

class TestDifferentRoot < LoaderTest
test "setting a different root for loader" do
files = [["foo.rb", "module Foo; end"]]

mod = Module.new
@loader = new_loader(root: mod, setup: false)

with_setup(files) do
assert mod::Foo
end
end

test "setting Object as root" do
on_teardown { remove_const :Foo, from: Object }

files = [["foo.rb", "module Foo; end"]]

@loader = new_loader(root: Object, setup: false)

with_setup(files) do
assert ::Foo
end
end
end
3 changes: 2 additions & 1 deletion test/support/loader_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ def setup
@loader = new_loader(setup: false)
end

def new_loader(dirs: [], enable_reloading: true, setup: true)
def new_loader(dirs: [], enable_reloading: true, setup: true, root: nil)
Im::Loader.new.tap do |loader|
Array(dirs).each { |dir| loader.push_dir(dir) }
loader.enable_reloading if enable_reloading
loader.root = root if root
loader.setup if setup
end
end
Expand Down