mocha 1.8.0 → 1.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -3
  3. data/RELEASE.md +10 -0
  4. data/bin/build-matrix +1 -2
  5. data/docs/Mocha.html +3 -3
  6. data/docs/Mocha/API.html +3 -3
  7. data/docs/Mocha/ClassMethods.html +3 -3
  8. data/docs/Mocha/Configuration.html +3 -3
  9. data/docs/Mocha/Expectation.html +3 -3
  10. data/docs/Mocha/ExpectationError.html +3 -3
  11. data/docs/Mocha/ExpectationErrorFactory.html +3 -3
  12. data/docs/Mocha/Hooks.html +3 -3
  13. data/docs/Mocha/Integration.html +3 -3
  14. data/docs/Mocha/Integration/MiniTest.html +3 -3
  15. data/docs/Mocha/Integration/MiniTest/Adapter.html +3 -3
  16. data/docs/Mocha/Integration/TestUnit.html +3 -3
  17. data/docs/Mocha/Integration/TestUnit/Adapter.html +3 -3
  18. data/docs/Mocha/Mock.html +3 -3
  19. data/docs/Mocha/ObjectMethods.html +3 -3
  20. data/docs/Mocha/ParameterMatchers.html +3 -3
  21. data/docs/Mocha/ParameterMatchers/AllOf.html +3 -3
  22. data/docs/Mocha/ParameterMatchers/AnyOf.html +3 -3
  23. data/docs/Mocha/ParameterMatchers/AnyParameters.html +3 -3
  24. data/docs/Mocha/ParameterMatchers/Anything.html +3 -3
  25. data/docs/Mocha/ParameterMatchers/Base.html +3 -3
  26. data/docs/Mocha/ParameterMatchers/Equals.html +3 -3
  27. data/docs/Mocha/ParameterMatchers/EquivalentUri.html +3 -3
  28. data/docs/Mocha/ParameterMatchers/HasEntries.html +3 -3
  29. data/docs/Mocha/ParameterMatchers/HasEntry.html +3 -3
  30. data/docs/Mocha/ParameterMatchers/HasKey.html +3 -3
  31. data/docs/Mocha/ParameterMatchers/HasValue.html +3 -3
  32. data/docs/Mocha/ParameterMatchers/Includes.html +3 -3
  33. data/docs/Mocha/ParameterMatchers/InstanceOf.html +3 -3
  34. data/docs/Mocha/ParameterMatchers/IsA.html +3 -3
  35. data/docs/Mocha/ParameterMatchers/KindOf.html +3 -3
  36. data/docs/Mocha/ParameterMatchers/Not.html +3 -3
  37. data/docs/Mocha/ParameterMatchers/Optionally.html +3 -3
  38. data/docs/Mocha/ParameterMatchers/RegexpMatches.html +3 -3
  39. data/docs/Mocha/ParameterMatchers/RespondsWith.html +3 -3
  40. data/docs/Mocha/ParameterMatchers/YamlEquivalent.html +3 -3
  41. data/docs/Mocha/Sequence.html +3 -3
  42. data/docs/Mocha/StateMachine.html +3 -3
  43. data/docs/Mocha/StateMachine/State.html +3 -3
  44. data/docs/Mocha/StateMachine/StatePredicate.html +3 -3
  45. data/docs/Mocha/StubbingError.html +3 -3
  46. data/docs/Mocha/UnexpectedInvocation.html +3 -3
  47. data/docs/_index.html +4 -4
  48. data/docs/file.COPYING.html +3 -3
  49. data/docs/file.MIT-LICENSE.html +3 -3
  50. data/docs/file.README.html +14 -6
  51. data/docs/file.RELEASE.html +15 -3
  52. data/docs/frames.html +1 -1
  53. data/docs/index.html +14 -6
  54. data/docs/js/app.js +11 -0
  55. data/docs/top-level-namespace.html +3 -3
  56. data/lib/mocha/any_instance_method.rb +17 -43
  57. data/lib/mocha/class_method.rb +79 -45
  58. data/lib/mocha/version.rb +1 -1
  59. data/test/unit/any_instance_method_test.rb +24 -0
  60. data/test/unit/class_method_test.rb +22 -0
  61. metadata +3 -5
  62. data/docs/CNAME +0 -1
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  Class: Mocha::StubbingError
8
8
 
