muack 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 309cafc82b9f7538884fa099e8ab6827d183afcf
4
- data.tar.gz: 64a20f3374a9c72abe10c4c7a78f26651c04c09b
2
+ SHA256:
3
+ metadata.gz: e65f1260993f94d96899086e3975500583ec077bfae332a8fd4cefc5a2c7da49
4
+ data.tar.gz: 736468eb986e1925f8f83973fec00c2142df16ca80aee9ce051bbdc255cbbfc8
5
5
  SHA512:
6
- metadata.gz: 312fd3143189a03c2c8d1fbe85a74296ccc71fd8247d09fc83ea8a5fc4ba3407fde7f7507e9c58d611cc476457b02d8b8ad614d1c6f9555694f2037c783eccc9
7
- data.tar.gz: 658d76b3ddac4ad03c10f643f8e16f996d1250862995037c4460abf586423b1e389e851bf4f376004187dbe1069b765428b8993d9175130db5627be586a50c7c
6
+ metadata.gz: d3bb1281eab20185484890205696cbed1d3996ed6392b76e08297af8e742bd76a80f2e3a26fffec265848d18a5373dffd517db6d2127b4e511dfdc5a2b475937
7
+ data.tar.gz: 2c148e33b0dce444708d09a58f6364e160a926f73e5432120fa8668c7ee0dd65c83128e69723673fd6c95bb62db879b8ff3636af29c93e783954f8409a882ebd
@@ -1,11 +1,21 @@
1
-
1
+ sudo: false
2
2
  language: ruby
3
- rvm:
4
- - 2.0
5
- - 2.1
6
- - 2.2
7
- - rbx-2
8
- - jruby
9
3
 
10
- install: 'bundle install --retry=3'
11
- script: 'ruby -r bundler/setup -S rake test'
4
+ install: 'gem update --system; gem install bundler; bundle install --retry=3'
5
+ before_script: unset CI
6
+ script: 'ruby -vwr bundler/setup -S rake test'
7
+
8
+ matrix:
9
+ include:
10
+ - rvm: 2.4
11
+ env: RUBYOPT=--enable-frozen-string-literal
12
+ - rvm: 2.5
13
+ env: RUBYOPT=--enable-frozen-string-literal
14
+ - rvm: 2.6
15
+ env: RUBYOPT=--enable-frozen-string-literal
16
+ - rvm: 2.7
17
+ env: RUBYOPT=--enable-frozen-string-literal
18
+ - rvm: ruby-head
19
+ env: RUBYOPT=--enable-frozen-string-literal
20
+ - rvm: jruby
21
+ env: RUBYOPT=--enable-frozen-string-literal
data/CHANGES.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # CHANGES
2
2
 
3
+ ## Muack 1.5.0 -- 2020-11-28
4
+
5
+ ### Bugs fixed
6
+
7
+ * Properly handle prepended objects
8
+ * Properly restore method visibilities for singleton methods
9
+
10
+ ### Enhancement
11
+
12
+ * Eliminated any potential keyword arguments warnings to be future proof
13
+ * Some major internal restructure
14
+
3
15
  ## Muack 1.4.0 -- 2015-11-21
4
16
 
5
17
  ### Incompatible changes / Enhancement
data/Gemfile CHANGED
@@ -8,7 +8,3 @@ gem 'pork'
8
8
 
9
9
  gem 'simplecov', :require => false if ENV['COV']
10
10
  gem 'coveralls', :require => false if ENV['CI']
