Skip to content
2 changes: 1 addition & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ The following default gems are updated.
* resolv 0.6.2
* stringio 3.1.8.dev
* strscan 3.1.6.dev
* uri 1.0.3
* uri 1.0.4
* weakref 0.1.4

The following bundled gems are added.
Expand Down
14 changes: 10 additions & 4 deletions internal/class.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,26 +336,31 @@ RCLASS_SET_NAMESPACE_CLASSEXT(VALUE obj, const rb_namespace_t *ns, rb_classext_t
return first_set;
}

#define VM_ASSERT_NAMESPACEABLE_TYPE(klass) \
VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS), "%s is not namespaceable type", rb_type_str(BUILTIN_TYPE(klass)))

static inline bool
RCLASS_PRIME_CLASSEXT_READABLE_P(VALUE klass)
{
VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
VM_ASSERT(klass != 0, "klass should be a valid object");
VM_ASSERT_NAMESPACEABLE_TYPE(klass);
// if the lookup table exists, then it means the prime classext is NOT directly readable.
return !FL_TEST_RAW(klass, RCLASS_NAMESPACEABLE) || RCLASS_CLASSEXT_TBL(klass) == NULL;
}

static inline bool
RCLASS_PRIME_CLASSEXT_WRITABLE_P(VALUE klass)
{
VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));
VM_ASSERT(klass != 0, "klass should be a valid object");
VM_ASSERT_NAMESPACEABLE_TYPE(klass);
return FL_TEST(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
}

static inline void
RCLASS_SET_PRIME_CLASSEXT_WRITABLE(VALUE klass, bool writable)
{
VM_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS));

VM_ASSERT(klass != 0, "klass should be a valid object");
VM_ASSERT_NAMESPACEABLE_TYPE(klass);
if (writable) {
FL_SET(klass, RCLASS_PRIME_CLASSEXT_WRITABLE);
}
Expand Down Expand Up @@ -429,6 +434,7 @@ RCLASS_EXT_WRITABLE_LOOKUP(VALUE obj, const rb_namespace_t *ns)
ext = rb_class_duplicate_classext(RCLASS_EXT_PRIME(obj), obj, ns);
first_set = RCLASS_SET_NAMESPACE_CLASSEXT(obj, ns, ext);
if (first_set) {
// TODO: are there any case that a class/module become non-writable after its birthtime?
RCLASS_SET_PRIME_CLASSEXT_WRITABLE(obj, false);
}
}
Expand Down
29 changes: 21 additions & 8 deletions lib/uri/generic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -186,18 +186,18 @@ def initialize(scheme,

if arg_check
self.scheme = scheme
self.userinfo = userinfo
self.hostname = host
self.port = port
self.userinfo = userinfo
self.path = path
self.query = query
self.opaque = opaque
self.fragment = fragment
else
self.set_scheme(scheme)
self.set_userinfo(userinfo)
self.set_host(host)
self.set_port(port)
self.set_userinfo(userinfo)
self.set_path(path)
self.query = query
self.set_opaque(opaque)
Expand Down Expand Up @@ -511,7 +511,7 @@ def set_userinfo(user, password = nil)
user, password = split_userinfo(user)
end
@user = user
@password = password if password
@password = password

[@user, @password]
end
Expand All @@ -522,7 +522,7 @@ def set_userinfo(user, password = nil)
# See also URI::Generic.user=.
#
def set_user(v)
set_userinfo(v, @password)
set_userinfo(v, nil)
v
end
protected :set_user
Expand Down Expand Up @@ -574,6 +574,12 @@ def password
@password
end

# Returns the authority info (array of user, password, host and
# port), if any is set. Or returns +nil+.
def authority
return @user, @password, @host, @port if @user || @password || @host || @port
end

# Returns the user component after URI decoding.
def decoded_user
URI.decode_uri_component(@user) if @user
Expand Down Expand Up @@ -615,6 +621,13 @@ def set_host(v)
end
protected :set_host

# Protected setter for the authority info (+user+, +password+, +host+
# and +port+). If +port+ is +nil+, +default_port+ will be set.
#
protected def set_authority(user, password, host, port = nil)
@user, @password, @host, @port = user, password, host, port || self.default_port
end

#
# == Args
#
Expand All @@ -639,6 +652,7 @@ def set_host(v)
def host=(v)
check_host(v)
set_host(v)
set_userinfo(nil)
v
end

Expand Down Expand Up @@ -729,6 +743,7 @@ def set_port(v)
def port=(v)
check_port(v)
set_port(v)
set_userinfo(nil)
port
end

Expand Down Expand Up @@ -1121,7 +1136,7 @@ def merge(oth)

base = self.dup

authority = rel.userinfo || rel.host || rel.port
authority = rel.authority

# RFC2396, Section 5.2, 2)
if (rel.path.nil? || rel.path.empty?) && !authority && !rel.query
Expand All @@ -1134,9 +1149,7 @@ def merge(oth)

# RFC2396, Section 5.2, 4)
if authority
base.set_userinfo(rel.userinfo)
base.set_host(rel.host)
base.set_port(rel.port || base.default_port)
base.set_authority(*authority)
base.set_path(rel.path)
elsif base.path && rel.path
base.set_path(merge_path(base.path, rel.path))
Expand Down
2 changes: 1 addition & 1 deletion lib/uri/version.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module URI
# :stopdoc:
VERSION_CODE = '010003'.freeze
VERSION_CODE = '010004'.freeze
VERSION = VERSION_CODE.scan(/../).collect{|n| n.to_i}.join('.').freeze
# :startdoc:
end
37 changes: 34 additions & 3 deletions namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -755,13 +755,15 @@ rb_initialize_main_namespace(void)
VM_ASSERT(NAMESPACE_OBJ_P(main_ns));
ns = rb_get_namespace_t(main_ns);
ns->ns_object = main_ns;
ns->ns_id = namespace_generate_id();
ns->is_user = true;
ns->is_optional = false;

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
Expand Down Expand Up @@ -843,11 +845,15 @@ rb_namespace_s_main(VALUE recv)
static const char *
classname(VALUE klass)
{
VALUE p = RCLASS_CLASSPATH(klass);
VALUE p;
if (!klass) {
return "Qfalse";
}
p = RCLASSEXT_CLASSPATH(RCLASS_EXT_PRIME(klass));
if (RTEST(p))
return RSTRING_PTR(p);
if (RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE) || RB_TYPE_P(klass, T_ICLASS))
return RSTRING_PTR(rb_inspect(klass));
return "AnyClassValue";
return "NonClassValue";
}