9
- &mdash; Mocha 1.8.0
9
+ &mdash; Mocha 1.9.0
10
10
 
11
11
  </title>
12
12
 
@@ -140,9 +140,9 @@
140
140
  </div>
141
141
 
142
142
  <div id="footer">
143
- Generated on Tue Jan 15 17:13:06 2019 by
143
+ Generated on Mon Jun 17 18:38:45 2019 by
144
144
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
145
- 0.9.16 (ruby-2.5.3).
145
+ 0.9.19 (ruby-2.5.3).
146
146
  </div>
147
147
 
148
148
  </div>
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  Class: Mocha::UnexpectedInvocation
8
8
 
9
- &mdash; Mocha 1.8.0
9
+ &mdash; Mocha 1.9.0
10
10
 
11
11
  </title>
12
12
 
@@ -130,9 +130,9 @@
130
130
  </div>
131
131
 
132
132
  <div id="footer">
133
- Generated on Tue Jan 15 17:13:06 2019 by
133
+ Generated on Mon Jun 17 18:38:45 2019 by
134
134
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
135
- 0.9.16 (ruby-2.5.3).
135
+ 0.9.19 (ruby-2.5.3).
136
136
  </div>
137
137
 
138
138
  </div>
@@ -4,7 +4,7 @@
4
4
  <meta charset="utf-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>
7
- Mocha 1.8.0
7
+ Mocha 1.9.0
8
8
 
9
9
  </title>
10
10
 
@@ -52,7 +52,7 @@
52
52
  <div class="clear"></div>
53
53
  </div>
54
54
 
55
- <div id="content"><h1 class="noborder title">Mocha 1.8.0</h1>
55
+ <div id="content"><h1 class="noborder title">Mocha 1.9.0</h1>
56
56
  <div id="listing">
57
57
  <h1 class="alphaindex">Alphabetic Index</h1>
58
58
 
@@ -527,9 +527,9 @@
527
527
  </div>
528
528
 
529
529
  <div id="footer">
530
- Generated on Tue Jan 15 17:13:05 2019 by
530
+ Generated on Mon Jun 17 18:38:42 2019 by
531
531
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
532
- 0.9.16 (ruby-2.5.3).
532
+ 0.9.19 (ruby-2.5.3).
533
533
  </div>
534
534
 
535
535
  </div>
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  File: COPYING
8
8
 
9
- &mdash; Mocha 1.8.0
9
+ &mdash; Mocha 1.9.0
10
10
 
11
11
  </title>
12
12
 
@@ -71,9 +71,9 @@
71
71
  </div>
72
72
 
73
73
  <div id="footer">
74
- Generated on Tue Jan 15 17:13:05 2019 by
74
+ Generated on Mon Jun 17 18:38:43 2019 by
75
75
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
76
- 0.9.16 (ruby-2.5.3).
76
+ 0.9.19 (ruby-2.5.3).
77
77
  </div>
78
78
 
79
79
  </div>
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  File: MIT-LICENSE
8
8
 
9
- &mdash; Mocha 1.8.0
9
+ &mdash; Mocha 1.9.0
10
10
 
11
11
  </title>
12
12
 
@@ -75,9 +75,9 @@
75
75
  </div>
76
76
 
77
77
  <div id="footer">
78
- Generated on Tue Jan 15 17:13:05 2019 by
78
+ Generated on Mon Jun 17 18:38:43 2019 by
79
79
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
80
- 0.9.16 (ruby-2.5.3).
80
+ 0.9.19 (ruby-2.5.3).
81
81
  </div>
82
82
 
83
83
  </div>
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  File: README
8
8
 
9
- &mdash; Mocha 1.8.0
9
+ &mdash; Mocha 1.9.0
10
10
 
11
11
  </title>
12
12
 
@@ -310,7 +310,15 @@
310
310
 
311
311
  <h3>Thread safety</h3>
