From 9b6748ddbe41a7ff65b86382670631bbb0f43ec6 Mon Sep 17 00:00:00 2001 From: Javier Blanco Date: Thu, 14 May 2015 08:12:27 +0200 Subject: [PATCH] Allow setting a custom URI adapter This option allows you to roll out fancier URI parsers like the one offered by the Addressable gem. Addressable is a replacement for the URI implementation that is part of Ruby's standard library. It more closely conforms to RFC 3986, RFC 3987, and RFC 6570 (level 4), additionally providing support for IRIs and URI templates. http://addressable.rubyforge.org/ --- lib/httparty.rb | 12 +++++++++ lib/httparty/connection_adapter.rb | 3 ++- lib/httparty/request.rb | 9 ++++--- spec/httparty_spec.rb | 39 ++++++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 4 deletions(-) diff --git a/lib/httparty.rb b/lib/httparty.rb index c62c967..fbd0d71 100644 --- a/lib/httparty.rb +++ b/lib/httparty.rb @@ -49,6 +49,7 @@ module HTTParty # * :+maintain_method_across_redirects+: see HTTParty::ClassMethods.maintain_method_across_redirects. # * :+no_follow+: see HTTParty::ClassMethods.no_follow. # * :+parser+: see HTTParty::ClassMethods.parser. + # * :+uri_adapter+: see HTTParty::ClassMethods.uri_adapter # * :+connection_adapter+: see HTTParty::ClassMethods.connection_adapter. # * :+pem+: see HTTParty::ClassMethods.pem. # * :+query_string_normalizer+: see HTTParty::ClassMethods.query_string_normalizer @@ -419,6 +420,17 @@ module HTTParty end end + # Allows setting a custom URI adapter. + # + # class Foo + # include HTTParty + # uri_adapter Addressable::URI + # end + def uri_adapter(uri_adapter) + raise ArgumentError, 'The URI adapter should respond to #parse' unless uri_adapter.respond_to?(:parse) + default_options[:uri_adapter] = uri_adapter + end + # Allows setting a custom connection_adapter for the http connections # # @example diff --git a/lib/httparty/connection_adapter.rb b/lib/httparty/connection_adapter.rb index 635799c..7a4d467 100644 --- a/lib/httparty/connection_adapter.rb +++ b/lib/httparty/connection_adapter.rb @@ -61,7 +61,8 @@ module HTTParty attr_reader :uri, :options def initialize(uri, options = {}) - raise ArgumentError, "uri must be a URI, not a #{uri.class}" unless uri.is_a? URI + uri_adapter = options[:uri_adapter] || URI + raise ArgumentError, "uri must be a #{uri_adapter}, not a #{uri.class}" unless uri.is_a? uri_adapter @uri = uri @options = options diff --git a/lib/httparty/request.rb b/lib/httparty/request.rb index f8d2b9e..8f7b323 100644 --- a/lib/httparty/request.rb +++ b/lib/httparty/request.rb @@ -37,6 +37,7 @@ module HTTParty default_params: {}, follow_redirects: true, parser: Parser, + uri_adapter: URI, connection_adapter: ConnectionAdapter }.merge(o) self.path = path @@ -90,13 +91,15 @@ module HTTParty end def URI uri - if uri.is_a?(URI) + uri_adapter = options[:uri_adapter] + + if uri.is_a?(uri_adapter) uri elsif uri = String.try_convert(uri) - URI.parse uri + uri_adapter.parse uri else raise ArgumentError, - "bad argument (expected URI object or URI string)" + "bad argument (expected #{uri_adapter} object or URI string)" end end diff --git a/spec/httparty_spec.rb b/spec/httparty_spec.rb index 914202e..139c102 100644 --- a/spec/httparty_spec.rb +++ b/spec/httparty_spec.rb @@ -351,6 +351,45 @@ RSpec.describe HTTParty do end end + describe "uri_adapter" do + + require 'forwardable' + class CustomURIAdaptor + extend Forwardable + def_delegators :@uri, :userinfo, :relative?, :query, :query=, :scheme, :path, :host, :port + + def initialize uri + @uri = uri + end + + def self.parse uri + new URI.parse uri + end + end + + let(:uri_adapter) { CustomURIAdaptor } + + it "should set the uri_adapter" do + @klass.uri_adapter uri_adapter + expect(@klass.default_options[:uri_adapter]).to be uri_adapter + end + + it "should raise an ArgumentError if uri_adapter doesn't implement parse method" do + expect do + @klass.uri_adapter double() + end.to raise_error(ArgumentError) + end + + + it "should process a request with a uri instance parsed from the uri_adapter" do + uri = 'http://foo.com/bar' + FakeWeb.register_uri(:get, uri, body: 'stuff') + @klass.uri_adapter uri_adapter + expect(@klass.get(uri).parsed_response).to eq('stuff') + end + + end + describe "connection_adapter" do let(:uri) { 'http://google.com/api.json' } let(:connection_adapter) { double('CustomConnectionAdapter') }