lib/stripe/util.rb in stripe-3.3.2 vs lib/stripe/util.rb in stripe-3.4.1
- old
+ new
@@ -1,9 +1,25 @@
require "cgi"
module Stripe
module Util
+ # Options that a user is allowed to specify.
+ OPTS_USER_SPECIFIED = Set[
+ :api_key,
+ :idempotency_key,
+ :stripe_account,
+ :stripe_version
+ ].freeze
+
+ # Options that should be copyable from one StripeObject to another
+ # including options that may be internal.
+ OPTS_COPYABLE = (OPTS_USER_SPECIFIED + Set[:api_base]).freeze
+
+ # Options that should be persisted between API requests. This includes
+ # client, which is an object containing an HTTP client to reuse.
+ OPTS_KEYS_TO_PERSIST = (OPTS_USER_SPECIFIED + Set[:client]).freeze
+
def self.objects_to_ids(h)
case h
when APIResource
h.id
when Hash
@@ -89,51 +105,54 @@
end
end
def self.log_error(message, data = {})
if !Stripe.logger.nil? ||
- !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_ERROR
+ !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_ERROR
log_internal(message, data, color: :cyan,
- level: Stripe::LEVEL_ERROR, logger: Stripe.logger, out: $stderr)
+ level: Stripe::LEVEL_ERROR, logger: Stripe.logger, out: $stderr)
end
end
def self.log_info(message, data = {})
if !Stripe.logger.nil? ||
- !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_INFO
+ !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_INFO
log_internal(message, data, color: :cyan,
- level: Stripe::LEVEL_INFO, logger: Stripe.logger, out: $stdout)
+ level: Stripe::LEVEL_INFO, logger: Stripe.logger, out: $stdout)
end
end
def self.log_debug(message, data = {})
if !Stripe.logger.nil? ||
- !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_DEBUG
+ !Stripe.log_level.nil? && Stripe.log_level <= Stripe::LEVEL_DEBUG
log_internal(message, data, color: :blue,
- level: Stripe::LEVEL_DEBUG, logger: Stripe.logger, out: $stdout)
+ level: Stripe::LEVEL_DEBUG, logger: Stripe.logger, out: $stdout)
end
end
def self.file_readable(file)
# This is nominally equivalent to File.readable?, but that can
# report incorrect results on some more oddball filesystems
# (such as AFS)
- begin
- File.open(file) { |f| }
- rescue
- false
- else
- true
- end
+
+ File.open(file) { |f| }
+ rescue StandardError
+ false
+ else
+ true
end
def self.symbolize_names(object)
case object
when Hash
new_hash = {}
object.each do |key, value|
- key = (key.to_sym rescue key) || key
+ key = (begin
+ key.to_sym
+ rescue StandardError
+ key
+ end) || key
new_hash[key] = symbolize_names(value)
end
new_hash
when Array
object.map { |value| symbolize_names(value) }
@@ -145,22 +164,22 @@
# Encodes a hash of parameters in a way that's suitable for use as query
# parameters in a URI or as form parameters in a request body. This mainly
# involves escaping special characters from parameter keys and values (e.g.
# `&`).
def self.encode_parameters(params)
- Util.flatten_params(params).
- map { |k,v| "#{url_encode(k)}=#{url_encode(v)}" }.join('&')
+ Util.flatten_params(params)
+ .map { |k, v| "#{url_encode(k)}=#{url_encode(v)}" }.join("&")
end
# Transforms an array into a hash with integer keys. Used for a small
# number of API endpoints. If the argument is not an Array, return it
# unchanged. Example: [{foo: 'bar'}] => {"0" => {foo: "bar"}}
def self.array_to_hash(array)
case array
when Array
hash = {}
- array.each_with_index { |v,i| hash[i.to_s] = v }
+ array.each_with_index { |v, i| hash[i.to_s] = v }
hash
else
array
end
end
@@ -171,20 +190,20 @@
def self.url_encode(key)
CGI.escape(key.to_s).
# Don't use strict form encoding by changing the square bracket control
# characters back to their literals. This is fine by the server, and
# makes these parameter strings easier to read.
- gsub('%5B', '[').gsub('%5D', ']')
+ gsub("%5B", "[").gsub("%5D", "]")
end
- def self.flatten_params(params, parent_key=nil)
+ def self.flatten_params(params, parent_key = nil)
result = []
# do not sort the final output because arrays (and arrays of hashes
# especially) can be order sensitive, but do sort incoming parameters
params.each do |key, value|
- calculated_key = parent_key ? "#{parent_key}[#{key}]" : "#{key}"
+ calculated_key = parent_key ? "#{parent_key}[#{key}]" : key.to_s
if value.is_a?(Hash)
result += flatten_params(value, calculated_key)
elsif value.is_a?(Array)
check_array_of_maps_start_keys!(value)
result += flatten_params_array(value, calculated_key)
@@ -209,11 +228,11 @@
end
result
end
def self.normalize_id(id)
- if id.kind_of?(Hash) # overloaded id
+ if id.is_a?(Hash) # overloaded id
params_hash = id.dup
id = params_hash.delete(:id)
else
params_hash = {}
end
@@ -223,44 +242,43 @@
# The secondary opts argument can either be a string or hash
# Turn this value into an api_key and a set of headers
def self.normalize_opts(opts)
case opts
when String
- {:api_key => opts}
+ { api_key: opts }
when Hash
- check_api_key!(opts.fetch(:api_key)) if opts.has_key?(:api_key)
+ check_api_key!(opts.fetch(:api_key)) if opts.key?(:api_key)
opts.clone
else
- raise TypeError.new('normalize_opts expects a string or a hash')
+ raise TypeError, "normalize_opts expects a string or a hash"
end
end
def self.check_string_argument!(key)
- raise TypeError.new("argument must be a string") unless key.is_a?(String)
+ raise TypeError, "argument must be a string" unless key.is_a?(String)
key
end
def self.check_api_key!(key)
- raise TypeError.new("api_key must be a string") unless key.is_a?(String)
+ raise TypeError, "api_key must be a string" unless key.is_a?(String)
key
end
# Normalizes header keys so that they're all lower case and each
# hyphen-delimited section starts with a single capitalized letter. For
# example, `request-id` becomes `Request-Id`. This is useful for extracting
# certain key values when the user could have set them with a variety of
# diffent naming schemes.
def self.normalize_headers(headers)
- headers.inject({}) do |new_headers, (k, v)|
+ headers.each_with_object({}) do |(k, v), new_headers|
if k.is_a?(Symbol)
- k = titlecase_parts(k.to_s.gsub("_", "-"))
+ k = titlecase_parts(k.to_s.tr("_", "-"))
elsif k.is_a?(String)
k = titlecase_parts(k)
end
new_headers[k] = v
- new_headers
end
end
# Generates a Dashboard link to inspect a request ID based off of a request
# ID value and an API key, which is used to attempt to extract whether the
@@ -277,26 +295,28 @@
l = a.unpack "C#{a.bytesize}"
res = 0
b.each_byte { |byte| res |= byte ^ l.shift }
- res == 0
+ res.zero?
end
- private
+ #
+ # private
+ #
COLOR_CODES = {
- :black => 0, :light_black => 60,
- :red => 1, :light_red => 61,
- :green => 2, :light_green => 62,
- :yellow => 3, :light_yellow => 63,
- :blue => 4, :light_blue => 64,
- :magenta => 5, :light_magenta => 65,
- :cyan => 6, :light_cyan => 66,
- :white => 7, :light_white => 67,
- :default => 9
- }
+ black: 0, light_black: 60,
+ red: 1, light_red: 61,
+ green: 2, light_green: 62,
+ yellow: 3, light_yellow: 63,
+ blue: 4, light_blue: 64,
+ magenta: 5, light_magenta: 65,
+ cyan: 6, light_cyan: 66,
+ white: 7, light_white: 67,
+ default: 9,
+ }.freeze
private_constant :COLOR_CODES
# We use a pretty janky version of form encoding (Rack's) that supports
# more complex data structures like maps and arrays through the use of
# specialized syntax. To encode an array of maps like:
@@ -315,20 +335,20 @@
# the array contains all non-empty maps, that each of those maps must start
# with the same key so that their boundaries can be properly encoded.
def self.check_array_of_maps_start_keys!(arr)
expected_key = nil
arr.each do |item|
- return if !item.is_a?(Hash)
- return if item.count == 0
+ break unless item.is_a?(Hash)
+ break if item.count.zero?
first_key = item.first[0]
if expected_key
if expected_key != first_key
raise ArgumentError,
- "All maps nested in an array should start with the same key " +
- "(expected starting key '#{expected_key}', got '#{first_key}')"
+ "All maps nested in an array should start with the same key " \
+ "(expected starting key '#{expected_key}', got '#{first_key}')"
end
else
expected_key = first_key
end
end
@@ -360,38 +380,33 @@
private_class_method :level_name
# TODO: Make these named required arguments when we drop support for Ruby
# 2.0.
def self.log_internal(message, data = {}, color: nil, level: nil, logger: nil, out: nil)
- data_str = data.select { |k,v| !v.nil? }.
- map { |(k,v)|
- "%s=%s" % [
- colorize(k, color, !out.nil? && out.isatty),
- wrap_logfmt_value(v)
- ]
- }.join(" ")
+ data_str = data.reject { |_k, v| v.nil? }
+ .map do |(k, v)|
+ format("%s=%s", colorize(k, color, !out.nil? && out.isatty), wrap_logfmt_value(v))
+ end.join(" ")
if !logger.nil?
# the library's log levels are mapped to the same values as the
# standard library's logger
logger.log(level,
- "message=%s %s" % [wrap_logfmt_value(message), data_str])
+ format("message=%s %s", wrap_logfmt_value(message), data_str))
elsif out.isatty
- out.puts "%s %s %s" %
- [colorize(level_name(level)[0, 4].upcase, color, out.isatty), message, data_str]
+ out.puts format("%s %s %s", colorize(level_name(level)[0, 4].upcase, color, out.isatty), message, data_str)
else
- out.puts "message=%s level=%s %s" %
- [wrap_logfmt_value(message), level_name(level), data_str]
+ out.puts format("message=%s level=%s %s", wrap_logfmt_value(message), level_name(level), data_str)
end
end
private_class_method :log_internal
def self.titlecase_parts(s)
- s.split("-").
- select { |p| p != "" }.
- map { |p| p[0].upcase + p[1..-1].downcase }.
- join("-")
+ s.split("-")
+ .reject { |p| p == "" }
+ .map { |p| p[0].upcase + p[1..-1].downcase }
+ .join("-")
end
private_class_method :titlecase_parts
# Wraps a value in double quotes if it looks sufficiently complex so that
# it can be read by logfmt parsers.
@@ -404,10 +419,10 @@
val = val.to_s
if %r{[^\w\-/]} =~ val
# If the string contains any special characters, escape any double
# quotes it has, remove newlines, and wrap the whole thing in quotes.
- %{"%s"} % val.gsub('"', '\"').gsub("\n", "")
+ format(%("%s"), val.gsub('"', '\"').delete("\n"))
else
# Otherwise use the basic value if it looks like a standard set of
# characters (and allow a few special characters like hyphens, and
# slashes)
val