312
312
 
313
- <p>Mocha is currently <em>not</em> thread-safe. There are two main reasons for this: (a) in multi-threaded code Mocha exceptions may be raised in a thread other than the one which is running the test and thus a Mocha exception may not be correctly intercepted by Mocha exception handling code; and (b) partial mocking changes the state of objects in the <code>ObjectSpace</code> which is shared across all threads in the Ruby process and this access to what is effectively global state is not synchronized.</p>
313
+ <p>Mocha currently <em>does not</em> attempt to be thread-safe.</p>
314
+
315
+ <h4>Can I test multi-threaded code with Mocha?</h4>
316
+
317
+ <p>The short answer is no. In multi-threaded code Mocha exceptions may be raised in a thread other than the one which is running the test and thus a Mocha exception may not be correctly intercepted by Mocha exception handling code.</p>
318
+
319
+ <h4>Can I run my tests across multiple threads?</h4>
320
+
321
+ <p>Maybe, but probably not. Partial mocking changes the state of objects in the <code>ObjectSpace</code> which is shared across all threads in the Ruby process and this access to what is effectively global state is not synchronized. So, for example, if two tests are running concurrently and one uses <code>#any_instance</code> to modify a class, both tests will see those changes immediately.</p>
314
322
 
315
323
  <h3>Expectation matching / invocation order</h3>
316
324
 
@@ -359,13 +367,13 @@
359
367
  <li>Commit &amp; push to GitHub</li>
360
368
  <li><p>Check Travis CI build is passing - <a href="https://travis-ci.org/freerange/mocha">https://travis-ci.org/freerange/mocha</a></p></li>
361
369
  <li><p>Sign in to Google Analytics - <a href="https://analytics.google.com/analytics/web/">https://analytics.google.com/analytics/web/</a></p></li>
362
- <li><p>Find the web property ID for Go Free Range Ltd &gt; Mocha Documentation (UA-45002715-2)</p></li>
370
+ <li><p>Find the web property ID for Go Free Range Ltd &gt; Mocha Documentation (UA-625523-7)</p></li>
363
371
  <li><p>Generate documentation:</p></li>
364
372
  </ul>
365
373
 
366
374
  <pre class="code bash"><code class="bash">$ MOCHA_GENERATE_DOCS=true bundle install
367
375
 
368
- $ MOCHA_GENERATE_DOCS=true GOOGLE_ANALYTICS_WEB_PROPERTY_ID=UA-45002715-2 rake generate_docs
376
+ $ MOCHA_GENERATE_DOCS=true GOOGLE_ANALYTICS_WEB_PROPERTY_ID=UA-625523-7 rake generate_docs
369
377
  </code></pre>
370
378
 
371
379
  <ul>
@@ -408,9 +416,9 @@ Pushed mocha 1.2.0 to rubygems.org.
408
416
  </div>
409
417
 
410
418
  <div id="footer">
411
- Generated on Tue Jan 15 17:13:05 2019 by
419
+ Generated on Mon Jun 17 18:38:43 2019 by
412
420
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
413
- 0.9.16 (ruby-2.5.3).
421
+ 0.9.19 (ruby-2.5.3).
414
422
  </div>
415
423
 
416
424
  </div>
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  File: RELEASE
8
8
 
9
- &mdash; Mocha 1.8.0
9
+ &mdash; Mocha 1.9.0
10
10
 
11
11
  </title>
12
12
 
@@ -59,6 +59,18 @@
59
59
 
60
60
  <div id="content"><div id='filecontents'><h1>Release Notes</h1>
61
61
 
