Commit d98902a

mo khan <mo.khan@gmail.com>
2020-06-13 00:00:48
Reduce # of instance variables
1 parent 5e327cc
lib/net/hippie/client.rb
@@ -10,26 +10,24 @@ module Net
         'User-Agent' => "net/hippie #{Net::Hippie::VERSION}"
       }.freeze
 
-      attr_accessor :mapper, :read_timeout, :open_timeout, :logger
-      attr_accessor :follow_redirects
-      attr_accessor :certificate, :key, :passphrase
+      attr_reader :mapper, :logger
+      attr_reader :follow_redirects
 
       def initialize(options = {})
-        @default_headers = options.fetch(:headers, DEFAULT_HEADERS)
+        @options = options
         @mapper = options.fetch(:mapper, ContentTypeMapper.new)
-        @read_timeout = options.fetch(:read_timeout, 10)
-        @open_timeout = options.fetch(:open_timeout, 10)
-        @verify_mode = options.fetch(:verify_mode, Net::Hippie.verify_mode)
         @logger = options.fetch(:logger, Net::Hippie.logger)
         @follow_redirects = options.fetch(:follow_redirects, 0)
-        @certificate = options[:certificate]
-        @key = options[:key]
-        @passphrase = options[:passphrase]
-        @connections = {}
+        @http_connections = Hash.new do |hash, key|
+          uri = URI.parse(key.to_s)
+          build_http_for(uri).tap do |http|
+            hash[key] = http
+          end
+        end
       end
 
       def execute(uri, request, limit: follow_redirects, &block)
-        http = http_for(uri)
+        http = @http_connections[uri]
         response = http.request(request)
         if limit.positive? && response.is_a?(Net::HTTPRedirection)
           url = build_url_for(http, response['location'])
@@ -80,7 +78,9 @@ module Net
 
       private
 
-      attr_reader :default_headers, :verify_mode
+      def default_headers
+        @options.fetch(:headers, DEFAULT_HEADERS)
+      end
 
       def attempt(attempt, max)
         yield
@@ -92,38 +92,33 @@ module Net
         sleep delay
       end
 
-      def http_for(uri)
-        @connections.fetch(uri.to_s) do |key|
-          uri = URI.parse(uri.to_s)
-          http = Net::HTTP.new(uri.host, uri.port)
-          http.read_timeout = read_timeout
-          http.open_timeout = open_timeout
-          http.use_ssl = uri.scheme == 'https'
-          http.verify_mode = verify_mode
-          http.set_debug_output(logger)
-          apply_client_tls_to(http)
-          @connections[key] = http
-          http
-        end
+      def build_http_for(uri)
+        http = Net::HTTP.new(uri.host, uri.port)
+        http.read_timeout = @options.fetch(:read_timeout, 10)
+        http.open_timeout = @options.fetch(:open_timeout, 10)
+        http.use_ssl = uri.scheme == 'https'
+        http.verify_mode = @options.fetch(:verify_mode, Net::Hippie.verify_mode)
+        http.set_debug_output(logger)
+        apply_client_tls_to(http)
+        http
       end
 
       def request_for(type, uri, headers: {}, body: {})
         final_headers = default_headers.merge(headers)
-        uri = URI.parse(uri.to_s)
-        type.new(uri, final_headers).tap do |x|
+        type.new(URI.parse(uri.to_s), final_headers).tap do |x|
           x.body = mapper.map_from(final_headers, body) unless body.empty?
         end
       end
 
-      def private_key(type = OpenSSL::PKey::RSA)
+      def private_key(key, passphrase, type = OpenSSL::PKey::RSA)
         passphrase ? type.new(key, passphrase) : type.new(key)
       end
 
       def apply_client_tls_to(http)
-        return if certificate.nil? || key.nil?
+        return if @options[:certificate].nil? || @options[:key].nil?
 
-        http.cert = OpenSSL::X509::Certificate.new(certificate)
-        http.key = private_key
+        http.cert = OpenSSL::X509::Certificate.new(@options[:certificate])
+        http.key = private_key(@options[:key], @options[:passphrase])
       end
 
       def run(uri, http_method, headers, body, &block)
lib/net/hippie/content_type_mapper.rb
@@ -5,6 +5,8 @@ module Net
     # Converts a ruby hash into a JSON string
     class ContentTypeMapper
       def map_from(headers, body)
+        return body if body.is_a?(String)
+
         content_type = headers['Content-Type'] || ''
         return JSON.generate(body) if content_type.include?('json')
 
lib/net/hippie/version.rb
@@ -2,6 +2,6 @@
 
 module Net
   module Hippie
