Add a lot of YARD docs to various classes.

Also switch to Markdown as the markup language, rather than rdoc.
This commit is contained in:
Andy Brody 2017-05-30 01:34:42 -04:00
parent 3001348c8a
commit f54f14398d
12 changed files with 403 additions and 128 deletions

View File

@ -1,3 +1,4 @@
--markup markdown
-
history.md
LICENSE

View File

@ -123,3 +123,8 @@ end
require 'yard'
YARD::Rake::YardocTask.new do |t|
end
desc 'Run YARD documentation server, reload with changes'
task :yardserver do
sh 'yard server --reload'
end

View File

@ -18,47 +18,88 @@ require File.dirname(__FILE__) + '/restclient/windows'
# This module's static methods are the entry point for using the REST client.
#
# # GET
# xml = RestClient.get 'http://example.com/resource'
# jpg = RestClient.get 'http://example.com/resource', :accept => 'image/jpg'
# These helpers provide a concise way to issue simple requests with headers. If
# you need to set other options on a request (e.g. timeout, SSL options, etc.)
# then use {RestClient::Request.execute}, which supports all of these options.
#
# # authentication and SSL
# RestClient.get 'https://user:password@example.com/private/resource'
# The {.get}, {.head}, {.delete}, and {.options} methods take a URL String and
# optional HTTP headers Hash.
#
# # POST or PUT with a hash sends parameters as a urlencoded form body
# RestClient.post 'http://example.com/resource', :param1 => 'one'
# The {.post}, {.put}, and {.patch} methods take a URL String, a payload, and
# an optional HTTP headers Hash.
#
# # nest hash parameters
# RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
# All of these helpers are just thin wrappers around
# {RestClient::Request.execute RestClient::Request.execute}.
#
# # POST and PUT with raw payloads
# RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
# RestClient.post 'http://example.com/resource.xml', xml_doc
# RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
#
# # DELETE
# RestClient.delete 'http://example.com/resource'
# ```ruby
# # Simple GET request, potentially with headers.
# RestClient.get('http://example.com/')
# # => <RestClient::Response 200 "<!doctype h...">
#
# # retreive the response http code and headers
# res = RestClient.get 'http://example.com/some.jpg'
# res.code # => 200
# res.headers[:content_type] # => 'image/jpg'
# RestClient.get('http://example.com/resource', accept: 'image/jpg')
#
# # HEAD
# RestClient.head('http://example.com').headers
# RestClient.get('http://example.com', 'If-Modified-Since': 'Sat, 10 Aug 2013 10:23:00 GMT')
# # raises RestClient::NotModified: 304 Not Modified
#
# # Basic authentication and SSL
# RestClient.get 'https://user:password@example.com/private/resource'
#
# # POST or PUT with a hash sends parameters as a urlencoded form body
# RestClient.post 'http://example.com/resource', :param1 => 'one'
#
# # nest hash parameters
# RestClient.post 'http://example.com/resource', :nested => { :param1 => 'one' }
#
# # POST and PUT with raw payloads
# RestClient.post 'http://example.com/resource', 'the post body', :content_type => 'text/plain'
# RestClient.post 'http://example.com/resource.xml', xml_doc
# RestClient.put 'http://example.com/resource.pdf', File.read('my.pdf'), :content_type => 'application/pdf'
#
# # DELETE
# RestClient.delete 'http://example.com/resource'
#
# # Retrieve the response http code and headers
# res = RestClient.get 'http://example.com/some.jpg'
# res.code # => 200
# res.headers[:content_type] # => 'image/jpg'
#
# # HEAD
# RestClient.head('http://example.com').headers
# ```
#
# To use with a proxy, just set RestClient.proxy to the proper http proxy:
#
# RestClient.proxy = "http://proxy.example.com/"
# RestClient.proxy = "http://proxy.example.com/"
#
# Or inherit the proxy from the environment:
# Proxies can also be set via the `http_proxy`/`https_proxy` environment
# variables, or with the `:proxy` option on an individual {RestClient::Request}.
#
# RestClient.proxy = ENV['http_proxy']
# For live tests of RestClient, try using https://httpbin.org/. This service
# echoes back information about the HTTP request.
#
# For live tests of RestClient, try using http://rest-test.heroku.com, which echoes back information about the rest call:
#
# >> RestClient.put 'http://rest-test.heroku.com/resource', :foo => 'baz'
# => "PUT http://rest-test.heroku.com/resource with a 7 byte payload, content type application/x-www-form-urlencoded {\"foo\"=>\"baz\"}"
# r = RestClient.post('https://httpbin.org/post', foo: 'bar')
# # => <RestClient::Response 200 "{\n \"args\":...">
# puts r.body
# {
# "args": {},
# "data": "",
# "files": {},
# "form": {
# "foo": "bar"
# },
# "headers": {
# "Accept": "*/*",
# "Accept-Encoding": "gzip;q=1.0,deflate;q=0.6,identity;q=0.3",
# "Connection": "close",
# "Content-Length": "7",
# "Content-Type": "application/x-www-form-urlencoded",
# "Host": "httpbin.org",
# "User-Agent": "rest-client/2.1.0 (linux-gnu x86_64) ruby/2.3.3p222"
# },
# "json": null,
# "url": "https://httpbin.org/post"
# }
#
module RestClient
@ -96,6 +137,10 @@ module RestClient
@proxy ||= nil
end
# Set a proxy URL to use for all requests.
#
# @param value [String] The proxy URL.
#
def self.proxy=(value)
@proxy = value
@proxy_set = true
@ -113,12 +158,21 @@ module RestClient
# Setup the log for RestClient calls.
# Value should be a logger but can can be stdout, stderr, or a filename.
# You can also configure logging by the environment variable RESTCLIENT_LOG.
#
# @param log [Logger, #<<, String] The log to write to. See {.create_log}
#
def self.log= log
@@log = create_log log
end
# Create a log that respond to << like a logger
# param can be 'stdout', 'stderr', a string (then we will log to that file) or a logger (then we return it)
# Create a log that responds to `<<` like a Logger.
#
# @param param [Logger, #<<, String, nil] The log to write to. Should be a
# Logger, IO, or other object with a `<<` method. If param is a String, it
# will be treated as a filename and that file will be opened as a log file.
# The special Strings `"stdout"` and `"stderr"` will log to `STDOUT` and
# `STDERR`.
#
def self.create_log param
if param
if param.is_a? String
@ -158,10 +212,16 @@ module RestClient
@@log = nil
def self.log # :nodoc:
# The RestClient global logger. This will be used for all requests unless a
# `:log` option is set on the individual request.
#
# @see log=
#
def self.log
@@env_log || @@log
end
# Array of procs executed prior to each request.
@@before_execution_procs = []
# Add a Proc to be called before each request in executed.
@ -176,7 +236,8 @@ module RestClient
@@before_execution_procs = []
end
def self.before_execution_procs # :nodoc:
# Array of procs executed prior to each request.
def self.before_execution_procs
@@before_execution_procs
end

