URI 모듈
URI 모듈
URI는 Uniform Resource Identifier(RFC 2396)를 다루는 클래스들을 제공하는 모듈이에요. URL을 문자열로 파싱하고, 구성 요소(스킴·호스트·경로·쿼리 등)를 나누고, 다시 조립하는 일을 표준화된 방식으로 해 주는 라이브러리예요.
특징
- URI를 다루는 일관된 방식을 제공해요.
- 커스텀 URI 스킴을 도입하기 쉬워요.
- 대체
URI::Parser(또는 다른 패턴·정규식)를 쓸 수 있는 유연성이 있어요.
기본 예제
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(...)로 문자열을 감싸면 자동으로 파싱되어, scheme·host·path·query·fragment 같은 접근자로 각 부분을 꺼낼 수 있어요.
커스텀 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>
Generic을 상속받은 새 클래스를 만들고 register_scheme으로 등록하면, 그 스킴 문자열을 파싱할 때 커스텀 클래스가 사용돼요.
관련 RFC
- RFC822, RFC1738, RFC2255, RFC2368, RFC2373, RFC2396, RFC2732, RFC3986
클래스 트리
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.rbURI::REGEXP— uri/common.rb,URI::REGEXP::PATTERN— uri/common.rbURI::Util— uri/common.rbURI::Error— uri/common.rb,URI::InvalidURIError,URI::InvalidComponentError,URI::BadURIError
저작권 정보
- 저자: Akira Yamada [email protected]
- 문서화: Akira Yamada, Dmitry V. Sabanin, Vincent Batts
- 라이선스: Copyright © 2001 akira yamada. Ruby와 같은 조건으로 재배포·수정 가능해요.
상수 (Constants)
DEFAULT_PARSER— 기본 파서 인스턴스RFC2396_PARSER— RFC 2396용 기본 파서 인스턴스RFC3986_PARSER— RFC 3986용 기본 파서 인스턴스
Public Class Methods
decode_uri_component(str, enc=Encoding::UTF_8)
URI.decode_www_form_component과 비슷하지만, '+'를 보존해요. 즉 URL 인코딩된 구성 요소를 디코드하되, +를 공백으로 바꾸지 않아요.
decode_www_form(str, enc=Encoding::UTF_8, separator: '&', use__charset_: false, isindex: false)
주어진 ASCII 문자열 str로부터 이름/값 쌍을 뽑아내요. Content-Type이 'application/x-www-form-urlencoded'인 HTTP 폼 데이터를 디코드할 때 써요.
반환값은 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", ""]]
decode_www_form_component(str, enc=Encoding::UTF_8)
주어진 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('+' 보존).
encode_uri_component(str, enc=nil)
URI.encode_www_form_component과 비슷하지만, ' '(공백)을 '+' 대신 '%20'으로 인코딩해요.
encode_www_form(enum, enc=nil)
주어진 Enumerable enum으로부터 URL-인코딩된 문자열을 만들어요. Content-Type이 'application/x-www-form-urlencoded'인 HTTP 요청의 폼 데이터로 쓰기에 적합해요.
반환 문자열은 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이 배열류일 때 각 원소를 필드로 변환하는 규칙은 다음과 같아요.
- 원소가 2개 이상의 배열이면 처음 두 원소로 필드를 만들고 나머지는 무시돼요:
name=value형태. 예:URI.encode_www_form([%w[foo bar], %w[baz bat bah]]) # => "foo=bar&baz=bat" - 원소가 1개 원소 배열이면
ele[0]으로 필드를 만들어요. 예:URI.encode_www_form([['foo'], [:bar], [0]]) # => "foo&bar&0" - 그 외에는
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가 배열로 변환 가능하면,value의 각 원소가key와 짝을 이뤄 필드를 만들어요. 예:URI.encode_www_form({foo: [:bar, 1], baz: [:bat, :bam, 2]}) # => "foo=bar&foo=1&baz=bat&baz=bam&baz=2"- 그 외에는
key와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"
encode_www_form_component(str, enc=nil)
주어진 문자열 str로부터 URL-인코딩된 문자열을 만들어요.
반환 문자열의 규칙은 다음과 같아요.
- 보존:
'*','.','-','_'문자와'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'으로 인코딩).
for(scheme, *arguments, default: Generic)
주어진 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://[email protected]:123/forum/questions/?tag=networking&order=newest#top>
URI.for('foo', *values, default: URI::HTTP)
# => #<URI::HTTP foo://[email protected]:123/forum/questions/?tag=networking&order=newest#top>
join(*str)
주어진 URI 문자열 str들을 RFC 2396에 따라 병합해요. str의 각 문자열은 병합 전에 RFC 3986 URI로 변환돼요.
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>
/로 시작하는 문자는 루트 기준, 그렇지 않으면 현재 경로에 이어붙이는 일반적인 URL 병합 규칙이 적용돼요.
open(name, *rest, &block)
URI를 포함한 여러 자원을 열 수 있게 해주는 메서드예요.
- 첫 인자가
open메서드에 응답하면, 나머지 인자로 그 객체의open을 호출해요. - 첫 인자가
(protocol)://로 시작하는 문자열이면URI.parse로 파싱하고, 파싱된 객체가open에 응답하면 그걸 호출해요. - 그 외에는
Kernel#open을 호출해요.
OpenURI::OpenRead#open이 URI::HTTP#open, URI::HTTPS#open, URI::FTP#open, Kernel#open을 제공해요. http://, https://, ftp://로 시작하는 URI(또는 문자열)를 받을 수 있고, 그 경우 열린 파일 객체는 OpenURI::Meta로 확장돼요.
parse(uri)
주어진 문자열 uri로부터 새 URI 객체를 만들어 돌려줘요.
URI.parse('https://[email protected]:123/forum/questions/?tag=networking&order=newest#top')
# => #<URI::HTTPS https://[email protected]:123/forum/questions/?tag=networking&order=newest#top>
URI.parse('http://[email protected]:123/forum/questions/?tag=networking&order=newest#top')
# => #<URI::HTTP http://[email protected]:123/forum/questions/?tag=networking&order=newest#top>
uri에 잘못된 URI 문자가 포함될 수 있다면, 먼저 URI::RFC2396_PARSER.escape로 문자열을 이스케이프하는 걸 권장해요.
parser=(parser = RFC3986_PARSER)
기본 파서 인스턴스를 설정해요. 파서를 교체하면 그 뒤의 파싱·조립 동작이 새 파서를 기준으로 동작해요.
register_scheme(scheme, klass)
주어진 scheme을 가진 URI를 파싱할 때 인스턴스화할 클래스로 klass를 등록해요.
URI.register_scheme('MS_SEARCH', URI::Generic) # => URI::Generic
URI.scheme_list['MS_SEARCH'] # => URI::Generic
scheme에 String#upcase를 적용한 결과가 유효한 상수 이름이어야 한다는 점에 주의하세요.
scheme_list()
정의된 스킴들의 해시를 돌려줘요.
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.
split(uri)
문자열 uri로 이루어지는 URI의 각 부분을 나타내는 9-원소 배열을 돌려줘요. 각 배열 원소는 문자열 또는 nil이에요.
names = %w[scheme userinfo host port registry path opaque query fragment]
values = URI.split('https://[email protected]: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"]]
Private Class Methods
_decode_uri_component(regexp, str, enc)
주어진 URL-인코딩 문자열 str에서 regexp와 일치하는 문자를 디코드한 문자열을 돌려줘요. 실제 파싱의 공통 로직으로, 위 공개 메서드들이 내부적으로 사용해요.
_encode_uri_component(regexp, table, str, enc)
주어진 문자열 str에서 regexp와 일치하는 문자를 table에 따라 URI-인코딩한 문자열을 돌려줘요.