lib/spy/subroutine.rb in spy-1.0.3 vs lib/spy/subroutine.rb in spy-1.0.4
- old
+ new
@@ -199,30 +199,32 @@
end
# check if the method was called with the exact arguments
# @param args Arguments that should have been sent to the method
# @return [Boolean]
- def has_been_called_with?(*args, &block)
+ def has_been_called_with?(*args, **kwargs, &block)
raise NeverHookedError unless @was_hooked
- match = block_given? ? block : proc { |call| call.args == args }
+ match = block_given? ? block : proc { |call| call.args == args && call.kwargs == kwargs }
calls.any?(&match)
end
# invoke that the method has been called. You really shouldn't use this
# method.
- def invoke(object, args, block, called_from)
- check_arity!(args.size)
+ def invoke(object, args, kwargs, block, called_from)
+ arity = args.size
+ arity += 1 if kwargs.present?
+ check_arity!(arity)
result =
if @call_through
- call_plan(build_call_through_plan(object), block, *args)
+ call_plan(build_call_through_plan(object), block, *args, **kwargs)
elsif @plan
check_for_too_many_arguments!(@plan)
- call_plan(@plan, block, *args)
+ call_plan(@plan, block, *args, **kwargs)
end
ensure
- calls << CallLog.new(object, called_from, args, block, result)
+ calls << CallLog.new(object, called_from, args, kwargs, block, result)
end
# reset the call log
def reset!
@was_hooked = false
@@ -235,15 +237,16 @@
# this returns a lambda that calls the spy object.
# we use eval to set the spy object id as a parameter so it can be extracted
# and looked up later using `Method#parameters`
SPY_ARGS_PREFIX='__spy_args_'.freeze
+ SPY_KWARGS_PREFIX='__spy_kwargs_'.freeze
def override_method
eval <<-METHOD, binding, __FILE__, __LINE__ + 1
__method_spy__ = self
- lambda do |*#{SPY_ARGS_PREFIX}#{self.object_id}, &block|
- __method_spy__.invoke(self, #{SPY_ARGS_PREFIX}#{self.object_id}, block, caller(1)[0])
+ lambda do |*#{SPY_ARGS_PREFIX}#{self.object_id}, **#{SPY_KWARGS_PREFIX}#{self.object_id}, &block|
+ __method_spy__.invoke(self, #{SPY_ARGS_PREFIX}#{self.object_id}, #{SPY_KWARGS_PREFIX}#{self.object_id}, block, caller(1)[0])
end
METHOD
end
def clear_method!
@@ -343,26 +346,11 @@
base_object.send(:method_missing, method_name, *args, &block)
end
end
end
- def call_plan(plan, block, *args)
- if ruby_27_last_arg_hash?(args)
- *prefix, last = args
- plan.call(*prefix, **last, &block)
- else
- plan.call(*args, &block)
- end
- end
-
- # Ruby 2.7 gives a deprecation warning about passing hash as last argument for a method
- # with a double-splat operator (**), and Ruby 3 raises an ArgumentError exception.
- # This checks if args has a hash as last element to extract it and pass it with double-splat to avoid an exception.
- def ruby_27_last_arg_hash?(args)
- last = args.last
- last.instance_of?(Hash) &&
- !last.empty? &&
- Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7.0")
+ def call_plan(plan, block, *args, **kwargs)
+ plan.call(*args, **kwargs, &block)
end
class << self
# retrieve the method spy from an object or create a new one