View File

@ -3,6 +3,17 @@ require 'http-cookie'
module RestClient
# The AbstractResponse module provides common functionality for RestClient
# responses. It is included by {RestClient::Response} and
# {RestClient::RawResponse}.
#
# Classes that include AbstractResponse should call {response_set_vars} as
# part of their `#initialize` method.
#
# Ideally this would have been a parent class, not a module. But the original
# RestClient API made {Response} be a subclass of `String`, so we are
# stuck with that for backwards compatibility.
#
module AbstractResponse
attr_reader :net_http_res, :request, :start_time, :end_time, :duration
@ -12,10 +23,17 @@ module RestClient
end
# Logger from the request, potentially nil.
#
# @see Request#log
#
def log
request.log
end
# Write log information about the response.
#
# @return [void]
#
def log_response
return unless log
@ -27,21 +45,39 @@ module RestClient
end
# HTTP status code
#
# @return [Integer]
#
def code
@code ||= @net_http_res.code.to_i
end
# An array of prior responses in the redirection chain, if any. If
# RestClient followed any redirects, this provides a way to see each
# individual response in the chain.
#
# @return [Array<Response>]
#
# @see Request#redirection_history
#
def history
@history ||= request.redirection_history || []
end
# A hash of the headers, beautified with symbols and underscores.
# e.g. "Content-type" will become :content_type.
# e.g. `"Content-type"` will become `:content_type`.
#
# @see beautify_headers
#
# @return [Hash]
#
def headers
@headers ||= AbstractResponse.beautify_headers(@net_http_res.to_hash)
end
# The raw headers.
#
# @return [Hash]
def raw_headers
@raw_headers ||= @net_http_res.to_hash
end
@ -49,6 +85,9 @@ module RestClient
# @param [Net::HTTPResponse] net_http_res
# @param [RestClient::Request] request
# @param [Time] start_time
#
# @return [void]
#
def response_set_vars(net_http_res, request, start_time)
@net_http_res = net_http_res
@request = request
@ -67,9 +106,9 @@ module RestClient
# Hash of cookies extracted from response headers.
#
# NB: This will return only cookies whose domain matches this request, and
# may not even return all of those cookies if there are duplicate names.
# Use the full cookie_jar for more nuanced access.
# **Note:** This will return only cookies whose domain matches this
# request, and may not even return all of those cookies if there are
# duplicate names. Use the full cookie_jar for more nuanced access.
#
# @see #cookie_jar
#
@ -104,11 +143,20 @@ module RestClient
#
# For 20x status codes: return the response itself
#
# For 30x status codes:
# 301, 302, 307: redirect GET / HEAD if there is a Location header
# 303: redirect, changing method to GET, if there is a Location header
# For 30x status codes, if there is a `Location` header and we have not yet
# reached {Request#max_redirects}:
#
# For all other responses, raise a response exception
# - 301, 302, 307: redirect GET / HEAD requests
# - 303: redirect, changing method to GET
#
# For all other responses, raise a response exception, a subclass of
# {ExceptionWithResponse} corresponding to the HTTP status code.
#
# For example, HTTP 404 => {RestClient::NotFound RestClient::NotFound}
#
# @raise [ExceptionWithResponse] for non-20x status codes, the exception
# from {RestClient::Exceptions::EXCEPTIONS_MAP} based on
# {RestClient::STATUSES} will be thrown.
#
def return!(&block)
case code
@ -130,11 +178,13 @@ module RestClient
end
end
# @deprecated Use {code} instead.
def to_i
warn('warning: calling Response#to_i is not recommended')
warn('warning: calling Response#to_i is deprecated. Use .code instead.')
super
end
# @return [String]
def description
"#{code} #{STATUSES[code]} | #{(headers[:content_type] || '').gsub(/;.*$/, '')} #{size} bytes\n"
end

