[ruby/uri] Add proper Ractor support to URI

* Using a module to map scheme name to scheme class, which also works with Ractor.
* No constant redefinition, no ObjectSpace, still fast lookup for initial schemes.

https://github.com/ruby/uri/commit/883567fd81
This commit is contained in:
Benoit Daloze 2021-06-25 13:38:01 +02:00 коммит произвёл Hiroshi SHIBATA
Родитель 090d799c24
Коммит 1cf111774f
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: F9CF13417264FAC2
12 изменённых файлов: 60 добавлений и 18 удалений

Просмотреть файл

@ -30,7 +30,7 @@
# class RSYNC < Generic
# DEFAULT_PORT = 873
# end
# @@schemes['RSYNC'] = RSYNC
# register_scheme 'RSYNC', RSYNC
# end
# #=> URI::RSYNC
#
@ -100,3 +100,9 @@ require_relative 'uri/https'
require_relative 'uri/ldap'
require_relative 'uri/ldaps'
require_relative 'uri/mailto'
module URI
INITIAL_SCHEMES = scheme_list
private_constant :INITIAL_SCHEMES
Ractor.make_shareable(INITIAL_SCHEMES) if defined?(Ractor)
end

Просмотреть файл

@ -16,6 +16,7 @@ module URI
REGEXP = RFC2396_REGEXP
Parser = RFC2396_Parser
RFC3986_PARSER = RFC3986_Parser.new
Ractor.make_shareable(RFC3986_PARSER) if defined?(Ractor)
# URI::Parser.new
DEFAULT_PARSER = Parser.new
@ -27,6 +28,7 @@ module URI
DEFAULT_PARSER.regexp.each_pair do |sym, str|
const_set(sym, str)
end
Ractor.make_shareable(DEFAULT_PARSER) if defined?(Ractor)
module Util # :nodoc:
def make_components_hash(klass, array_hash)
@ -62,10 +64,19 @@ module URI
include REGEXP
@@schemes = {}
module Schemes
end
private_constant :Schemes
def self.register_scheme(scheme, klass)
Schemes.const_set(scheme, klass)
end
# Returns a Hash of the defined schemes.
def self.scheme_list
@@schemes
Schemes.constants.map { |name|
[name.to_s.upcase, Schemes.const_get(name)]
}.to_h
end
#
@ -73,11 +84,13 @@ module URI
# from +URI.scheme_list+.
#
def self.for(scheme, *arguments, default: Generic)
if scheme
uri_class = @@schemes[scheme.upcase] || default
else
uri_class = default
const_name = scheme.to_s.upcase
uri_class = INITIAL_SCHEMES[const_name]
if !uri_class && !const_name.empty? && Schemes.const_defined?(const_name, false)
uri_class = Schemes.const_get(const_name, false)
end
uri_class ||= default
return uri_class.new(scheme, *arguments)
end
@ -653,6 +666,7 @@ module URI
"utf-16"=>"utf-16le",
"utf-16le"=>"utf-16le",
} # :nodoc:
Ractor.make_shareable(WEB_ENCODINGS_) if defined?(Ractor)
# :nodoc:
# return encoding or nil

Просмотреть файл

@ -90,5 +90,5 @@ module URI
end
end
@@schemes['FILE'] = File
register_scheme 'FILE', File
end

Просмотреть файл

@ -262,5 +262,6 @@ module URI
return str
end
end
@@schemes['FTP'] = FTP
register_scheme 'FTP', FTP
end

Просмотреть файл

@ -82,6 +82,5 @@ module URI
end
end
@@schemes['HTTP'] = HTTP
register_scheme 'HTTP', HTTP
end

Просмотреть файл

@ -18,5 +18,6 @@ module URI
# A Default port of 443 for URI::HTTPS
DEFAULT_PORT = 443
end
@@schemes['HTTPS'] = HTTPS
register_scheme 'HTTPS', HTTPS
end

Просмотреть файл

@ -257,5 +257,5 @@ module URI
end
end
@@schemes['LDAP'] = LDAP
register_scheme 'LDAP', LDAP
end

Просмотреть файл

@ -17,5 +17,6 @@ module URI
# A Default port of 636 for URI::LDAPS
DEFAULT_PORT = 636
end
@@schemes['LDAPS'] = LDAPS
register_scheme 'LDAPS', LDAPS
end

Просмотреть файл

@ -289,5 +289,5 @@ module URI
alias to_rfc822text to_mailtext
end
@@schemes['MAILTO'] = MailTo
register_scheme 'MAILTO', MailTo
end

Просмотреть файл

@ -79,6 +79,5 @@ module URI
end
end
@@schemes['WS'] = WS
register_scheme 'WS', WS
end

Просмотреть файл

@ -18,5 +18,6 @@ module URI
# A Default port of 443 for URI::WSS
DEFAULT_PORT = 443
end
@@schemes['WSS'] = WSS
register_scheme 'WSS', WSS
end

Просмотреть файл

@ -33,6 +33,26 @@ class TestCommon < Test::Unit::TestCase
end
end
def test_ractor
return unless defined?(Ractor)
r = Ractor.new { URI.parse("https://ruby-lang.org/").inspect }
assert_equal(URI.parse("https://ruby-lang.org/").inspect, r.take)
end
def test_register_scheme
assert_equal(["FILE", "FTP", "HTTP", "HTTPS", "LDAP", "LDAPS", "MAILTO", "WS"].sort, URI.scheme_list.keys.sort)
foobar = Class.new(URI::Generic)
URI.register_scheme 'FOOBAR', foobar
begin
assert_equal(["FILE", "FTP", "HTTP", "HTTPS", "LDAP", "LDAPS", "MAILTO", "WS", "FOOBAR"].sort, URI.scheme_list.keys.sort)
ensure
URI.const_get(:Schemes).send(:remove_const, :FOOBAR)
end
assert_equal(["FILE", "FTP", "HTTP", "HTTPS", "LDAP", "LDAPS", "MAILTO", "WS"].sort, URI.scheme_list.keys.sort)
end
def test_regexp
EnvUtil.suppress_warning do
assert_instance_of Regexp, URI.regexp