Skip to content

Commit

Permalink
Merge pull request #1592 from tk0miya/open-uri
Browse files Browse the repository at this point in the history
stdlib: Add types for open-uri
  • Loading branch information
soutaro authored Nov 2, 2023
2 parents e29c62f + e13e32e commit 05b8d17
Show file tree
Hide file tree
Showing 3 changed files with 360 additions and 0 deletions.
3 changes: 3 additions & 0 deletions stdlib/open-uri/0/manifest.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
dependencies:
- name: tempfile
- name: uri
341 changes: 341 additions & 0 deletions stdlib/open-uri/0/open-uri.rbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,341 @@
%a{annotate:rdoc:skip}
module URI
# <!--
# rdoc-file=lib/open-uri.rb
# - open(name, *rest, &block)
# -->
# 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

# <!-- rdoc-file=lib/open-uri.rb -->
# 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 # <URI::HTTP:0x40e6ef2 URL:http://www.ruby-lang.org/en/>
# 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" => "[email protected]",
# "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 <[email protected]>
#
module OpenURI
# <!-- rdoc-file=lib/open-uri.rb -->
# Mixin for holding meta-information.
#
module Meta
# <!-- rdoc-file=lib/open-uri.rb -->
# returns an Array that consists of status code and message.
#
attr_accessor status: [ String, String ]

# <!-- rdoc-file=lib/open-uri.rb -->
# 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

# <!-- rdoc-file=lib/open-uri.rb -->
# 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]

# <!--
# rdoc-file=lib/open-uri.rb
# - last_modified()
# -->
# returns a Time that represents the Last-Modified field.
#
def last_modified: () -> Time?

# <!--
# rdoc-file=lib/open-uri.rb
# - content_type()
# -->
# 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?

# <!--
# rdoc-file=lib/open-uri.rb
# - content_encoding()
# -->
# 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

# <!-- rdoc-file=lib/open-uri.rb -->
# Mixin for HTTP and FTP URIs.
#
module OpenRead
# <!--
# rdoc-file=lib/open-uri.rb
# - open(*rest, &block)
# -->
# 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

# <!--
# rdoc-file=lib/open-uri.rb
# - read(options={})
# -->
# 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

%a{annotate:rdoc:skip}
class FTP
include OpenURI::OpenRead
end
end
16 changes: 16 additions & 0 deletions test/stdlib/open-uri_test.rb
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 05b8d17

Please sign in to comment.