diff --git a/stdlib/open-uri/0/manifest.yaml b/stdlib/open-uri/0/manifest.yaml new file mode 100644 index 000000000..d5cea9508 --- /dev/null +++ b/stdlib/open-uri/0/manifest.yaml @@ -0,0 +1,3 @@ +dependencies: + - name: tempfile + - name: uri diff --git a/stdlib/open-uri/0/open-uri.rbs b/stdlib/open-uri/0/open-uri.rbs new file mode 100644 index 000000000..d044b8dc9 --- /dev/null +++ b/stdlib/open-uri/0/open-uri.rbs @@ -0,0 +1,349 @@ +%a{annotate:rdoc:skip} +module URI + # + # Allows the opening of various resources including URIs. + # + # If the first argument responds to the 'open' method, 'open' is called on it + # with the rest of the arguments. + # + # If the first argument is a string that begins with `(protocol)://`, it is + # parsed by URI.parse. If the parsed object responds to the 'open' method, + # 'open' is called on it with the rest of the arguments. + # + # Otherwise, Kernel#open is called. + # + # OpenURI::OpenRead#open provides URI::HTTP#open, URI::HTTPS#open and + # URI::FTP#open, Kernel#open. + # + # We can accept URIs and strings that begin with http://, https:// and ftp://. + # In these cases, the opened file object is extended by OpenURI::Meta. + # + def self.open: (String name, ?String mode, ?Integer perm, ?untyped options) -> (StringIO & OpenURI::Meta | Tempfile & OpenURI::Meta) + | [T] (String name, ?String mode, ?Integer perm, ?untyped options) { (StringIO | Tempfile) -> T } -> T +end + +# +# OpenURI is an easy-to-use wrapper for Net::HTTP, Net::HTTPS and Net::FTP. +# +# ## Example +# +# It is possible to open an http, https or ftp URL as though it were a file: +# +# URI.open("http://www.ruby-lang.org/") {|f| +# f.each_line {|line| p line} +# } +# +# The opened file has several getter methods for its meta-information, as +# follows, since it is extended by OpenURI::Meta. +# +# URI.open("http://www.ruby-lang.org/en") {|f| +# f.each_line {|line| p line} +# p f.base_uri # +# p f.content_type # "text/html" +# p f.charset # "iso-8859-1" +# p f.content_encoding # [] +# p f.last_modified # Thu Dec 05 02:45:02 UTC 2002 +# } +# +# Additional header fields can be specified by an optional hash argument. +# +# URI.open("http://www.ruby-lang.org/en/", +# "User-Agent" => "Ruby/#{RUBY_VERSION}", +# "From" => "foo@bar.invalid", +# "Referer" => "http://www.ruby-lang.org/") {|f| +# # ... +# } +# +# The environment variables such as http_proxy, https_proxy and ftp_proxy are in +# effect by default. Here we disable proxy: +# +# URI.open("http://www.ruby-lang.org/en/", :proxy => nil) {|f| +# # ... +# } +# +# See OpenURI::OpenRead.open and URI.open for more on available options. +# +# URI objects can be opened in a similar way. +# +# uri = URI.parse("http://www.ruby-lang.org/en/") +# uri.open {|f| +# # ... +# } +# +# URI objects can be read directly. The returned string is also extended by +# OpenURI::Meta. +# +# str = uri.read +# p str.base_uri +# +# Author +# : Tanaka Akira +# +module OpenURI + # + # Mixin for holding meta-information. + # + module Meta + # + # returns an Array that consists of status code and message. + # + attr_accessor status: [ String, String ] + + # + # returns a URI that is the base of relative URIs in the data. It may differ + # from the URI supplied by a user due to redirection. + # + attr_accessor base_uri: URI::Generic + + # + # returns a Hash that represents header fields. The Hash keys are downcased for + # canonicalization. The Hash values are a field body. If there are multiple + # field with same field name, the field values are concatenated with a comma. + # + attr_reader meta: Hash[String, String] + + # + # returns a Time that represents the Last-Modified field. + # + def last_modified: () -> Time? + + # + # returns "type/subtype" which is MIME Content-Type. It is downcased for + # canonicalization. Content-Type parameters are stripped. + # + def content_type: () -> String + + def charet: () -> String? + + # + # Returns a list of encodings in Content-Encoding field as an array of strings. + # + # The encodings are downcased for canonicalization. + # + def content_encoding: () -> Array[String] + end + + # + # Mixin for HTTP and FTP URIs. + # + module OpenRead + # + # OpenURI::OpenRead#open provides `open' for URI::HTTP and URI::FTP. + # + # OpenURI::OpenRead#open takes optional 3 arguments as: + # + # OpenURI::OpenRead#open([mode [, perm]] [, options]) [{|io| ... }] + # + # OpenURI::OpenRead#open returns an IO-like object if block is not given. + # Otherwise it yields the IO object and return the value of the block. The IO + # object is extended with OpenURI::Meta. + # + # `mode` and `perm` are the same as Kernel#open. + # + # However, `mode` must be read mode because OpenURI::OpenRead#open doesn't + # support write mode (yet). Also `perm` is ignored because it is meaningful only + # for file creation. + # + # `options` must be a hash. + # + # Each option with a string key specifies an extra header field for HTTP. I.e., + # it is ignored for FTP without HTTP proxy. + # + # The hash may include other options, where keys are symbols: + # + # :proxy + # : Synopsis: + # :proxy => "http://proxy.foo.com:8000/" + # :proxy => URI.parse("http://proxy.foo.com:8000/") + # :proxy => true + # :proxy => false + # :proxy => nil + # + # If :proxy option is specified, the value should be String, URI, boolean or + # nil. + # + # When String or URI is given, it is treated as proxy URI. + # + # When true is given or the option itself is not specified, environment + # variable `scheme_proxy' is examined. `scheme' is replaced by `http', + # `https' or `ftp'. + # + # When false or nil is given, the environment variables are ignored and + # connection will be made to a server directly. + # + # :proxy_http_basic_authentication + # : Synopsis: + # :proxy_http_basic_authentication => + # ["http://proxy.foo.com:8000/", "proxy-user", "proxy-password"] + # :proxy_http_basic_authentication => + # [URI.parse("http://proxy.foo.com:8000/"), + # "proxy-user", "proxy-password"] + # + # If :proxy option is specified, the value should be an Array with 3 + # elements. It should contain a proxy URI, a proxy user name and a proxy + # password. The proxy URI should be a String, an URI or nil. The proxy + # user name and password should be a String. + # + # If nil is given for the proxy URI, this option is just ignored. + # + # If :proxy and :proxy_http_basic_authentication is specified, ArgumentError + # is raised. + # + # :http_basic_authentication + # : Synopsis: + # :http_basic_authentication=>[user, password] + # + # If :http_basic_authentication is specified, the value should be an array + # which contains 2 strings: username and password. It is used for HTTP Basic + # authentication defined by RFC 2617. + # + # :content_length_proc + # : Synopsis: + # :content_length_proc => lambda {|content_length| ... } + # + # If :content_length_proc option is specified, the option value procedure is + # called before actual transfer is started. It takes one argument, which is + # expected content length in bytes. + # + # If two or more transfers are performed by HTTP redirection, the procedure + # is called only once for the last transfer. + # + # When expected content length is unknown, the procedure is called with nil. + # This happens when the HTTP response has no Content-Length header. + # + # :progress_proc + # : Synopsis: + # :progress_proc => lambda {|size| ...} + # + # If :progress_proc option is specified, the proc is called with one + # argument each time when `open' gets content fragment from network. The + # argument `size` is the accumulated transferred size in bytes. + # + # If two or more transfer is done by HTTP redirection, the procedure is + # called only one for a last transfer. + # + # :progress_proc and :content_length_proc are intended to be used for + # progress bar. For example, it can be implemented as follows using + # Ruby/ProgressBar. + # + # pbar = nil + # open("http://...", + # :content_length_proc => lambda {|t| + # if t && 0 < t + # pbar = ProgressBar.new("...", t) + # pbar.file_transfer_mode + # end + # }, + # :progress_proc => lambda {|s| + # pbar.set s if pbar + # }) {|f| ... } + # + # :read_timeout + # : Synopsis: + # :read_timeout=>nil (no timeout) + # :read_timeout=>10 (10 second) + # + # :read_timeout option specifies a timeout of read for http connections. + # + # :open_timeout + # : Synopsis: + # :open_timeout=>nil (no timeout) + # :open_timeout=>10 (10 second) + # + # :open_timeout option specifies a timeout of open for http connections. + # + # :ssl_ca_cert + # : Synopsis: + # :ssl_ca_cert=>filename or an Array of filenames + # + # :ssl_ca_cert is used to specify CA certificate for SSL. If it is given, + # default certificates are not used. + # + # :ssl_verify_mode + # : Synopsis: + # :ssl_verify_mode=>mode + # + # :ssl_verify_mode is used to specify openssl verify mode. + # + # :ssl_min_version + # : Synopsis: + # :ssl_min_version=>:TLS1_2 + # + # :ssl_min_version option specifies the minimum allowed SSL/TLS protocol + # version. See also OpenSSL::SSL::SSLContext#min_version=. + # + # :ssl_max_version + # : Synopsis: + # :ssl_max_version=>:TLS1_2 + # + # :ssl_max_version option specifies the maximum allowed SSL/TLS protocol + # version. See also OpenSSL::SSL::SSLContext#max_version=. + # + # :ftp_active_mode + # : Synopsis: + # :ftp_active_mode=>bool + # + # `:ftp_active_mode => true` is used to make ftp active mode. Ruby 1.9 uses + # passive mode by default. Note that the active mode is default in Ruby 1.8 + # or prior. + # + # :redirect + # : Synopsis: + # :redirect=>bool + # + # `:redirect` is true by default. `:redirect => false` is used to disable + # all HTTP redirects. + # + # OpenURI::HTTPRedirect exception raised on redirection. Using `true` also + # means that redirections between http and ftp are permitted. + # + def open: (*untyped) -> IO + | [T] (*untyped) { (IO) -> T } -> T + + # + # OpenURI::OpenRead#read([ options ]) reads a content referenced by self and + # returns the content as string. The string is extended with OpenURI::Meta. The + # argument `options` is same as OpenURI::OpenRead#open. + # + def read: (untyped options) -> String + end +end + +%a{annotate:rdoc:skip} +module URI + %a{annotate:rdoc:skip} + class HTTP + include OpenURI::OpenRead + end + + # + # FTP URI syntax is defined by RFC1738 section 3.2. + # + # This class will be redesigned because of difference of implementations; the + # structure of its path. draft-hoffman-ftp-uri-04 is a draft but it is a good + # summary about the de facto spec. + # http://tools.ietf.org/html/draft-hoffman-ftp-uri-04 + # + %a{annotate:rdoc:skip} + class FTP + include OpenURI::OpenRead + end +end diff --git a/test/stdlib/open-uri_test.rb b/test/stdlib/open-uri_test.rb new file mode 100644 index 000000000..acc9f03c9 --- /dev/null +++ b/test/stdlib/open-uri_test.rb @@ -0,0 +1,16 @@ +require_relative "test_helper" +require "open-uri" + +class OpenURISingletonTest < Test::Unit::TestCase + include TypeAssertions + + library "open-uri" + testing "singleton(::URI)" + + def test_URI_open + assert_send_type "(String) -> StringIO", + URI, :open, "https://www.ruby-lang.org" + assert_send_type "(String) { (StringIO) -> String } -> String", + URI, :open, "https://www.ruby-lang.org" do |io| io.read end + end +end