модуль URI
URI — это модуль, предоставляющий классы для работы с универсальными идентификаторами ресурсов (RFC2396).
Особенности
-
Единый способ обработки URI.
-
Гибкость введения пользовательских схем
URI. -
Гибкость в использовании альтернативного парсера URI (или просто различных шаблонов и регулярных выражений).
Базовый пример
require 'uri'
uri = URI("http://foo.com/posts?id=30&limit=5#time=1305298413")
#=> #<URI::HTTP http://foo.com/posts?id=30&limit=5#time=1305298413>
uri.scheme #=> "http"
uri.host #=> "foo.com"
uri.path #=> "/posts"
uri.query #=> "id=30&limit=5"
uri.fragment #=> "time=1305298413"
uri.to_s #=> "http://foo.com/posts?id=30&limit=5#time=1305298413"
Добавление пользовательских URI
module URI
class RSYNC < Generic
DEFAULT_PORT = 873
end
register_scheme 'RSYNC', RSYNC
end
#=> URI::RSYNC
URI.scheme_list
#=> {"FILE"=>URI::File, "FTP"=>URI::FTP, "HTTP"=>URI::HTTP,
# "HTTPS"=>URI::HTTPS, "LDAP"=>URI::LDAP, "LDAPS"=>URI::LDAPS,
# "MAILTO"=>URI::MailTo, "RSYNC"=>URI::RSYNC}
uri = URI("rsync://rsync.foo.com")
#=> #<URI::RSYNC rsync://rsync.foo.com>
Ссылки на RFC
Хорошее место для просмотра спецификации RFC — www.ietf.org/rfc.html.
Вот список всех связанных RFC:
Class дерево
-
URI::Generic(в uri/generic.rb)-
URI::File- (в uri/file.rb) -
URI::FTP- (в uri/ftp.rb) -
URI::HTTP- (в uri/http.rb)-
URI::HTTPS- (в uri/https.rb)
-
-
URI::LDAP- (в uri/ldap.rb)-
URI::LDAPS- (в uri/ldaps.rb)
-
-
URI::MailTo- (в uri/mailto.rb)
-
-
URI::Parser - (в uri/common.rb)
-
URI::REGEXP - (в uri/common.rb)
-
URI::REGEXP::PATTERN - (в uri/common.rb)
-
-
URI::Util - (в uri/common.rb)
-
URI::Error- (в uri/common.rb)-
URI::InvalidURIError- (в uri/common.rb) -
URI::InvalidComponentError- (в uri/common.rb) -
URI::BadURIError- (в uri/common.rb)
-
Информация об авторских правах
- Автор
-
Akira Yamada <akira@ruby-lang.org>
- Документация
-
Akira Yamada <akira@ruby-lang.org> Dmitry V. Sabanin <sdmitry@lrn.ru> Vincent Batts <vbatts@hashbangbash.com>
- Лицензия
-
Авторские права © 2001 akira yamada <akira@ruby-lang.org> Вы можете перераспределять и/или изменять его в соответствии с условиями лицензии Ruby.
Константы
- DEFAULT_PARSER
- INITIAL_SCHEMES
- RFC2396_PARSER
- RFC3986_PARSER
- TBLENCURICOMP_
Публичные методы класса
Исходный код
# File lib/uri/common.rb, line 43
def self.const_missing(const)
if const == :REGEXP
warn "URI::REGEXP is obsolete. Use URI::RFC2396_REGEXP explicitly.", uplevel: 1 if $VERBOSE
URI::RFC2396_REGEXP
elsif value = RFC2396_PARSER.regexp[const]
warn "URI::#{const} is obsolete. Use RFC2396_PARSER.regexp[#{const.inspect}] explicitly.", uplevel: 1 if $VERBOSE
value
elsif value = RFC2396_Parser.const_get(const)
warn "URI::#{const} is obsolete. Use RFC2396_Parser::#{const} explicitly.", uplevel: 1 if $VERBOSE
value
else
super
end
end Исходный код
# File lib/uri/common.rb, line 402 def self.decode_uri_component(str, enc=Encoding::UTF_8) _decode_uri_component(/%\h\h/, str, enc) end
Аналогично URI.decode_www_form_component, за исключением того, что '+' сохраняется.
Исходный код
# File lib/uri/common.rb, line 577
def self.decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false)
raise ArgumentError, "the input of #{self.name}.#{__method__} must be ASCII only string" unless str.ascii_only?
ary = []
return ary if str.empty?
enc = Encoding.find(enc)
str.b.each_line(separator) do |string|
string.chomp!(separator)
key, sep, val = string.partition('=')
if isindex
if sep.empty?
val = key
key = +''
end
isindex = false
end
if use__charset_ and key == '_charset_' and e = get_encoding(val)
enc = e
use__charset_ = false
end
key.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_)
if val
val.gsub!(/\+|%\h\h/, TBLDECWWWCOMP_)
else
val = +''
end
ary << [key, val]
end
ary.each do |k, v|
k.force_encoding(enc)
k.scrub!
v.force_encoding(enc)
v.scrub!
end
ary
end Возвращает пары имя/значение, полученные из данной строки str, которая должна быть строкой ASCII.
Метод может использоваться для декодирования тела объекта Net::HTTPResponse res, для которого res['Content-Type'] является 'application/x-www-form-urlencoded'.
Возвращаемые данные представляют собой массив 2-элементных подмассивов; каждый подмассив является парой имя/значение (оба являются строками). Каждая возвращаемая строка имеет кодировку enc, и из неё были удалены недопустимые символы с помощью String#scrub.
Простой пример:
URI.decode_www_form('foo=0&bar=1&baz')
# => [["foo", "0"], ["bar", "1"], ["baz", ""]]
Возвращаемые строки имеют определённые преобразования, аналогичные тем, которые выполняются в URI.decode_www_form_component:
URI.decode_www_form('f%23o=%2F&b-r=%24&b+z=%40')
# => [["f#o", "/"], ["b-r", "$"], ["b z", "@"]]
Данная строка может содержать последовательные разделители:
URI.decode_www_form('foo=0&&bar=1&&baz=2')
# => [["foo", "0"], ["", ""], ["bar", "1"], ["", ""], ["baz", "2"]]
Можно указать другой разделитель:
URI.decode_www_form('foo=0--bar=1--baz', separator: '--')
# => [["foo", "0"], ["bar", "1"], ["baz", ""]]
Исходный код
# File lib/uri/common.rb, line 391 def self.decode_www_form_component(str, enc=Encoding::UTF_8) _decode_uri_component(/\+|%\h\h/, str, enc) end
Возвращает строку, декодированную из данной URL-кодированной строки str.
Данная строка сначала кодируется как Encoding::ASCII-8BIT (с помощью String#b), затем декодируется (как показано ниже) и, наконец, принудительно кодируется в заданную кодировку enc.
Возвращаемая строка:
-
Сохраняет:
-
Символы
'*','.','-'и'_'. -
Символы в диапазонах
'a'..'z','A'..'Z'и'0'..'9'.
Пример:
URI.decode_www_form_component('*.-_azAZ09') # => "*.-_azAZ09" -
-
Преобразует:
-
Символ
'+'в символ' '. -
Каждое «процентное обозначение» в символ ASCII.
Пример:
URI.decode_www_form_component('Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A') # => "Here are some punctuation characters: ,;?:" -
Связанный метод: URI.decode_uri_component (сохраняет '+').
Исходный код
# File lib/uri/common.rb, line 397 def self.encode_uri_component(str, enc=nil) _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCURICOMP_, str, enc) end
Аналогично URI.encode_www_form_component, за исключением того, что ' ' (пробел) кодируется как '%20' (вместо '+').
Исходный код
# File lib/uri/common.rb, line 524
def self.encode_www_form(enum, enc=nil)
enum.map do |k,v|
if v.nil?
encode_www_form_component(k, enc)
elsif v.respond_to?(:to_ary)
v.to_ary.map do |w|
str = encode_www_form_component(k, enc)
unless w.nil?
str << '='
str << encode_www_form_component(w, enc)
end
end.join('&')
else
str = encode_www_form_component(k, enc)
str << '='
str << encode_www_form_component(v, enc)
end
end.join('&')
end Возвращает URL-кодированную строку, полученную из заданного объекта Enumerable enum.
Результат подходит для использования в качестве данных формы для HTTP-запроса, Content-Type которого 'application/x-www-form-urlencoded'.
Возвращаемая строка состоит из элементов enum, каждый из которых преобразован в одну или несколько URL-кодированных строк, и все они соединены символом '&'.
Простые примеры:
URI.encode_www_form([['foo', 0], ['bar', 1], ['baz', 2]])
# => "foo=0&bar=1&baz=2"
URI.encode_www_form({foo: 0, bar: 1, baz: 2})
# => "foo=0&bar=1&baz=2"
Возвращаемая строка формируется с помощью метода URI.encode_www_form_component, который преобразует определённые символы:
URI.encode_www_form('f#o': '/', 'b-r': '$', 'b z': '@')
# => "f%23o=%2F&b-r=%24&b+z=%40"
Когда enum является похожим на массив, каждый элемент ele преобразуется в поле:
-
Если
eleявляется массивом из двух или более элементов, поле формируется из его первых двух элементов (а все остальные элементы игнорируются):name = URI.encode_www_form_component(ele[0], enc) value = URI.encode_www_form_component(ele[1], enc) "#{name}=#{value}"Примеры:
URI.encode_www_form([%w[foo bar], %w[baz bat bah]]) # => "foo=bar&baz=bat" URI.encode_www_form([['foo', 0], ['bar', :baz, 'bat']]) # => "foo=0&bar=baz"
-
Если
eleявляется массивом из одного элемента, поле формируется изele[0]:URI.encode_www_form_component(ele[0])
Пример:
URI.encode_www_form([['foo'], [:bar], [0]]) # => "foo&bar&0"
-
В противном случае поле формируется из
ele:URI.encode_www_form_component(ele)
Пример:
URI.encode_www_form(['foo', :bar, 0]) # => "foo&bar&0"
Элементы объекта, похожего на массив enum, могут быть смешанными:
URI.encode_www_form([['foo', 0], ['bar', 1, 2], ['baz'], :bat]) # => "foo=0&bar=1&baz&bat"
Когда enum является похожим на хэш, каждая пара key/value преобразуется в одно или несколько полей:
-
Если
valueявляется преобразуемым в массив, каждый элементeleвvalueсоединяется сkeyдля формирования поля:name = URI.encode_www_form_component(key, enc) value = URI.encode_www_form_component(ele, enc) "#{name}=#{value}"Пример:
URI.encode_www_form({foo: [:bar, 1], baz: [:bat, :bam, 2]}) # => "foo=bar&foo=1&baz=bat&baz=bam&baz=2" -
В противном случае
keyиvalueсоединяются для формирования поля:name = URI.encode_www_form_component(key, enc) value = URI.encode_www_form_component(value, enc) "#{name}=#{value}"Пример:
URI.encode_www_form({foo: 0, bar: 1, baz: 2}) # => "foo=0&bar=1&baz=2"
Элементы объекта, похожего на хэш enum, могут быть смешанными:
URI.encode_www_form({foo: [0, 1], bar: 2})
# => "foo=0&foo=1&bar=2"
Исходный код
# File lib/uri/common.rb, line 358 def self.encode_www_form_component(str, enc=nil) _encode_uri_component(/[^*\-.0-9A-Z_a-z]/, TBLENCWWWCOMP_, str, enc) end
Возвращает URL-кодированную строку, полученную из данной строки str.
Возвращаемая строка:
-
Сохраняет:
-
Символы
'*','.','-'и'_'. -
Символы в диапазонах
'a'..'z','A'..'Z'и'0'..'9'.
Пример:
URI.encode_www_form_component('*.-_azAZ09') # => "*.-_azAZ09" -
-
Преобразует:
-
Символ
' 'в символ'+'. -
Любой другой символ в «процентное обозначение»; процентное обозначение для символа c — это
'%%%X' % c.ord.
Пример:
URI.encode_www_form_component('Here are some punctuation characters: ,;?:') # => "Here+are+some+punctuation+characters%3A+%2C%3B%3F%3A" -
Кодирование:
-
Если
strимеет кодировку Encoding::ASCII_8BIT, аргументencигнорируется. -
В противном случае
strсначала преобразуется в Encoding::UTF_8 (с соответствующими заменами символов), а затем в кодировкуenc.
В любом случае, возвращаемая строка имеет принудительную кодировку Encoding::US_ASCII.
Связанный метод: URI.encode_uri_component (кодирует ' ' как '%20').
Исходный код
# File lib/uri/common.rb, line 146
def self.for(scheme, *arguments, default: Generic)
const_name = scheme.to_s.upcase
uri_class = INITIAL_SCHEMES[const_name]
uri_class ||= if /\A[A-Z]\w*\z/.match?(const_name) && Schemes.const_defined?(const_name, false)
Schemes.const_get(const_name, false)
end
uri_class ||= default
return uri_class.new(scheme, *arguments)
end Возвращает новый объект, созданный из заданных scheme, arguments и default:
-
Новый объект является экземпляром
URI.scheme_list[scheme.upcase]. -
Объект инициализируется вызовом инициализатора класса с использованием
schemeиarguments. См.URI::Generic.new.
Примеры:
values = ['john.doe', 'www.example.com', '123', nil, '/forum/questions/', nil, 'tag=networking&order=newest', 'top']
URI.for('https', *values)
# => #<URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
URI.for('foo', *values, default: URI::HTTP)
# => #<URI::HTTP foo://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
Исходный код
# File lib/uri/common.rb, line 234 def self.join(*str) DEFAULT_PARSER.join(*str) end
Объединяет заданные URI строки str в соответствии с RFC 2396.
Каждая строка в str преобразуется в URI RFC3986 перед объединением.
Примеры:
URI.join("http://example.com/","main.rbx")
# => #<URI::HTTP http://example.com/main.rbx>
URI.join('http://example.com', 'foo')
# => #<URI::HTTP http://example.com/foo>
URI.join('http://example.com', '/foo', '/bar')
# => #<URI::HTTP http://example.com/bar>
URI.join('http://example.com', '/foo', 'bar')
# => #<URI::HTTP http://example.com/bar>
URI.join('http://example.com', '/foo/', 'bar')
# => #<URI::HTTP http://example.com/foo/bar>
Исходный код
# File lib/open-uri.rb, line 23
def self.open(name, *rest, &block)
if name.respond_to?(:open)
name.open(*rest, &block)
elsif name.respond_to?(:to_str) &&
%r{\A[A-Za-z][A-Za-z0-9+\-\.]*://} =~ name &&
(uri = URI.parse(name)).respond_to?(:open)
uri.open(*rest, &block)
else
super
end
end Позволяет открывать различные ресурсы, включая URI.
Если первый аргумент отвечает методу «open», вызывается «open» с остальными аргументами.
Если первый аргумент — строка, начинающаяся с (protocol)://, она парсится с помощью URI.parse. Если полученный объект отвечает методу «open», вызывается «open» с остальными аргументами.
В противном случае, вызывается Kernel#open.
OpenURI::OpenRead#open предоставляет URI::HTTP#open, URI::HTTPS#open и URI::FTP#open, Kernel#open.
Мы можем принимать URI и строки, начинающиеся с http://, https:// и ftp://. В этих случаях открытый объект файла дополняется OpenURI::Meta.
Исходный код
# File lib/uri/common.rb, line 207 def self.parse(uri) DEFAULT_PARSER.parse(uri) end
Возвращает новый объект URI, созданный из заданной строки uri:
URI.parse('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
# => #<URI::HTTPS https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
URI.parse('http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
# => #<URI::HTTP http://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top>
Рекомендуется предварительно ::escape строку uri, если она может содержать недопустимые символы URI.
Исходный код
# File lib/uri/common.rb, line 25
def self.parser=(parser = RFC3986_PARSER)
remove_const(:Parser) if defined?(::URI::Parser)
const_set("Parser", parser.class)
remove_const(:REGEXP) if defined?(::URI::REGEXP)
remove_const(:PATTERN) if defined?(::URI::PATTERN)
if Parser == RFC2396_Parser
const_set("REGEXP", URI::RFC2396_REGEXP)
const_set("PATTERN", URI::RFC2396_REGEXP::PATTERN)
end
Parser.new.regexp.each_pair do |sym, str|
remove_const(sym) if const_defined?(sym, false)
const_set(sym, str)
end
end Исходный код
# File lib/uri/common.rb, line 102 def self.register_scheme(scheme, klass) Schemes.const_set(scheme.to_s.upcase, klass) end
Регистрирует заданный klass как класс, который будет создан при парсинге URI с заданным scheme:
URI.register_scheme('MS_SEARCH', URI::Generic) # => URI::Generic
URI.scheme_list['MS_SEARCH'] # => URI::Generic
Обратите внимание, что после вызова String#upcase на scheme, он должен быть допустимым именем константы.
Исходный код
# File lib/uri/common.rb, line 120
def self.scheme_list
Schemes.constants.map { |name|
[name.to_s.upcase, Schemes.const_get(name)]
}.to_h
end Возвращает хеш определённых схем:
URI.scheme_list
# =>
{"MAILTO"=>URI::MailTo,
"LDAPS"=>URI::LDAPS,
"WS"=>URI::WS,
"HTTP"=>URI::HTTP,
"HTTPS"=>URI::HTTPS,
"LDAP"=>URI::LDAP,
"FILE"=>URI::File,
"FTP"=>URI::FTP}
Связанно с: URI.register_scheme.
Исходный код
# File lib/uri/common.rb, line 193 def self.split(uri) DEFAULT_PARSER.split(uri) end
Возвращает массив из 9 элементов, представляющих части URI, сформированные из строки uri; каждый элемент массива — строка или nil:
names = %w[scheme userinfo host port registry path opaque query fragment]
values = URI.split('https://john.doe@www.example.com:123/forum/questions/?tag=networking&order=newest#top')
names.zip(values)
# =>
[["scheme", "https"],
["userinfo", "john.doe"],
["host", "www.example.com"],
["port", "123"],
["registry", nil],
["path", "/forum/questions/"],
["opaque", nil],
["query", "tag=networking&order=newest"],
["fragment", "top"]]
Методы частного класса
Исходный код
# File lib/uri/common.rb, line 420
def self._decode_uri_component(regexp, str, enc)
raise ArgumentError, "invalid %-encoding (#{str})" if /%(?!\h\h)/.match?(str)
str.b.gsub(regexp, TBLDECWWWCOMP_).force_encoding(enc)
end Исходный код
# File lib/uri/common.rb, line 406
def self._encode_uri_component(regexp, table, str, enc)
str = str.to_s.dup
if str.encoding != Encoding::ASCII_8BIT
if enc && enc != Encoding::ASCII_8BIT
str.encode!(Encoding::UTF_8, invalid: :replace, undef: :replace)
str.encode!(enc, fallback: ->(x){"&##{x.ord};"})
end
str.force_encoding(Encoding::ASCII_8BIT)
end
str.gsub!(regexp, table)
str.force_encoding(Encoding::US_ASCII)
end
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.