From 73744b0d6b6a5c5ce28e7d9b1ae274e76d3ff4cc Mon Sep 17 00:00:00 2001 From: Jon Rowe Date: Wed, 8 Apr 2020 16:33:26 +0100 Subject: [PATCH] Refactor respond to matcher extracting arity logic to reduce class length --- lib/rspec/matchers/built_in/respond_to.rb | 91 ++++++++++++----------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/lib/rspec/matchers/built_in/respond_to.rb b/lib/rspec/matchers/built_in/respond_to.rb index 9fa4c7ef4..9adbe04ea 100644 --- a/lib/rspec/matchers/built_in/respond_to.rb +++ b/lib/rspec/matchers/built_in/respond_to.rb @@ -1,7 +1,5 @@ RSpec::Support.require_rspec_support "method_signature_verifier" -# TODO: Refactor this file to be under our class length -# rubocop:disable ClassLength module RSpec module Matchers module BuiltIn @@ -118,49 +116,15 @@ def find_failing_method_names(actual, filter_method) end end - def setup_method_signature_expectation - expectation = Support::MethodSignatureExpectation.new - - if @expected_arity.is_a?(Range) - expectation.min_count = @expected_arity.min - expectation.max_count = @expected_arity.max - else - expectation.min_count = @expected_arity - end - - expectation.keywords = @expected_keywords - expectation.expect_unlimited_arguments = @unlimited_arguments - expectation.expect_arbitrary_keywords = @arbitrary_keywords - - expectation - end - def matches_arity?(actual, name) - expectation = setup_method_signature_expectation - - return true if expectation.empty? - - begin - Support::StrictSignatureVerifier.new(method_signature_for(actual, name)). - with_expectation(expectation).valid? - rescue NameError - return true if @ignoring_method_signature_failure - raise ArgumentError, "The #{matcher_name} matcher requires that " \ - "the actual object define the method(s) in " \ - "order to check arity, but the method " \ - "`#{name}` is not defined. Remove the arity " \ - "check or define the method to continue." - end - end - - def method_signature_for(actual, name) - method_handle = Support.method_handle_for(actual, name) - - if name == :new && method_handle.owner === ::Class && ::Class === actual - Support::MethodSignature.new(actual.instance_method(:initialize)) - else - Support::MethodSignature.new(method_handle) - end + ArityCheck.new(@expected_arity, @expected_keywords, @arbitrary_keywords, @unlimited_arguments).matches?(actual, name) + rescue NameError + return true if @ignoring_method_signature_failure + raise ArgumentError, "The #{matcher_name} matcher requires that " \ + "the actual object define the method(s) in " \ + "order to check arity, but the method " \ + "`#{name}` is not defined. Remove the arity " \ + "check or define the method to continue." end def with_arity @@ -192,8 +156,45 @@ def with_keywords_string def pp_names @names.length == 1 ? "##{@names.first}" : description_of(@names) end + + # @private + class ArityCheck + def initialize(expected_arity, expected_keywords, arbitrary_keywords, unlimited_arguments) + expectation = Support::MethodSignatureExpectation.new + + if expected_arity.is_a?(Range) + expectation.min_count = expected_arity.min + expectation.max_count = expected_arity.max + else + expectation.min_count = expected_arity + end + + expectation.keywords = expected_keywords + expectation.expect_unlimited_arguments = unlimited_arguments + expectation.expect_arbitrary_keywords = arbitrary_keywords + @expectation = expectation + end + + def matches?(actual, name) + return true if @expectation.empty? + verifier_for(actual, name).with_expectation(@expectation).valid? + end + + def verifier_for(actual, name) + Support::StrictSignatureVerifier.new(method_signature_for(actual, name)) + end + + def method_signature_for(actual, name) + method_handle = Support.method_handle_for(actual, name) + + if name == :new && method_handle.owner === ::Class && ::Class === actual + Support::MethodSignature.new(actual.instance_method(:initialize)) + else + Support::MethodSignature.new(method_handle) + end + end + end end end end end -# rubocop:enable ClassLength