Expand Down Expand Up @@ -971,6 +977,27 @@ rb_f_dump_classext(VALUE recv, VALUE klass)
return res;
}

static VALUE
rb_namespace_root_p(VALUE namespace)
{
const rb_namespace_t *ns = (const rb_namespace_t *)rb_get_namespace_t(namespace);
return RBOOL(NAMESPACE_ROOT_P(ns));
}

static VALUE
rb_namespace_main_p(VALUE namespace)
{
const rb_namespace_t *ns = (const rb_namespace_t *)rb_get_namespace_t(namespace);
return RBOOL(NAMESPACE_MAIN_P(ns));
}

static VALUE
rb_namespace_user_p(VALUE namespace)
{
const rb_namespace_t *ns = (const rb_namespace_t *)rb_get_namespace_t(namespace);
return RBOOL(NAMESPACE_USER_P(ns));
}

#endif /* RUBY_DEBUG */

/*
Expand Down Expand Up @@ -1008,6 +1035,10 @@ Init_Namespace(void)
rb_define_singleton_method(rb_cNamespace, "root", rb_namespace_s_root, 0);
rb_define_singleton_method(rb_cNamespace, "main", rb_namespace_s_main, 0);
rb_define_global_function("dump_classext", rb_f_dump_classext, 1);

rb_define_method(rb_cNamespace, "root?", rb_namespace_root_p, 0);
rb_define_method(rb_cNamespace, "main?", rb_namespace_main_p, 0);
rb_define_method(rb_cNamespace, "user?", rb_namespace_user_p, 0);
#endif
}

Expand Down
5 changes: 4 additions & 1 deletion ruby.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
40 changes: 21 additions & 19 deletions spec/ruby/library/uri/set_component_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,27 @@
it "conforms to the MatzRuby tests" do
uri = URI.parse('http://foo:bar@baz')
(uri.user = 'oof').should == 'oof'
uri.to_s.should == 'http://oof:bar@baz'
(uri.password = 'rab').should == 'rab'
uri.to_s.should == 'http://oof:rab@baz'
(uri.userinfo = 'foo').should == 'foo'
uri.to_s.should == 'http://foo:rab@baz'
(uri.userinfo = ['foo', 'bar']).should == ['foo', 'bar']
uri.to_s.should == 'http://foo:bar@baz'
(uri.userinfo = ['foo']).should == ['foo']
uri.to_s.should == 'http://foo:bar@baz'
(uri.host = 'zab').should == 'zab'
uri.to_s.should == 'http://foo:bar@zab'
(uri.port = 8080).should == 8080
uri.to_s.should == 'http://foo:bar@zab:8080'
(uri.path = '/').should == '/'
uri.to_s.should == 'http://foo:bar@zab:8080/'
(uri.query = 'a=1').should == 'a=1'
uri.to_s.should == 'http://foo:bar@zab:8080/?a=1'
(uri.fragment = 'b123').should == 'b123'
uri.to_s.should == 'http://foo:bar@zab:8080/?a=1#b123'
version_is(URI::VERSION, "1.0.4") do
uri.to_s.should == 'http://oof@baz'
(uri.password = 'rab').should == 'rab'
uri.to_s.should == 'http://oof:rab@baz'
(uri.userinfo = 'foo').should == 'foo'
uri.to_s.should == 'http://foo@baz'
(uri.userinfo = ['foo', 'bar']).should == ['foo', 'bar']
uri.to_s.should == 'http://foo:bar@baz'
(uri.userinfo = ['foo']).should == ['foo']
uri.to_s.should == 'http://foo@baz'
(uri.host = 'zab').should == 'zab'
uri.to_s.should == 'http://zab'
(uri.port = 8080).should == 8080
uri.to_s.should == 'http://zab:8080'
(uri.path = '/').should == '/'
uri.to_s.should == 'http://zab:8080/'
(uri.query = 'a=1').should == 'a=1'
uri.to_s.should == 'http://zab:8080/?a=1'
(uri.fragment = 'b123').should == 'b123'
uri.to_s.should == 'http://zab:8080/?a=1#b123'
end

uri = URI.parse('http://example.com')
-> { uri.password = 'bar' }.should raise_error(URI::InvalidURIError)
Expand Down
1 change: 1 addition & 0 deletions template/fake.rb.in
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class Object
else%><%=v.inspect%><%end%>
% }
end
v=$VERBOSE;$VERBOSE=nil;module Ruby; end;$VERBOSE=v
module Ruby
constants.each {|n| remove_const n}
% arg['versions'].each {|n, v|
Expand Down
49 changes: 49 additions & 0 deletions test/ruby/test_namespace.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -534,6 +538,51 @@ def test_load_path_and_loaded_features
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?

Expand Down
4 changes: 3 additions & 1 deletion test/ruby/test_rubyoptions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ def test_enable
assert_in_out_err(%w(--enable foobarbazqux -e) + [""], "", [],
/unknown argument for --enable: 'foobarbazqux'/)
assert_in_out_err(%w(--enable), "", [], /missing argument for --enable/)
assert_in_out_err(%w(-e) + ['p defined? Gem'], "", %w["constant"], [], gems: true)
assert_in_out_err(%w(-e) + ['p defined? Gem'], "", %w["constant"], [], gems: nil)
end

def test_disable
Expand All @@ -219,7 +221,7 @@ def test_disable
assert_in_out_err(%w(--disable foobarbazqux -e) + [""], "", [],
/unknown argument for --disable: 'foobarbazqux'/)
assert_in_out_err(%w(--disable), "", [], /missing argument for --disable/)
assert_in_out_err(%w(-e) + ['p defined? Gem'], "", ["nil"], [])
assert_in_out_err(%w(-e) + ['p defined? Gem'], "", ["nil"], [], gems: false)
assert_in_out_err(%w(--disable-did_you_mean -e) + ['p defined? DidYouMean'], "", ["nil"], [])
assert_in_out_err(%w(-e) + ['p defined? DidYouMean'], "", ["nil"], [])
end
Expand Down
Loading