62
+ <h2>1.9.0</h2>
63
+
64
+ <ul>
65
+ <li>Add TruffleRuby to Travis CI build matrix - thanks to @deepj (#354)</li>
66
+ <li>Explicitly set Travis CI OS to Ubuntu Trusty 14.04 (ded1fa45)</li>
67
+ <li>Expand explanation of thread-safety concerns - thanks to @techbelly (#357)</li>
68
+ <li>Refactor class method and any instance method - thanks to @chrisroos (#358)</li>
69
+ <li>Rely on default bundler version in Travis CI builds (3352e9c5)</li>
70
+ <li>Fix local build-matrix script (11abe231)</li>
71
+ <li>No need to install latest bundler in build-matrix script (8247a894)</li>
72
+ </ul>
73
+
62
74
  <h2>1.8.0</h2>
63
75
 
64
76
  <ul>
@@ -865,9 +877,9 @@ Hash with wrong number of entries.
865
877
  </div>
866
878
 
867
879
  <div id="footer">
868
- Generated on Tue Jan 15 17:13:05 2019 by
880
+ Generated on Mon Jun 17 18:38:43 2019 by
869
881
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
870
- 0.9.16 (ruby-2.5.3).
882
+ 0.9.19 (ruby-2.5.3).
871
883
  </div>
872
884
 
873
885
  </div>
@@ -2,7 +2,7 @@
2
2
  <html>
3
3
  <head>
4
4
  <meta charset="utf-8">
5
- <title>Mocha 1.8.0</title>
5
+ <title>Mocha 1.9.0</title>
6
6
  </head>
7
7
  <script type="text/javascript" charset="utf-8">
8
8
  var match = unescape(window.location.hash).match(/^#!(.+)/);
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  File: README
8
8
 
9
- &mdash; Mocha 1.8.0
9
+ &mdash; Mocha 1.9.0
10
10
 
11
11
  </title>
12
12
 
@@ -310,7 +310,15 @@
310
310
 
311
311
  <h3>Thread safety</h3>
312
312
 
313
- <p>Mocha is currently <em>not</em> thread-safe. There are two main reasons for this: (a) in multi-threaded code Mocha exceptions may be raised in a thread other than the one which is running the test and thus a Mocha exception may not be correctly intercepted by Mocha exception handling code; and (b) partial mocking changes the state of objects in the <code>ObjectSpace</code> which is shared across all threads in the Ruby process and this access to what is effectively global state is not synchronized.</p>
313
+ <p>Mocha currently <em>does not</em> attempt to be thread-safe.</p>
314
+
315
+ <h4>Can I test multi-threaded code with Mocha?</h4>
316
+
317
+ <p>The short answer is no. In multi-threaded code Mocha exceptions may be raised in a thread other than the one which is running the test and thus a Mocha exception may not be correctly intercepted by Mocha exception handling code.</p>
318
+
319
+ <h4>Can I run my tests across multiple threads?</h4>
320
+
321
+ <p>Maybe, but probably not. Partial mocking changes the state of objects in the <code>ObjectSpace</code> which is shared across all threads in the Ruby process and this access to what is effectively global state is not synchronized. So, for example, if two tests are running concurrently and one uses <code>#any_instance</code> to modify a class, both tests will see those changes immediately.</p>
314
322
 
315
323
  <h3>Expectation matching / invocation order</h3>
316
324
 
@@ -359,13 +367,13 @@
359
367
  <li>Commit &amp; push to GitHub</li>
360
368
  <li><p>Check Travis CI build is passing - <a href="https://travis-ci.org/freerange/mocha">https://travis-ci.org/freerange/mocha</a></p></li>
361
369
  <li><p>Sign in to Google Analytics - <a href="https://analytics.google.com/analytics/web/">https://analytics.google.com/analytics/web/</a></p></li>
362
- <li><p>Find the web property ID for Go Free Range Ltd &gt; Mocha Documentation (UA-45002715-2)</p></li>
370
+ <li><p>Find the web property ID for Go Free Range Ltd &gt; Mocha Documentation (UA-625523-7)</p></li>
363
371
  <li><p>Generate documentation:</p></li>
364
372
  </ul>
365
373
 
366
374
  <pre class="code bash"><code class="bash">$ MOCHA_GENERATE_DOCS=true bundle install
367
375
 
368
- $ MOCHA_GENERATE_DOCS=true GOOGLE_ANALYTICS_WEB_PROPERTY_ID=UA-45002715-2 rake generate_docs
376
+ $ MOCHA_GENERATE_DOCS=true GOOGLE_ANALYTICS_WEB_PROPERTY_ID=UA-625523-7 rake generate_docs
369
377
  </code></pre>
370
378
 
371
379
  <ul>
@@ -408,9 +416,9 @@ Pushed mocha 1.2.0 to rubygems.org.
408
416
  </div>
409
417
 
410
418
  <div id="footer">
411
- Generated on Tue Jan 15 17:13:05 2019 by
419
+ Generated on Mon Jun 17 18:38:42 2019 by
412
420
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
413
- 0.9.16 (ruby-2.5.3).
421
+ 0.9.19 (ruby-2.5.3).
414
422
  </div>
415
423
 
416
424
  </div>
@@ -275,6 +275,16 @@ function mainFocus() {
275
275
  setTimeout(function() { $('#main').focus(); }, 10);
276
276
  }
277
277
 
278
+ function navigationChange() {
279
+ // This works around the broken anchor navigation with the YARD template.
280
+ window.onpopstate = function() {
281
+ var hash = window.location.hash;
282
+ if (hash !== '' && $(hash)[0]) {
283
+ $(hash)[0].scrollIntoView();
284
+ }
285
+ };
286
+ }
287
+
278
288
  $(document).ready(function() {
279
289
  navResizer();
280
290
  navExpander();
@@ -287,6 +297,7 @@ $(document).ready(function() {
287
297
  constantSummaryToggle();
288
298
  generateTOC();
289
299
  mainFocus();
300
+ navigationChange();
290
301
  });
291
302
 
292
303
  })();
@@ -6,7 +6,7 @@
6
6
  <title>
7
7
  Top Level Namespace
8
8
 
9
- &mdash; Mocha 1.8.0
9
+ &mdash; Mocha 1.9.0
10
10
 
11
11
  </title>
12
12
 
@@ -108,9 +108,9 @@
108
108
  </div>
109
109
 
110
110
  <div id="footer">
111
- Generated on Tue Jan 15 17:13:05 2019 by
111
+ Generated on Mon Jun 17 18:38:43 2019 by
112
112
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
113
- 0.9.16 (ruby-2.5.3).
113
+ 0.9.19 (ruby-2.5.3).
114
114
  </div>
115
115
 
116
116
  </div>
@@ -11,56 +11,30 @@ module Mocha
11
11
  stubbee.any_instance.reset_mocha
12
12
  end
13
13
 
14
- def hide_original_method
15
- return unless (@original_visibility = method_visibility(method))
16
- begin
17
- if RUBY_V2_PLUS
18
- @definition_target = PrependedModule.new
19
- stubbee.__send__ :prepend, @definition_target
20
- else
21
- @original_method = stubbee.instance_method(method)
22
- if @original_method && @original_method.owner == stubbee
23
- stubbee.send(:remove_method, method)
24
- end
25
- end
26
- # rubocop:disable Lint/HandleExceptions
27
- rescue NameError
28
- # deal with nasties like ActiveRecord::Associations::AssociationProxy
29
- end
30
- # rubocop:enable Lint/HandleExceptions
31
- end
32
-
33
- def define_new_method
34
- definition_target.class_eval(<<-CODE, __FILE__, __LINE__ + 1)
35
- def #{method}(*args, &block)
36
- self.class.any_instance.mocha.method_missing(:#{method}, *args, &block)
37
- end
38
- CODE
39
- return unless @original_visibility
40
- Module.instance_method(@original_visibility).bind(definition_target).call(method)
14
+ def restore_original_method
15
+ return if use_prepended_module_for_stub_method?
16
+ return unless stub_method_overwrites_original_method?
17
+ original_method_owner.send(:define_method, method_name, original_method)
18
+ Module.instance_method(original_visibility).bind(original_method_owner).call(method_name)
41
19
  end
42
20
 
43
- def remove_new_method
44
- definition_target.send(:remove_method, method)
45
- end
21
+ private
46
22
 
47
- def restore_original_method
48
- return if RUBY_V2_PLUS
49
- return unless @original_method && @original_method.owner == stubbee
50
- stubbee.send(:define_method, method, @original_method)
51
- Module.instance_method(@original_visibility).bind(stubbee).call(method)
23
+ def store_original_method
24
+ @original_method = original_method_owner.instance_method(method_name)
52
25
  end
53
26
 
54
- def method_visibility(method)
55
- (stubbee.public_instance_methods(true).include?(method) && :public) ||
56
- (stubbee.protected_instance_methods(true).include?(method) && :protected) ||
57
- (stubbee.private_instance_methods(true).include?(method) && :private)
27
+ def stub_method_definition
28
+ method_implementation = <<-CODE
29
+ def #{method_name}(*args, &block)
30
+ self.class.any_instance.mocha.method_missing(:#{method_name}, *args, &block)
31
+ end
32
+ CODE
33
+ [method_implementation, __FILE__, __LINE__ - 4]
58
34
  end
59
35
 
60
- private
61
-
62
- def definition_target
63
- @definition_target ||= stubbee
36
+ def original_method_owner
37
+ stubbee
64
38
  end
65
39
  end
66
40
  end
@@ -5,13 +5,13 @@ module Mocha
5
5
  class ClassMethod
6
6
  PrependedModule = Class.new(Module)
7
7
 
8
- attr_reader :stubbee, :method
8
+ attr_reader :stubbee, :method_name
9
9
 
10
- def initialize(stubbee, method)
10
+ def initialize(stubbee, method_name)
11
11
  @stubbee = stubbee
12
12
  @original_method = nil
13
13
  @original_visibility = nil
14
- @method = PRE_RUBY_V19 ? method.to_s : method.to_sym
14
+ @method_name = PRE_RUBY_V19 ? method_name.to_s : method_name.to_sym
15
15
  end
16
16
 
17
17
  def stub
@@ -22,7 +22,7 @@ module Mocha
22
22
  def unstub
23
23
  remove_new_method
24
24
  restore_original_method
25
- mock.unstub(method.to_sym)
25
+ mock.unstub(method_name.to_sym)
26
26
  return if mock.any_expectations?
27
27
  reset_mocha
28
28
  end
@@ -36,78 +36,112 @@ module Mocha
36
36
  end
37
37
 
38
38
  def hide_original_method
39
- return unless (@original_visibility = method_visibility(method))
40
- begin
41
- if RUBY_V2_PLUS
42
- @definition_target = PrependedModule.new
43
- stubbee.__metaclass__.__send__ :prepend, @definition_target
44
- else
45
- @original_method = stubbee._method(method)
46
- if @original_method && @original_method.owner == stubbee.__metaclass__
47
- stubbee.__metaclass__.send(:remove_method, method)
48
- end
39
+ return unless method_defined_in_stubbee_or_in_ancestor_chain?
40
+ store_original_method_visibility
41
+ if use_prepended_module_for_stub_method?
42
+ use_prepended_module_for_stub_method
43
+ else
44
+ begin
45
+ store_original_method
46
+ # rubocop:disable Lint/HandleExceptions
47
+ rescue NameError
48
+ # deal with nasties like ActiveRecord::Associations::AssociationProxy
49
+ end
50
+ # rubocop:enable Lint/HandleExceptions
51
+ if stub_method_overwrites_original_method?
52
+ remove_original_method_from_stubbee
49
53
  end
50
- # rubocop:disable Lint/HandleExceptions
51
- rescue NameError
52
- # deal with nasties like ActiveRecord::Associations::AssociationProxy
53
54
  end
54
- # rubocop:enable Lint/HandleExceptions
55
55
  end
56
56
 
57
57
  def define_new_method
58
- definition_target.class_eval(<<-CODE, __FILE__, __LINE__ + 1)
59
- def #{method}(*args, &block)
60
- mocha.method_missing(:#{method}, *args, &block)
61
- end
62
- CODE
63
- return unless @original_visibility
64
- Module.instance_method(@original_visibility).bind(definition_target).call(method)
58
+ stub_method_owner.class_eval(*stub_method_definition)
59
+ return unless original_visibility
60
+ Module.instance_method(original_visibility).bind(stub_method_owner).call(method_name)
65
61
  end
66
62
 
67
63
  def remove_new_method
68
- definition_target.send(:remove_method, method)
64
+ stub_method_owner.send(:remove_method, method_name)
69
65
  end
70
66
 
71
67
  def restore_original_method
72
- return if RUBY_V2_PLUS
73
- if @original_method && @original_method.owner == stubbee.__metaclass__
68
+ return if use_prepended_module_for_stub_method?
69
+ if stub_method_overwrites_original_method?
74
70
  if PRE_RUBY_V19
75
- original_method = @original_method
76
- stubbee.__metaclass__.send(:define_method, method) do |*args, &block|
77
- original_method.call(*args, &block)
71
+ original_method_in_scope = original_method
72
+ original_method_owner.send(:define_method, method_name) do |*args, &block|
73
+ original_method_in_scope.call(*args, &block)
78
74
  end
79
75
  else
80
- stubbee.__metaclass__.send(:define_method, method, @original_method)
76
+ original_method_owner.send(:define_method, method_name, original_method)
81
77
  end
82
78
  end
83
- return unless @original_visibility
84
- Module.instance_method(@original_visibility).bind(stubbee.__metaclass__).call(method)
79
+ return unless original_visibility
80
+ Module.instance_method(original_visibility).bind(stubbee.__metaclass__).call(method_name)
85
81
  end
86
82
 
87
83
  def matches?(other)
88
84
  return false unless other.class == self.class
89
- (stubbee.object_id == other.stubbee.object_id) && (method == other.method)
85
+ (stubbee.object_id == other.stubbee.object_id) && (method_name == other.method_name)
90
86
  end
91
87
 
92
88
  alias_method :==, :eql?
93
89
 
94
90
  def to_s
95
- "#{stubbee}.#{method}"
91
+ "#{stubbee}.#{method_name}"
96
92
  end
97
93
 
98
- def method_visibility(method)
99
- symbol = method.to_sym
100
- metaclass = stubbee.__metaclass__
101
-
102
- (metaclass.public_method_defined?(symbol) && :public) ||
103
- (metaclass.protected_method_defined?(symbol) && :protected) ||
104
- (metaclass.private_method_defined?(symbol) && :private)
94
+ def method_visibility
95
+ (original_method_owner.public_method_defined?(method_name) && :public) ||
96
+ (original_method_owner.protected_method_defined?(method_name) && :protected) ||
97
+ (original_method_owner.private_method_defined?(method_name) && :private)
105
98
  end
99
+ alias_method :method_defined_in_stubbee_or_in_ancestor_chain?, :method_visibility
106
100
 
107
101
  private
108
102
 
109
- def definition_target
110
- @definition_target ||= stubbee.__metaclass__
103
+ attr_reader :original_method, :original_visibility
104
+
105
+ def store_original_method
106
+ @original_method = stubbee._method(method_name)
107
+ end
108
+
109
+ def store_original_method_visibility
110
+ @original_visibility = method_visibility
111
+ end
112
+
113
+ def stub_method_overwrites_original_method?
114
+ original_method && original_method.owner == original_method_owner
115
+ end
116
+
117
+ def remove_original_method_from_stubbee
118
+ original_method_owner.send(:remove_method, method_name)
119
+ end
120
+
121
+ def use_prepended_module_for_stub_method?
122
+ RUBY_V2_PLUS
123
+ end
124
+
125
+ def use_prepended_module_for_stub_method
126
+ @stub_method_owner = PrependedModule.new
127
+ original_method_owner.__send__ :prepend, @stub_method_owner
128
+ end
129
+
130
+ def stub_method_definition
131
+ method_implementation = <<-CODE
132
+ def #{method_name}(*args, &block)
133
+ mocha.method_missing(:#{method_name}, *args, &block)
134
+ end
135
+ CODE
136
+ [method_implementation, __FILE__, __LINE__ - 4]
137
+ end
138
+
139
+ def stub_method_owner
140
+ @stub_method_owner ||= original_method_owner
141
+ end
142
+
143
+ def original_method_owner
144
+ stubbee.__metaclass__
111
145
  end
112
146
  end
113
147
  end