View File

@ -2,18 +2,26 @@ module RestClient
# Hash of HTTP status code => message.
#
# 1xx: Informational - Request received, continuing process
# 2xx: Success - The action was successfully received, understood, and
# accepted
# 3xx: Redirection - Further action must be taken in order to complete the
# request
# 4xx: Client Error - The request contains bad syntax or cannot be fulfilled
# 5xx: Server Error - The server failed to fulfill an apparently valid
# request
# ### HTTP status code families:
#
# - 1xx: Informational --- Request received, continuing process
# - 2xx: Success --- The action was successfully received, understood, and
# accepted
# - 3xx: Redirection --- Further action must be taken in order to complete
# the request
# - 4xx: Client Error --- The request contains bad syntax or cannot be
# fulfilled
# - 5xx: Server Error --- The server failed to fulfill an apparently valid
# request
#
# This hash is used to populate all of the individual response exception
# classes, which are collected in {RestClient::Exceptions::EXCEPTIONS_MAP}.
#
# @see
# http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml
#
# **TODO:** Move these out of the top-level namespace and into {Exceptions}.
#
STATUSES = {100 => 'Continue',
101 => 'Switching Protocols',
102 => 'Processing', #WebDAV
@ -84,6 +92,11 @@ module RestClient
511 => 'Network Authentication Required', # RFC6585
}
# This Hash contains a mapping of aliases for the canonical HTTP status code
# classes that are preserved for backwards compatibility. For example,
# `RestClient::ResourceNotFound` is an alias for `RestClient::NotFound`.
#
# **TODO:** Move this out of the top-level namespace and into {Exceptions}.
STATUSES_COMPATIBILITY = {
# The RFCs all specify "Not Found", but "Resource Not Found" was used in
# earlier RestClient releases.
@ -101,16 +114,22 @@ module RestClient
# This is the base RestClient exception class. Rescue it if you want to
# catch any exception that your request might raise
# You can get the status code by e.http_code, or see anything about the
# response via e.response.
# For example, the entire result body (which is
# probably an HTML error page) is e.response.
# catch any exception that your request might raise. Note that the underlying
# network and socket libraries may raise other exceptions.
#
# You can get the status code with {#http_code}, or see anything about the
# response via {#response}.
#
# For more detailed information from the response, just call the
# corresponding methods on the response object (e.g. `e.response.history`).
#
class Exception < RuntimeError
attr_accessor :response
attr_accessor :original_exception
attr_writer :message
# @param response [RestClient::Response, RestClient::RawResponse]
#
def initialize response = nil, initial_response_code = nil
@response = response
@message = nil
@ -126,10 +145,14 @@ module RestClient
end
end
# @see Response#headers
# @return [Hash, nil]
def http_headers
@response.headers if @response
end
# @see Response#body
# @return [String, nil]
def http_body
@response.body if @response
end
@ -169,7 +192,9 @@ module RestClient
# http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
#
module Exceptions
# Map http status codes to the corresponding exception class
# Map http status codes to the corresponding exception class.
# This Hash is populated when the library is loaded, so values won't appear
# in the YARD documentation.
EXCEPTIONS_MAP = {}
end

View File

@ -10,6 +10,9 @@ rescue LoadError
end
module RestClient
# The Payload module contains several different classes used to process and
# represent different types of HTTP bodies / payloads.
module Payload
extend self
@ -56,6 +59,7 @@ module RestClient
end
end
# The base class for all the Payload classes.
class Base
def initialize(params)
build_stream(params)

View File

@ -29,10 +29,20 @@ module RestClient
RUBY_ENGINE == 'jruby'
end
# Return the host architecture and CPU from `RbConfig::CONFIG`.
#
# @return [String]
def self.architecture
"#{RbConfig::CONFIG['host_os']} #{RbConfig::CONFIG['host_cpu']}"
end
# Return information about the ruby version from `RUBY_ENGINE`,
# `RUBY_VERSION`, and `RUBY_PATCHLEVEL`.
#
# When running in jruby, also return the jruby version.
#
# @return [String]
#
def self.ruby_agent_version
case RUBY_ENGINE
when 'jruby'
@ -42,6 +52,17 @@ module RestClient
end
end
# Return a reasonable string for the `User-Agent` HTTP header.
#
# @example
# "rest-client/2.1.0 (linux-gnu x86_64) ruby/2.3.3p222"
#
# @return [String]
#
# @see VERSION RestClient::VERSION
# @see .architecture
# @see .ruby_agent_version
#
def self.default_user_agent
"rest-client/#{VERSION} (#{architecture}) #{ruby_agent_version}"
end

View File

@ -1,14 +1,35 @@
module RestClient
# The response from RestClient on a raw request looks like a string, but is
# actually one of these. 99% of the time you're making a rest call all you
# care about is the body, but on the occassion you want to fetch the
# headers you can:
# {RawResponse} is used to represent RestClient responses when
# `:raw_response => true` is passed to the {Request}.
#
# RestClient.get('http://example.com').headers[:content_type]
# Instead of processing the response data in various ways, the `RawResponse`
# downloads the response body to a `Tempfile` and does little processing of
# the underlying `Net::HTTPResponse` object. This is especially useful for
# large downloads when you don't want to load the entire response into
# memory.
#
# Use {#file} to access the `Tempfile` containing the raw response body. The
# file path is accessible at `.file.path`.
#
# **Note that like all `Tempfile` objects, the {#file} will be deleted when
# the object is dereferenced.**
#
# This class brings in all the common functionality from {AbstractResponse},
# such as {AbstractResponse.headers}, etc.
#
# @example
#
# r = RestClient::Request.execute(method: :get, url: 'http://example.com', raw_response: true)
# r.code
# # => 200
# puts r.file.inspect
# # => #<Tempfile:/tmp/rest-client.20170102-15213-b8kgcj>
# r.file.path
# # => "/tmp/rest-client.20170102-15213-b8kgcj"
# r.size
# # => 1270
#
# In addition, if you do not use the response as a string, you can access
# a Tempfile object at res.file, which contains the path to the raw
# downloaded request body.
class RawResponse
include AbstractResponse
@ -36,11 +57,18 @@ module RestClient
body
end
# Read the response body from {#file} into memory and return as a String.
#
# @return [String]
#
def body
@file.rewind
@file.read
end
# Return the response body file size.
#
# @return [Integer]
def size
file.size
end

View File

@ -15,24 +15,27 @@ module RestClient
# call it directly if you'd like to use a method not supported by the
# main API.
#
# @example using {.execute} class method:
# @example Using {.execute} class method:
# RestClient::Request.execute(method: :head, url: 'http://example.com')
#
# @example initializing {#initialize} and then calling {#execute}:
# @example Initializing {#initialize} and then calling {#execute}:
# req = RestClient::Request.new(method: :get, url: 'http://example.com', timeout: 5)
# req.execute
#
# The `:method` and `:url` parameters are required. All others are optional.
#
# @deprecated *Note:*
# The RestClient API has a very ugly misfeature that dates to the original
# design, where certain options are destructively pulled out of the
# `:headers` hash that normally contains HTTP request headers. This is
# because in the top-level helper shortcuts like {RestClient.get}, the only
# hash argument permitted is the headers hash, so there is no place to put
# options. For example, while it is currently allowed to pass options like
# `:params` or `:cookies` as keys inside the `:headers` hash, this is
# strongly discouraged.
# **See {#initialize} for the full list of available options.**
#
# **Deprecation note:**
# Certain options are accepted as keys in the headers hash, but doing so is
# deprecated. This misfeature in the RestClient API dates to the original
# design, where certain options are destructively pulled out of the
# `:headers` hash that normally contains HTTP request headers. This is
# because in the top-level helper shortcuts like {RestClient.get}, the only
# hash argument permitted is the headers hash, so there is no place to put
# options. For example, while it is currently allowed to pass options like
# `:params` or `:cookies` as keys inside the `:headers` hash, this is
# strongly discouraged.
#
class Request
@ -46,12 +49,18 @@ module RestClient
# Shorthand for initializing a Request and executing it.
#
# RestClient::Request.execute is a great way to pass complex options.
# `RestClient::Request.execute` is the recommended way to pass complex
# options. It is shorthand for `RestClient::Request.new(args).execute`.
#
# For example:
# RestClient::Request.execute(method: get, url: 'http://example.com', timeout: 5)
# @example
# RestClient::Request.execute(method: :get, url: 'http://example.com', timeout: 5)
#
# @see RestClient::Request
# @example
# RestClient::Request.execute(method: :get, url: 'http://httpbin.org/redirect/2', max_redirects: 1)
#
# @see RestClient::Request#initialize
#
# @return [RestClient::Response, RestClient::RawResponse]
#
def self.execute(args, & block)
new(args).execute(& block)
@ -71,15 +80,15 @@ module RestClient
#
# @param [Hash] args
#
# @option args [String] :url *Required.* The HTTP URL to request.
# @option args [String, Symbol] :method *Required.* The HTTP request method
# or verb, such as "GET", "HEAD", or "POST".
# @option args [String] :url **Required.** The HTTP URL to request.
# @option args [String, Symbol] :method **Required.** The HTTP request method
# or verb, such as `"GET"`, `"HEAD"`, or `"POST"`.
#
# @option args [Hash] :headers The HTTP request headers. Keys may be
# Symbol or String. Symbol keys will be converted to String header names
# by {#stringify_headers}. For backwards compatibility, this Hash
# recognizes certain keys that will be pulled out as options, but relying
# on this is deprecated and strongly discouraged.
# on this behavior is deprecated and strongly discouraged.
# @option args :cookies [HTTP::CookieJar, Hash{String, Symbol => String},
# Array<HTTP::Cookie>] The cookies to be sent with the request. This can
# be passed as a Hash, an array of HTTP::Cookie objects, or as a full
@ -121,10 +130,10 @@ module RestClient
# timeout on an individual network read, but does not limit the overall
# duration of the request so long as the server continues sending data at
# a trickle. Pass nil to disable the timeout. See
# {Net::HTTP#read_timeout}.
# `Net::HTTP#read_timeout`.
# @option args [Numeric, nil] :open_timeout Number of seconds to wait for
# the connection to be established. Pass nil to disable the timeout. See
# {Net::HTTP#open_timeout}.
# `Net::HTTP#open_timeout`.
# @option args [Numeric, nil] :timeout Set both `:read_timeout` and
# `:open_timeout`
# @option args :ssl_client_cert
@ -258,7 +267,7 @@ module RestClient
# Extract the query parameters and append them to the url
#
# Look through the headers hash for a :params option (case-insensitive,
# Look through the headers hash for a `:params` option (case-insensitive,
# may be string or symbol). If present and the value is a Hash or
# RestClient::ParamsArray, *delete* the key/value pair from the headers
# hash and encode the value into a query string. Append this query string
@ -266,10 +275,12 @@ module RestClient
#
# @param [String] url
# @param [Hash] headers An options/headers hash to process. Mutation
# warning: the params key may be removed if present!
# warning: the `params` key may be removed if present!
#
# @return [String] resulting url with query string
#
# @api private
#
def process_url_params(url, headers)
url_params = nil
@ -342,19 +353,21 @@ module RestClient
end
# Process cookies passed as hash or as HTTP::CookieJar. For backwards
# compatibility, these may be passed as a :cookies option masquerading
# inside the headers hash. To avoid confusion, if :cookies is passed in
# both headers and Request#initialize, raise an error.
# compatibility, these may be passed as a `:cookies` option masquerading
# inside the headers hash. To avoid confusion, if `:cookies` is passed in
# both headers and {#initialize}, raise an error.
#
# :cookies may be a:
# - Hash{String/Symbol => String}
# - Array<HTTP::Cookie>
# - HTTP::CookieJar
# `:cookies` may be a:
#
# - `Hash{String/Symbol => String}`
# - `Array<HTTP::Cookie>`
# - `HTTP::CookieJar`
#
# **Passing as a hash:**
#
# Passing as a hash:
# Keys may be symbols or strings. Values must be strings.
# Infer the domain name from the request URI and allow subdomains (as
# though '.example.com' had been set in a Set-Cookie header). Assume a
# though '.example.com' had been set in a `Set-Cookie` header). Assume a
# path of '/'.
#
# RestClient::Request.new(url: 'http://example.com', method: :get,
@ -362,28 +375,30 @@ module RestClient
# )
#
# results in cookies as though set from the server by:
#
# Set-Cookie: foo=Value; Domain=.example.com; Path=/
# Set-Cookie: bar=123; Domain=.example.com; Path=/
#
# which yields a client cookie header of:
#
# Cookie: foo=Value; bar=123
#
# Passing as HTTP::CookieJar, which will be passed through directly:
# **Passing as HTTP::CookieJar, which will be passed through directly:**
#
# jar = HTTP::CookieJar.new
# jar.add(HTTP::Cookie.new('foo', 'Value', domain: 'example.com',
# path: '/', for_domain: false))
#
# RestClient::Request.new(..., :cookies => jar)
# RestClient::Request.new('...', :cookies => jar)
#
# @param [URI::HTTP] uri The URI for the request. This will be used to
# infer the domain name for cookies passed as strings in a hash. To avoid
# this implicit behavior, pass a full cookie jar or use HTTP::Cookie hash
# values.
# @param [Hash] headers The headers hash from which to pull the :cookies
# option. MUTATION NOTE: This key will be deleted from the hash if
# present.
# @param [Hash] args The options passed to Request#initialize. This hash
# infer the domain name for cookies passed as strings in a hash. To avoid
# this implicit behavior, pass a full cookie jar or use `HTTP::Cookie`
# hash values.
# @param [Hash] headers The headers hash from which to pull the `:cookies`
# option. **MUTATION NOTE:** This key will be deleted from the hash if
# present. Passing cookies in this way is deprecated.
# @param [Hash] args The options passed to {Request#initialize}. This hash
# will be used as another potential source for the :cookies key.
# These args will not be mutated.
#
@ -439,19 +454,20 @@ module RestClient
end
# Generate headers for use by a request. Header keys will be stringified
# using `#stringify_headers` to normalize them as capitalized strings.
# using {#stringify_headers} to normalize them as capitalized strings.
#
# The final headers consist of:
# - default headers from #default_headers
# - user_headers provided here
# - headers from the payload object (e.g. Content-Type, Content-Lenth)
# - cookie headers from #make_cookie_header
#
# BUG: stringify_headers does not alter the capitalization of headers that
# are passed as strings, it only normalizes those passed as symbols. This
# behavior will probably remain for a while for compatibility, but it means
# that the warnings that attempt to detect accidental header overrides may
# not always work.
# - default headers from {#default_headers}
# - `user_headers` provided here
# - headers from the payload object (e.g. Content-Type, Content-Lenth)
# - cookie headers from {#make_cookie_header}
#
# **BUG:** stringify_headers does not alter the capitalization of headers
# that are passed as strings, it only normalizes those passed as symbols.
# This behavior will probably remain for a while for compatibility, but it
# means that the warnings that attempt to detect accidental header
# overrides may not always work.
# https://github.com/rest-client/rest-client/issues/599
#
# @param [Hash] user_headers User-provided headers to include
@ -494,7 +510,7 @@ module RestClient
end
# The proxy URI for this request. If `:proxy` was provided on this request,
# use it over `RestClient.proxy`.
# use it over {RestClient.proxy}.
#
# Return false if a proxy was explicitly set and is falsy.
#
@ -518,6 +534,17 @@ module RestClient
end
end
# Create a new Net::HTTP object representing a connection to a server
# without actually opening the connection. This method will set up an HTTP
# proxy according to {#proxy_uri}.
#
# @param hostname [String]
# @param port [Integer]
#
# @return [Net::HTTP]
#
# @api private
#
def net_http_object(hostname, port)
p_uri = proxy_uri
@ -534,10 +561,28 @@ module RestClient
end
end
# Find the Net::HTTPRequest subclass for a given HTTP method/verb.
#
# @param method [Symbol, String]
#
# @return [Class] A subclass of Net::HTTPRequest.
#
# @api private
#
def net_http_request_class(method)
Net::HTTP.const_get(method.capitalize, false)
end
# Actually execute the request with Net::HTTP.
#
# @param http [Net::HTTP]
# @param req [Net::HTTPRequest]
# @param body [String, IO, nil]
#
# @see https://ruby-doc.org/stdlib-2.4.0/libdoc/net/http/rdoc/Net/HTTP.html#method-i-request
# Net::HTTP#request
#
# @api private
def net_http_do_request(http, req, body=nil, &block)
if body && body.respond_to?(:read)
req.body_stream = body
@ -557,6 +602,8 @@ module RestClient
#
# @return [String]
#
# @api private
#
def normalize_url(url)
url = 'http://' + url unless url.match(%r{\A[a-z][a-z0-9+.-]*://}i)
url
@ -605,11 +652,20 @@ module RestClient
redacted_uri.to_s
end
# Default to the global logger if there's not a request-specific one
# The log used for this request.
#
# Defaults to the global logger {RestClient.log} if there was no `:log`
# option set on this request.
#
def log
@log || RestClient.log
end
# Write log information about the request. Called just prior to sending the
# request to the server.
#
# @return [void]
#
def log_request
return unless log

View File

@ -4,34 +4,34 @@ module RestClient
#
# Example:
#
# resource = RestClient::Resource.new('http://some/resource')
# jpg = resource.get(:accept => 'image/jpg')
# resource = RestClient::Resource.new('http://some/resource')
# jpg = resource.get(:accept => 'image/jpg')
#
# With HTTP basic authentication:
#
# resource = RestClient::Resource.new('http://protected/resource', :user => 'user', :password => 'password')
# resource.delete
# resource = RestClient::Resource.new('http://protected/resource', :user => 'user', :password => 'password')
# resource.delete
#
# With a timeout (seconds):
#
# RestClient::Resource.new('http://slow', :read_timeout => 10)
# RestClient::Resource.new('http://slow', :read_timeout => 10)
#
# With an open timeout (seconds):
#
# RestClient::Resource.new('http://behindfirewall', :open_timeout => 10)
# RestClient::Resource.new('http://behindfirewall', :open_timeout => 10)
#
# You can also use resources to share common headers. For headers keys,
# symbols are converted to strings. Example:
#
# resource = RestClient::Resource.new('http://some/resource', :headers => { :client_version => 1 })
# resource = RestClient::Resource.new('http://some/resource', :headers => { :client_version => 1 })
#
# This header will be transported as X-Client-Version (notice the X prefix,
# capitalization and hyphens)
#
# Use the [] syntax to allocate subresources:
#
# site = RestClient::Resource.new('http://example.com', :user => 'adam', :password => 'mypasswd')
# site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
# site = RestClient::Resource.new('http://example.com', :user => 'adam', :password => 'mypasswd')
# site['posts/1/comments'].post 'Good article.', :content_type => 'text/plain'
#
class Resource
attr_reader :url, :options, :block

View File

@ -2,6 +2,17 @@ module RestClient
# A Response from RestClient, you can access the response body, the code or the headers.
#
# Response is a subclass of `String` for backwards compatibility. This may
# change in a future major release of RestClient, so it is recommended to
# explicitly call {#body} or {#to_s} before invoking `String` methods.
#
# The request that resulted in this response is accessible at {#request}.
#
# Much of the functionality is implemented on the {AbstractResponse} module.
#
# @see AbstractResponse
# @see RawResponse
#
class Response < String
include AbstractResponse
@ -38,14 +49,17 @@ module RestClient
"<RestClient::Response #{code.inspect} #{body_truncated(10).inspect}>"
end
# Initialize a Response object. Because RestClient::Response is
# Initialize a Response object. Because `RestClient::Response` is
# (unfortunately) a subclass of String for historical reasons,
# Response.create is the preferred initializer.
# `Response.create` is the preferred initializer.
#
# @param [String, nil] body The response body from the Net::HTTPResponse
# @param [Net::HTTPResponse] net_http_res
# @param [RestClient::Request] request
# @param [Time] start_time
#
# @return [Response]
#
def self.create(body, net_http_res, request, start_time=nil)
result = self.new(body || '')
@ -55,8 +69,13 @@ module RestClient
result
end
# Set the String encoding according to the 'Content-Type: charset' header,
# Set the String encoding according to the `Content-Type: charset` header,
# if possible.
#
# @param response [Response]
#
# @return [Response]
#
def self.fix_encoding(response)
charset = RestClient::Utils.get_encoding_from_headers(response.headers)
encoding = nil

View File

@ -1,7 +1,12 @@
module RestClient
# The current RestClient version array
VERSION_INFO = [2, 1, 0, 'rc1'] unless defined?(self::VERSION_INFO)
# The current RestClient version string
VERSION = VERSION_INFO.map(&:to_s).join('.') unless defined?(self::VERSION)
# @return [String] The current RestClient version string
def self.version
VERSION
end