-    VERSION = '0.3.2'
+    VERSION = '1.0.0'
   end
 end
lib/net/hippie.rb
@@ -56,11 +56,15 @@ module Net
     def self.method_missing(symbol, *args)
       default_client.with_retry(retries: 3) do |client|
         client.public_send(symbol, *args)
-      end
+      end || super
+    end
+
+    def self.respond_to_missing?(name, _include_private = false)
+      Client.public_instance_methods.include?(name.to_sym)
     end
 
     def self.default_client
-      @subject ||= Client.new
+      @default_client ||= Client.new(follow_redirects: 3, logger: logger)
     end
   end
 end
test/net/client_test.rb
@@ -6,7 +6,6 @@ class ClientTest < Minitest::Test
   def initialize(*args)
     super
     @subject = Net::Hippie::Client.new
-    @subject.logger = ENV['CIBUILD'] ? Logger.new('/dev/null') : Logger.new(STDOUT)
   end
 
   def test_get
@@ -27,7 +26,7 @@ class ClientTest < Minitest::Test
         https://pypi.org/pypi/pytz/2019.2/json
         https://pypi.org/pypi/requests/2.5.3/json
       }.each do |url|
-        subject.follow_redirects = 3
+        subject = Net::Hippie::Client.new(follow_redirects: 3)
         response = subject.get(url)
         refute_nil response
         assert_equal Net::HTTPOK, response.class
@@ -38,7 +37,7 @@ class ClientTest < Minitest::Test
 
   def test_does_not_follow_redirect
     VCR.use_cassette('does_not_follow_redirect') do
-      subject.follow_redirects = 0
+      subject = Net::Hippie::Client.new(follow_redirects: 0)
       response = subject.get('https://pypi.org/pypi/django/1.11.3/json')
       refute_nil response
       assert_kind_of Net::HTTPRedirection, response
@@ -48,7 +47,7 @@ class ClientTest < Minitest::Test
 
   def test_does_follow_redirects
     VCR.use_cassette('does_follow_redirects') do
-      subject.follow_redirects = 10
+      subject = Net::Hippie::Client.new(follow_redirects: 10)
       response = subject.get('https://pypi.org/pypi/django/1.11.3/json')
       refute_nil response
       assert_kind_of Net::HTTPOK, response
@@ -58,7 +57,7 @@ class ClientTest < Minitest::Test
 
   def test_follow_redirects_with_relative_paths
     VCR.use_cassette('follow_redirects_with_relative_paths') do
-      subject.follow_redirects = 10
+      subject = Net::Hippie::Client.new(follow_redirects: 10)
       response = subject.get("http://go.microsoft.com/fwlink/?LinkId=329770")
       refute_nil response
       assert_kind_of Net::HTTPOK, response
@@ -76,7 +75,7 @@ class ClientTest < Minitest::Test
       .then
       .to_return(status: 200, body: { success: true }.to_json)
 
-    subject.follow_redirects = n
+    subject = Net::Hippie::Client.new(follow_redirects: n)
     response = subject.get(url)
     refute_nil response
     assert_equal Net::HTTPOK, response.class
@@ -304,10 +303,4 @@ class ClientTest < Minitest::Test
     end
     assert(@called)
   end
-
-  def test_open_timeout_setting
-    assert_equal subject.open_timeout, 10
-    @subject.open_timeout = 5
-    assert_equal subject.open_timeout, 5
-  end
 end
test/test_helper.rb
@@ -7,6 +7,8 @@ require 'securerandom'
 require 'vcr'
 require 'webmock'
 
+Net::Hippie.logger = ENV['CIBUILD'] ? Logger.new('/dev/null') : Logger.new(STDERR)
+
 VCR.configure do |config|
   config.cassette_library_dir = 'test/fixtures'
   config.hook_into :webmock
.rubocop.yml
@@ -5,7 +5,7 @@ AllCops:
     - 'test/**/*'
     - 'tmp/**/*'
     - 'vendor/**/*'
-  TargetRubyVersion: 2.4
+  TargetRubyVersion: 2.5
 
 Layout/ParameterAlignment:
   EnforcedStyle: with_fixed_indentation
net-hippie.gemspec
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
   spec.bindir        = 'exe'
   spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
   spec.require_paths = ['lib']
-  spec.required_ruby_version = '~> 2.4'
+  spec.required_ruby_version = '~> 2.5'
 
   spec.add_development_dependency 'minitest', '~> 5.0'
   spec.add_development_dependency 'rake', '~> 13.0'