diff --git a/lib/http/chainable.rb b/lib/http/chainable.rb index a3d9d49b..0ff4c8d4 100644 --- a/lib/http/chainable.rb +++ b/lib/http/chainable.rb @@ -95,27 +95,7 @@ def timeout(options) klass, options = case options when Numeric then [HTTP::Timeout::Global, {:global_timeout => options}] when Hash - options = options.dup - %i[read write connect].each do |k| - next unless options.key? k - - if options.key?("#{k}_timeout".to_sym) - raise ArgumentError, "can't pass both #{k} and #{"#{k}_timeout".to_sym}" - end - - options["#{k}_timeout".to_sym] = options.delete k - end - - options.each do |key, value| - unless HTTP::Timeout::PerOperation::SETTINGS.member?(key) && value.is_a?(Numeric) - raise ArgumentError, "invalid option #{key.inspect}, must be numeric " \ - "`.timeout(connect: x, write: y, read: z)`." - end - end - - raise ArgumentError, "at least one option" if options.empty? - - [HTTP::Timeout::PerOperation, options.dup] + [HTTP::Timeout::PerOperation, HTTP::Timeout::PerOperation.parse_options(options)] when :null then [HTTP::Timeout::Null, {}] else raise ArgumentError, "Use `.timeout(:null)`, " \ "`.timeout(global_timeout_in_seconds)` or " \ diff --git a/lib/http/timeout/per_operation.rb b/lib/http/timeout/per_operation.rb index f80d751f..bb20b57d 100644 --- a/lib/http/timeout/per_operation.rb +++ b/lib/http/timeout/per_operation.rb @@ -20,6 +20,38 @@ def initialize(*args) @connect_timeout = options.fetch(:connect_timeout, CONNECT_TIMEOUT) end + class << self + def parse_options(options) + options = options.dup.then { |opts| undo_short_names(opts) } + options.each do |key, value| + unless SETTINGS.member?(key) && value.is_a?(Numeric) + raise ArgumentError, "invalid option #{key.inspect}, must be numeric " \ + "`.timeout(connect: x, write: y, read: z)`." + end + end + + raise ArgumentError, "at least one option" if options.empty? + + options + end + + private + + def undo_short_names(options) + %i[read write connect].each do |k| + next unless options.key? k + + if options.key?("#{k}_timeout".to_sym) + raise ArgumentError, "can't pass both #{k} and #{"#{k}_timeout".to_sym}" + end + + options["#{k}_timeout".to_sym] = options.delete k + end + + options + end + end + def connect(socket_class, host, port, nodelay = false) ::Timeout.timeout(@connect_timeout, ConnectTimeoutError) do @socket = socket_class.open(host, port)