11
-
12
- platform :rbx do
13
- gem 'rubysl-singleton' # used in rake
14
- end
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Muack [![Build Status](https://secure.travis-ci.org/godfat/muack.png?branch=master)](http://travis-ci.org/godfat/muack) [![Coverage Status](https://coveralls.io/repos/godfat/muack/badge.png?branch=master)](https://coveralls.io/r/godfat/muack?branch=master) [![Join the chat at https://gitter.im/godfat/muack](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/godfat/muack)
1
+ # Muack [![Build Status](https://secure.travis-ci.org/godfat/muack.png?branch=master)](http://travis-ci.org/godfat/muack) [![Coverage Status](https://coveralls.io/repos/github/godfat/muack/badge.png)](https://coveralls.io/github/godfat/muack) [![Join the chat at https://gitter.im/godfat/muack](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/godfat/muack)
2
2
 
3
3
  by Lin Jen-Shin ([godfat](http://godfat.org))
4
4
 
@@ -7,6 +7,7 @@ by Lin Jen-Shin ([godfat](http://godfat.org))
7
7
  * [github](https://github.com/godfat/muack)
8
8
  * [rubygems](https://rubygems.org/gems/muack)
9
9
  * [rdoc](http://rdoc.info/github/godfat/muack)
10
+ * [issues](https://github.com/godfat/muack/issues) (feel free to ask for support)
10
11
 
11
12
  ## DESCRIPTION:
12
13
 
@@ -25,7 +26,7 @@ Muack is much simpler and thus much faster and much more consistent.
25
26
 
26
27
  ## REQUIREMENTS:
27
28
 
28
- * Tested with MRI (official CRuby), Rubinius and JRuby.
29
+ * Tested with MRI (official CRuby) and JRuby.
29
30
 
30
31
  ## INSTALLATION:
31
32
 
@@ -46,7 +47,7 @@ describe 'Hello' do
46
47
  after { Muack.verify }
47
48
 
48
49
  would 'say world!' do
49
- str = 'Hello'
50
+ str = 'Hello'.dup
50
51
  mock(str).say('!'){ |arg| "World#{arg}" }
51
52
  str.say('!').should.eq 'World!'
52
53
  end
@@ -172,7 +173,7 @@ affecting the others. This is helpful in the cases of mocking some very
172
173
  basic objects like Time, without causing too much side effect.
173
174
 
174
175
  ``` ruby
175
- name = 'str'
176
+ name = 'str'.dup
176
177
  stub(name).to_s{ 'hi' }
177
178
  stub(Time).new { Time.at(0) }
178
179
  mock(Time).now { Time.new }
@@ -274,7 +275,7 @@ into proxy mode we simply do not provide any block to the injected method,
274
275
  but just name it. Here's an example:
275
276
 
276
277
  ``` ruby
277
- str = 'str'
278
+ str = 'str'.dup
278
279
  mock(str).reverse
279
280
  p str.reverse # 'rts'
280
281
  p Muack.verify # true
@@ -284,7 +285,7 @@ Note that if reverse was not called exactly once, the mock would complain.
284
285
  We could also use stub + spy to do the same thing as well:
285
286
 
286
287
  ``` ruby
287
- str = 'str'
288
+ str = 'str'.dup
288
289
  stub(str).reverse
289
290
  p str.reverse # 'rts'
290
291
  spy(str).reverse
@@ -623,7 +624,7 @@ our own behaviour, then we already have full control of the arguments.
623
624
  There's no points to use both. This also applies to `peek_return`.
624
625
 
625
626
  ``` ruby
626
- str = 'ff'
627
+ str = 'ff'.dup
627
628
  mock(str).to_i.with_any_args.peek_args{ |radix| radix * 2 }
628
629
  p str.to_i(8) # 255
629
630
  p Muack.verify # true
@@ -654,7 +655,7 @@ might just want to take a look at the return? Here's an example using
654
655
  `peek_return` to modify the original return value.
655
656
 
656
657
  ``` ruby
657
- str = 'ff'
658
+ str = 'ff'.dup
658
659
  mock(str).to_i.with_any_args.peek_return{ |int| int * 2 }
659
660
  p str.to_i(16) # 510
660
661
  p Muack.verify # true
@@ -832,7 +833,7 @@ p Muack.verify # true
832
833
 
833
834
  ``` ruby
834
835
  obj = Object.new
835
- mock(obj).say(where(:a => is_a(Fixnum))){ |arg| arg }
836
+ mock(obj).say(where(:a => is_a(Integer))){ |arg| arg }
836
837
  p obj.say(:a => 0) # {:a => 0}
837
838
  p Muack.verify # true
838
839
  ```
@@ -841,7 +842,7 @@ Note that this could be recursive.
841
842
 
842
843
  ``` ruby
843
844
  obj = Object.new
844
- mock(obj).say(where(:a => {:b => [is_a(Fixnum)]})){ |arg| arg[:a] }
845
+ mock(obj).say(where(:a => {:b => [is_a(Integer)]})){ |arg| arg[:a] }
845
846
  p obj.say(:a => {:b => [0]}) # {:b => [0]}
846
847
  p Muack.verify # true
847
848
  ```
@@ -862,7 +863,7 @@ Note that this could be recursive.
862
863
 
863
864
  ``` ruby
864
865
  obj = Object.new
865
- mock(obj).say(having(:a => {:b => [is_a(Fixnum)]})){ |arg| arg[:c] }
866
+ mock(obj).say(having(:a => {:b => [is_a(Integer)]})){ |arg| arg[:c] }
866
867
  p obj.say(:a => {:b => [1]}, :c => 2) # 2
867
868
  p Muack.verify # true
868
869
  ```
@@ -883,7 +884,7 @@ Note that this could be recursive.
883
884
 
884
885
  ``` ruby
885
886
  obj = Object.new
886
- mock(obj).say(allowing(:a => {:b => is_a(Fixnum), :c => 1})){ |arg| arg[:a] }
887
+ mock(obj).say(allowing(:a => {:b => is_a(Integer), :c => 1})){ |arg| arg[:a] }
887
888
  p obj.say(:a => {:b => 2}) # {:b => 2}
888
889
  p Muack.verify # true
889
890
  ```
@@ -1209,8 +1210,8 @@ Or, I am happy to break legacy.
1209
1210
  ## USERS:
1210
1211
 
1211
1212
  * [Rib][]
1212
- * [rest-core](https://github.com/cardinalblue/rest-core)
1213
- * [rest-more](https://github.com/cardinalblue/rest-more)
1213
+ * [rest-core](https://github.com/godfat/rest-core)
1214
+ * [rest-more](https://github.com/godfat/rest-more)
1214
1215
 
1215
1216
  ## CONTRIBUTORS:
1216
1217
 
@@ -1218,9 +1219,9 @@ Or, I am happy to break legacy.
1218
1219
 
1219
1220
  ## LICENSE:
1220
1221
 
1221
- Apache License 2.0
1222
+ Apache License 2.0 (Apache-2.0)
1222
1223
 
1223
- Copyright (c) 2013-2015, Lin Jen-Shin (godfat)
1224
+ Copyright (c) 2013-2020, Lin Jen-Shin (godfat)
1224
1225
 
1225
1226
  Licensed under the Apache License, Version 2.0 (the "License");
1226
1227
  you may not use this file except in compliance with the License.
data/Rakefile CHANGED
@@ -1,14 +1,13 @@
1
1
 
2
2
  begin
3
- require "#{dir = File.dirname(__FILE__)}/task/gemgem"
3
+ require "#{__dir__}/task/gemgem"
4
4
  rescue LoadError
5
- sh 'git submodule update --init'
5
+ sh 'git submodule update --init --recursive'
6
6
  exec Gem.ruby, '-S', $PROGRAM_NAME, *ARGV
7
7
  end
8
8
 
9
- Gemgem.init(dir) do |s|
9
+ Gemgem.init(__dir__) do |s|
10
10
  require 'muack/version'
11
11
  s.name = 'muack'
12
12
  s.version = Muack::VERSION
13
- %w[].each{ |g| s.add_runtime_dependency(g) }
14
13
  end
@@ -1,17 +1,6 @@
1
1
 
2
- module Muack
3
- class Block
4
- attr_accessor :block, :context
5
- def initialize block, context=nil
6
- self.block, self.context = block, context
7
- end
8
-
9
- def call *args, &actual_block
10
- if context # ruby: no way to pass actual_block to instance_exec
11
- context.instance_exec(*args, &block)
12
- else
13
- block.call(*args, &actual_block)
14
- end
15
- end
16
- end
2
+ if RUBY_VERSION < '2.7'
3
+ require 'muack/block_26'
4
+ else
5
+ require 'muack/block_27'
17
6
  end
@@ -0,0 +1,16 @@
1
+
2
+ module Muack
3
+ class Block < Struct.new(:block, :context)
4
+ def initialize block, context=nil
5
+ super
6
+ end
7
+
8
+ def call(*args, &block)
9
+ if context
10
+ context.instance_exec(*args, &block)
11
+ else
12
+ block.call(*args, &block)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+
2
+ module Muack
3
+ class Block < Struct.new(:block, :context)
4
+ def initialize block, context=nil
5
+ super
6
+ end
7
+
8
+ def call(...)
9
+ if context
10
+ context.instance_exec(...)
11
+ else
12
+ block.call(...)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -4,7 +4,7 @@ require 'muack/mock'
4
4
  module Muack
5
5
  class Coat < Mock
6
6
  # used for mocked object to dispatch mocked method
7
- def __mock_dispatch msg, actual_args
7
+ def __mock_dispatch actual_call
8
8
  defi = super
9
9
  if __mock_defis[defi.msg].empty?
10
10
  __mock_reset_method(defi)
@@ -1,7 +1,8 @@
1
1
 
2
2
  module Muack
3
- Definition = Class.new(Struct.new(:msg, :args, :returns,
4
- :peek_args, :peek_return,
5
- :original_method))
3
+ Definition = Struct.new(:msg, :args, :returns,
4
+ :peek_args, :peek_return,
5
+ :original_method, :visibility)
6
+ ActualCall = Struct.new(:msg, :args, :block)
6
7
  WithAnyArgs = Object.new
7
8
  end
@@ -12,11 +12,12 @@ module Muack
12
12
 
13
13
  class Unexpected < Failure
14
14
  attr_reader :was
15
- def initialize obj, expected_defis, msg, args
16
- @was = "#{obj.inspect}.#{msg}(" \
17
- "#{args.map(&:inspect).join(', ')})"
15
+ def initialize obj, expected_defis, actual_call
16
+ args = actual_call.args.map(&:inspect)
17
+ @was = "#{obj.inspect}.#{actual_call.msg}(#{args.join(', ')})"
18
+
18
19
  if expected_defis.empty?
19
- super("\nUnexpected call: #{@was}")
20
+ super("\nUnexpected call: #{was}")
20
21
  else
21
22
  build_expected(obj, expected_defis)
22
23
  super("\nExpected: #{expected}\n but was: #{was}")
@@ -6,8 +6,6 @@ require 'muack/block'
6
6
  require 'muack/error'
7
7
 
8
8
  module Muack
9
- EmptyBlock = proc{}
10
-
11
9
  class Mock < BasicObject
12
10
  attr_reader :object
13
11
  def initialize object
@@ -24,8 +22,8 @@ module Muack
24
22
  end
25
23
 
26
24
  # Public API: Define mocked method
27
- def method_missing msg, *args, &block
28
- defi = Definition.new(msg, args, block)
25
+ def method_missing msg, *args, &returns
26
+ defi = Definition.new(msg, args, returns)
29
27
  if injected = __mock_injected[defi.msg]
30
28
  defi.original_method = injected.original_method
31
29
  else
@@ -51,42 +49,42 @@ module Muack
51
49
  end
52
50
 
53
51
  # used for mocked object to dispatch mocked method
54
- def __mock_dispatch msg, actual_args
55
- if defi = __mock_defis[msg].shift
52
+ def __mock_dispatch actual_call
53
+ if defi = __mock_defis[actual_call.msg].shift
56
54
  __mock_disps_push(defi)
57
- if __mock_check_args(defi.args, actual_args)
55
+ if __mock_check_args(defi, actual_call)
58
56
  defi
59
57
  else
60
58
  Mock.__send__(:raise, # Wrong argument
61
- Unexpected.new(object, [defi], msg, actual_args))
59
+ Unexpected.new(object, [defi], actual_call))
62
60
  end
63
61
  else
64
- __mock_failed(msg, actual_args)
62
+ __mock_failed(actual_call)
65
63
  end
66
64
  end
67
65
 
68
66
  # used for mocked object to dispatch mocked method
69
- def __mock_dispatch_call context, disp, actual_args, actual_block, &_yield
70
- args = if disp.peek_args
71
- __mock_block_call(context, disp.peek_args,
72
- actual_args, actual_block, true)
73
- else
74
- actual_args
75
- end
76
-
77
- ret = if disp.returns
78
- __mock_block_call(context, disp.returns,
79
- args, actual_block, true)
80
- elsif disp.original_method # proxies for singleton methods
81
- context.__send__(disp.original_method, *args, &actual_block)
82
- else # proxies for instance methods
83
- # need the original context for calling `super`
84
- # ruby: can't pass a block to yield, so we name it _yield
85
- _yield.call(args, &actual_block)
86
- end
67
+ def __mock_dispatch_call context, disp, actual_call, &proxy_super
68
+ # resolving arguments
69
+ call =
70
+ if disp.peek_args
71
+ args = __mock_block_call(context, disp.peek_args, actual_call)
72
+ ActualCall.new(actual_call.msg, args, actual_call.block)
73
+ else
74
+ actual_call
75
+ end
87
76
 
77
+ # retrieve actual return
78
+ ret =
79
+ if disp.returns
80
+ __mock_block_call(context, disp.returns, call)
81
+ else
82
+ __mock_proxy_call(context, disp, call, proxy_super)
83
+ end
84
+
85
+ # resolving return
88
86
  if disp.peek_return
89
- __mock_block_call(context, disp.peek_return, ret, EmptyBlock, false)
87
+ __mock_block_call(context, disp.peek_return, ret, true)
90
88
  else
91
89
  ret
92
90
  end
@@ -95,9 +93,9 @@ module Muack
95
93
  # used for Muack::Session#verify
96
94
  def __mock_verify
97
95
  __mock_defis.values.all?(&:empty?) || begin
98
- msg, defis_with_same_msg = __mock_defis.find{ |_, v| v.size > 0 }
96
+ msg, defis_with_same_msg = __mock_defis.find{ |_, v| v.any? }
99
97
  args, defis = defis_with_same_msg.group_by(&:args).first
100
- dsize = __mock_disps[msg].select{ |d| d.args == args }.size
98
+ dsize = __mock_disps[msg].count{ |d| d.args == args }
101
99
  Mock.__send__(:raise, # Too little times
102
100
  Expected.new(object, defis.first, defis.size + dsize, dsize))
103
101
  end
@@ -114,36 +112,46 @@ module Muack
114
112
  private
115
113
  def __mock_inject_method defi
116
114
  __mock_injected[defi.msg] = defi
117
- target = object.singleton_class # would be the class in AnyInstanceOf
118
- privilege = Mock.store_original_method(target, defi)
119
- __mock_inject_mock_method(target, defi, privilege)
115
+ # a) ancestors.first is the first module in the method chain.
116
+ # it's just the singleton_class when nothing was prepended,
117
+ # otherwise the last prepended module.
118
+ # b) would be the class in AnyInstanceOf.
119
+ target = object.singleton_class.ancestors.first
120
+ Mock.store_original_method(target, defi)
121
+ __mock_inject_mock_method(target, defi)
120
122
  end
121
123
 
122
124
  def __mock_reset_method defi
123
- object.singleton_class.module_eval do
125
+ object.singleton_class.ancestors.first.module_eval do
124
126
  remove_method(defi.msg)
125
127
  # restore original method
126
- if instance_methods(false).include?(defi.original_method) ||
128
+ if public_instance_methods(false).include?(defi.original_method) ||
129
+ protected_instance_methods(false).include?(defi.original_method) ||
127
130
  private_instance_methods(false).include?(defi.original_method)
128
131
  alias_method(defi.msg, defi.original_method)
132
+ __send__(defi.visibility, defi.msg)
129
133
  remove_method(defi.original_method)
130
134
  end
131
135
  end
132
136
  end
133
137
 
134
138
  def self.store_original_method klass, defi
135
- privilege = if klass.instance_methods(false).include?(defi.msg)
136
- :public # TODO: forget about protected methods?
139
+ visibility = if klass.public_instance_methods(false).include?(defi.msg)
140
+ :public
141
+ elsif klass.protected_instance_methods(false).include?(defi.msg)
142
+ :protected
137
143
  elsif klass.private_instance_methods(false).include?(defi.msg)
138
144
  :private
139
145
  end
140
146
 
141
- return :public unless privilege
142
- # store original method
143
- original_method = find_new_name(klass, defi.msg)
144
- klass.__send__(:alias_method, original_method, defi.msg)
145
- defi.original_method = original_method
146
- privilege
147
+ if visibility # store original method
148
+ original_method = find_new_name(klass, defi.msg)
149
+ klass.__send__(:alias_method, original_method, defi.msg)
150
+ defi.original_method = original_method
151
+ defi.visibility = visibility
152
+ else
153
+ defi.visibility = :public
154
+ end
147
155
  end
148
156
 
149
157
  def self.find_new_name klass, message, level=0
@@ -159,50 +167,100 @@ module Muack
159
167
  end
160
168
  end
161
169
 
162
- def __mock_inject_mock_method target, defi, privilege=:public
170
+ def __mock_inject_mock_method target, defi
163
171
  mock = self # remember the context
164
172
  target.__send__(:define_method, defi.msg){ |*actual_args, &actual_block|
165
- disp = mock.__mock_dispatch(defi.msg, actual_args)
166
- mock.__mock_dispatch_call(self, disp, actual_args,
167
- actual_block) do |args, &block|
168
- super(*args, &block)
173
+ actual_call = ActualCall.new(defi.msg, actual_args, actual_block)
174
+ disp = mock.__mock_dispatch(actual_call)
175
+ mock.__mock_dispatch_call(self, disp, actual_call) do |call, has_kargs|
176
+ # need the original context for calling `super`
177
+ if has_kargs && kargs = call.args.last
178
+ super(*call.args[0...-1], **kargs, &call.block)
179
+ else
180
+ super(*call.args, &call.block)
181
+ end
169
182
  end
170
183
  }
171
- target.__send__(privilege, defi.msg)
184
+ target.__send__(defi.visibility, defi.msg)
172
185
  end
173
186
 
174
187
  # used for __mock_dispatch
175
- def __mock_failed msg, actual_args, disps=__mock_disps[msg]
176
- if expected = __mock_find_checked_difi(disps, actual_args)
188
+ def __mock_failed actual_call, disps=__mock_disps[actual_call.msg]
189
+ if expected = __mock_find_checked_difi(disps, actual_call)
177
190
  Mock.__send__(:raise, # Too many times
178
191
  Expected.new(object, expected, disps.size, disps.size+1))
179
192
  else
180
193
  Mock.__send__(:raise, # Wrong argument
181
- Unexpected.new(object, disps, msg, actual_args))
194
+ Unexpected.new(object, disps, actual_call))
182
195
  end
183
196
  end
184
197
 
185
198
  # used for __mock_dispatch_call
186
- def __mock_block_call context, block, actual_args, actual_block, splat
187
- return unless block
199
+ def __mock_block_call context, block, actual_call, peek_return=false
188
200
  # for AnyInstanceOf, we don't have the actual context at the time
189
201
  # we're defining it, so we update it here
190
- block.context = context if block.kind_of?(Block)
191
- if splat
192
- block.call(*actual_args, &actual_block)
193
- else # peek_return doesn't need splat
194
- block.call(actual_args, &actual_block)
202
+ if block.kind_of?(Block)
203
+ block.context = context
204
+ instance_exec_block = block.block
205
+ end
206
+
207
+ if peek_return # actual_call is the actual return in this case
208
+ block.call(actual_call, &instance_exec_block)
209
+ else
210
+ actual_block = actual_call.block || instance_exec_block
211
+ if __mock_block_with_kargs?(instance_exec_block || block) &&
212
+ kargs = actual_call.args.last
213
+ block.call(*actual_call.args[0...-1], **kargs, &actual_block)
214
+ else
215
+ block.call(*actual_call.args, &actual_block)
216
+ end
217
+ end
218
+ end
219
+
220
+ # used for __mock_dispatch_call
221
+ def __mock_proxy_call context, disp, call, proxy_super
222
+ if disp.original_method # proxies for singleton methods with __send__
223
+ if __mock_method_with_kargs?(context, disp.original_method) &&
224
+ kargs = call.args.last
225
+ context.__send__(
226
+ disp.original_method, *call.args[0...-1], **kargs, &call.block)
227
+ else
228
+ context.__send__(disp.original_method, *call.args, &call.block)
229
+ end
230
+ else # proxies for instance methods with super
231
+ proxy_super.call(call, __mock_super_with_kargs?(context, call.msg))
195
232
  end
196
233
  end
197
234
 
198
- def __mock_find_checked_difi defis, actual_args, meth=:find
199
- defis.public_send(meth){ |d| __mock_check_args(d.args, actual_args) }
235
+ def __mock_find_checked_difi defis, actual_call, meth=:find
236
+ defis.public_send(meth){ |d| __mock_check_args(d, actual_call) }
237
+ end
238
+
239
+ def __mock_method_with_kargs? object, method_name
240
+ __mock_block_with_kargs?(
241
+ ::Kernel.instance_method(:method).bind(object).call(method_name))
200
242
  end
201
243
 
202
- def __mock_check_args expected_args, actual_args
203
- if expected_args == [WithAnyArgs]
204
- true
205
- elsif expected_args.none?{ |arg| arg.kind_of?(Satisfying) }
244
+ def __mock_super_with_kargs? object, method_name
245
+ super_method =
246
+ ::Kernel.instance_method(:method).bind(object).call(method_name).
247
+ super_method
248
+
249
+ super_method && __mock_block_with_kargs?(super_method)
250
+ end
251
+
252
+ def __mock_block_with_kargs? block
253
+ # there's no Symbol#start_with? in older Ruby
254
+ block.parameters.dig(-1, 0).to_s.start_with?('key')
255
+ end
256
+
257
+ def __mock_check_args defi, actual_call
258
+ return true if defi.args.size == 1 && defi.args.first == WithAnyArgs
259
+
260
+ expected_args = defi.args
261
+ actual_args = actual_call.args
262
+
263
+ if expected_args.none?{ |arg| arg.kind_of?(Satisfying) }
206
264
  expected_args == actual_args
207
265
 
208
266
  elsif expected_args.size == actual_args.size