Initialize the main namespace after loading builtin libraries

* For having the common set of loaded libraries between root and main namespaces
* To have the consistent $LOADED_FEATURES in the main namespace
This commit is contained in:
Satoshi Tagomori 2025-10-07 12:38:27 +09:00 committed by Satoshi Tagomori
parent 0f05979299
commit 52c6b32f80
Notes: git 2025-10-07 05:21:09 +00:00
3 changed files with 56 additions and 1 deletions

View File

@ -761,6 +761,9 @@ rb_initialize_main_namespace(void)
rb_const_set(rb_cNamespace, rb_intern("MAIN"), main_ns);
vm->main_namespace = main_namespace = ns;
// create the writable classext of ::Object explicitly to finalize the set of visible top-level constants
RCLASS_EXT_WRITABLE_IN_NS(rb_cObject, ns);
}
static VALUE

5
ruby.c
View File

@ -1826,10 +1826,13 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
GET_VM()->running = 1;
memset(ruby_vm_redefined_flag, 0, sizeof(ruby_vm_redefined_flag));
ruby_init_prelude();
/* Initialize the main namespace after loading libraries (including rubygems)
* to enable those in both root and main */
if (rb_namespace_available())
rb_initialize_main_namespace();
rb_namespace_init_done();
ruby_init_prelude();
// Initialize JITs after ruby_init_prelude() because JITing prelude is typically not optimal.
#if USE_YJIT

View File

@ -3,6 +3,10 @@
require 'test/unit'
class TestNamespace < Test::Unit::TestCase
EXPERIMENTAL_WARNINGS = [
"warning: Namespace is experimental, and the behavior may change in the future!",
"See doc/namespace.md for known issues, etc."
].join("\n")
ENV_ENABLE_NAMESPACE = {'RUBY_NAMESPACE' => '1'}
def setup
@ -534,6 +538,51 @@ class TestNamespace < Test::Unit::TestCase
assert !$LOADED_FEATURES.include?(File.join(namespace_dir, 'blank2.rb'))
end
def test_prelude_gems_and_loaded_features
assert_in_out_err([ENV_ENABLE_NAMESPACE, "--enable=gems"], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error|
begin;
puts ["before:", $LOADED_FEATURES.select{ it.end_with?("/bundled_gems.rb") }&.first].join
puts ["before:", $LOADED_FEATURES.select{ it.end_with?("/error_highlight.rb") }&.first].join
require "error_highlight"
puts ["after:", $LOADED_FEATURES.select{ it.end_with?("/bundled_gems.rb") }&.first].join
puts ["after:", $LOADED_FEATURES.select{ it.end_with?("/error_highlight.rb") }&.first].join
end;
# No additional warnings except for experimental warnings
assert_includes error.join("\n"), EXPERIMENTAL_WARNINGS
assert_equal error.size, 2
assert_includes output.grep(/^before:/).join("\n"), '/bundled_gems.rb'
assert_includes output.grep(/^before:/).join("\n"), '/error_highlight.rb'
assert_includes output.grep(/^after:/).join("\n"), '/bundled_gems.rb'
assert_includes output.grep(/^after:/).join("\n"), '/error_highlight.rb'
end
end
def test_prelude_gems_and_loaded_features_with_disable_gems
assert_in_out_err([ENV_ENABLE_NAMESPACE, "--disable=gems"], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error|
begin;
puts ["before:", $LOADED_FEATURES.select{ it.end_with?("/bundled_gems.rb") }&.first].join
puts ["before:", $LOADED_FEATURES.select{ it.end_with?("/error_highlight.rb") }&.first].join
require "error_highlight"
puts ["after:", $LOADED_FEATURES.select{ it.end_with?("/bundled_gems.rb") }&.first].join
puts ["after:", $LOADED_FEATURES.select{ it.end_with?("/error_highlight.rb") }&.first].join
end;
assert_includes error.join("\n"), EXPERIMENTAL_WARNINGS
assert_equal error.size, 2
refute_includes output.grep(/^before:/).join("\n"), '/bundled_gems.rb'
refute_includes output.grep(/^before:/).join("\n"), '/error_highlight.rb'
refute_includes output.grep(/^after:/).join("\n"), '/bundled_gems.rb'
assert_includes output.grep(/^after:/).join("\n"), '/error_highlight.rb'
end
end
def test_eval_basic
pend unless Namespace.enabled?