mocha 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fee7267881fbeec218036679d2d7002f5a2f0f30
4
- data.tar.gz: 8801ccb9858bbafe1a422702ca1d91e19d31c777
3
+ metadata.gz: db34295002c13283fa7653ae3a1474a77bf081f2
4
+ data.tar.gz: ce7b148d39f32c3e9d0c527d679d1295b6440b0a
5
5
  SHA512:
6
- metadata.gz: a1a6ca8a2301842c8ecba0db5df9223232af8076e3d4745763307264c635f68ccb2ff13e8b359dad1d03950341f4fd226cbbda3ef6e22d3bcdea140b776a449e
7
- data.tar.gz: 2cc8b79a37943f4039764780c9c602d30d63e083e6bf375937e387ef6e3f08369f8669dc0b55e99216f15aa6672f9a6033dc52a91e08a172f55b0c59d7f7bc6f
6
+ metadata.gz: cfee63cd238bb06188c8c73bcd864c4b6c0e6d89e0433f85eb65ade2e1607c8557e370e448a6d98c5609a22db07d1f07240fb13c606323ae86694362b7342f0f
7
+ data.tar.gz: fb2ae63bf63e64df43d60d7ec48548b6410f8d4c594039b6abdf50d8f3fabb6c3c91fabd99920f97e1ff76e429135c0aca02bae217213cab313a65b47e784ae4
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
- ## Mocha [![build status](https://secure.travis-ci.org/freerange/mocha.png)](https://secure.travis-ci.org/freerange/mocha) [![Gem Version](https://badge.fury.io/rb/mocha.png)](http://badge.fury.io/rb/mocha)
1
+ ## Mocha [![build status](https://secure.travis-ci.org/freerange/mocha.png)](https://secure.travis-ci.org/freerange/mocha) [![Gem Version](https://badge.fury.io/rb/mocha.png)](http://badge.fury.io/rb/mocha) [![OpenCollective](https://opencollective.com/mocha/backers/badge.svg)](#backers) [![OpenCollective](https://opencollective.com/mocha/sponsors/badge.svg)](#sponsors)
2
+
2
3
 
3
4
  ### Description
4
5
 
@@ -75,6 +76,22 @@ gem 'mocha'
75
76
  require 'mocha/mini_test'
76
77
  ```
77
78
 
79
+ ##### RSpec
80
+
81
+ Assuming you are using the `rspec-rails` gem:
82
+
83
+ ```ruby
84
+ # Gemfile in Rails app
85
+ gem 'mocha'
86
+
87
+ # Within `spec/spec_helper.rb`
88
+ RSpec.configure do |config|
89
+ config.mock_with :mocha
90
+ end
91
+ ```
92
+
93
+ Note: There is no need to use a require statement to setup Mocha; RSpec does this itself.
94
+
78
95
  #### Rails Plugin
79
96
 
80
97
  Install the Rails plugin...
@@ -90,8 +107,9 @@ Note: As of version 0.9.8, the Mocha plugin is not automatically setup at plugin
90
107
  require 'mocha/mini_test'
91
108
  ```
92
109
 
93
- #### Know Issues
110
+ #### Known Issues
94
111
 
112
+ * Stubbing an aliased class method, where the original method is defined in a module that's used to `extend` the class doesn't work in Ruby 1.8.x. See stub_method_defined_on_module_and_aliased_test.rb for an example of this behaviour.
95
113
  * 0.13.x versions cause a harmless, but annoying, deprecation warning when used with Rails 3.2.0-3.2.12, 3.1.0-3.1.10 & 3.0.0-3.0.19.
96
114
  * 0.11.x versions don't work with Rails 3.2.13 (`TypeError: superclass mismatch for class ExpectationError`). See #115.
97
115
  * Versions 0.10.2, 0.10.3 & 0.11.0 of the Mocha gem were broken. Please do not use these versions.
@@ -193,7 +211,7 @@ class Order
193
211
  def find_all
194
212
  # Database.connection.execute('select * from orders...
195
213
  end
196
-
214
+
197
215
  def number_shipped_since(date)
198
216
  find_all.select { |order| order.shipped_on > date }.length
199
217
  end
@@ -262,6 +280,75 @@ See the [documentation](http://gofreerange.com/mocha/docs/Mocha/Mock.html) for `
262
280
 
263
281
  See this [list of contributors](https://github.com/freerange/mocha/graphs/contributors).
264
282
 
283
+ ###Backers
284
+
285
+ Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/mocha#backer)]
286
+
287
+ <a href="https://opencollective.com/mocha/backer/0/website" target="_blank"><img src="https://opencollective.com/mocha/backer/0/avatar.svg"></a>
288
+ <a href="https://opencollective.com/mocha/backer/1/website" target="_blank"><img src="https://opencollective.com/mocha/backer/1/avatar.svg"></a>
289
+ <a href="https://opencollective.com/mocha/backer/2/website" target="_blank"><img src="https://opencollective.com/mocha/backer/2/avatar.svg"></a>
290
+ <a href="https://opencollective.com/mocha/backer/3/website" target="_blank"><img src="https://opencollective.com/mocha/backer/3/avatar.svg"></a>
291
+ <a href="https://opencollective.com/mocha/backer/4/website" target="_blank"><img src="https://opencollective.com/mocha/backer/4/avatar.svg"></a>
292
+ <a href="https://opencollective.com/mocha/backer/5/website" target="_blank"><img src="https://opencollective.com/mocha/backer/5/avatar.svg"></a>
293
+ <a href="https://opencollective.com/mocha/backer/6/website" target="_blank"><img src="https://opencollective.com/mocha/backer/6/avatar.svg"></a>
294
+ <a href="https://opencollective.com/mocha/backer/7/website" target="_blank"><img src="https://opencollective.com/mocha/backer/7/avatar.svg"></a>
295
+ <a href="https://opencollective.com/mocha/backer/8/website" target="_blank"><img src="https://opencollective.com/mocha/backer/8/avatar.svg"></a>
296
+ <a href="https://opencollective.com/mocha/backer/9/website" target="_blank"><img src="https://opencollective.com/mocha/backer/9/avatar.svg"></a>
297
+ <a href="https://opencollective.com/mocha/backer/10/website" target="_blank"><img src="https://opencollective.com/mocha/backer/10/avatar.svg"></a>
298
+ <a href="https://opencollective.com/mocha/backer/11/website" target="_blank"><img src="https://opencollective.com/mocha/backer/11/avatar.svg"></a>
299
+ <a href="https://opencollective.com/mocha/backer/12/website" target="_blank"><img src="https://opencollective.com/mocha/backer/12/avatar.svg"></a>
300
+ <a href="https://opencollective.com/mocha/backer/13/website" target="_blank"><img src="https://opencollective.com/mocha/backer/13/avatar.svg"></a>
301
+ <a href="https://opencollective.com/mocha/backer/14/website" target="_blank"><img src="https://opencollective.com/mocha/backer/14/avatar.svg"></a>
302
+ <a href="https://opencollective.com/mocha/backer/15/website" target="_blank"><img src="https://opencollective.com/mocha/backer/15/avatar.svg"></a>
303
+ <a href="https://opencollective.com/mocha/backer/16/website" target="_blank"><img src="https://opencollective.com/mocha/backer/16/avatar.svg"></a>
304
+ <a href="https://opencollective.com/mocha/backer/17/website" target="_blank"><img src="https://opencollective.com/mocha/backer/17/avatar.svg"></a>
305
+ <a href="https://opencollective.com/mocha/backer/18/website" target="_blank"><img src="https://opencollective.com/mocha/backer/18/avatar.svg"></a>
306
+ <a href="https://opencollective.com/mocha/backer/19/website" target="_blank"><img src="https://opencollective.com/mocha/backer/19/avatar.svg"></a>
307
+ <a href="https://opencollective.com/mocha/backer/20/website" target="_blank"><img src="https://opencollective.com/mocha/backer/20/avatar.svg"></a>
308
+ <a href="https://opencollective.com/mocha/backer/21/website" target="_blank"><img src="https://opencollective.com/mocha/backer/21/avatar.svg"></a>
309
+ <a href="https://opencollective.com/mocha/backer/22/website" target="_blank"><img src="https://opencollective.com/mocha/backer/22/avatar.svg"></a>
310
+ <a href="https://opencollective.com/mocha/backer/23/website" target="_blank"><img src="https://opencollective.com/mocha/backer/23/avatar.svg"></a>
311
+ <a href="https://opencollective.com/mocha/backer/24/website" target="_blank"><img src="https://opencollective.com/mocha/backer/24/avatar.svg"></a>
312
+ <a href="https://opencollective.com/mocha/backer/25/website" target="_blank"><img src="https://opencollective.com/mocha/backer/25/avatar.svg"></a>
313
+ <a href="https://opencollective.com/mocha/backer/26/website" target="_blank"><img src="https://opencollective.com/mocha/backer/26/avatar.svg"></a>
314
+ <a href="https://opencollective.com/mocha/backer/27/website" target="_blank"><img src="https://opencollective.com/mocha/backer/27/avatar.svg"></a>
315
+ <a href="https://opencollective.com/mocha/backer/28/website" target="_blank"><img src="https://opencollective.com/mocha/backer/28/avatar.svg"></a>
316
+ <a href="https://opencollective.com/mocha/backer/29/website" target="_blank"><img src="https://opencollective.com/mocha/backer/29/avatar.svg"></a>
317
+
318
+ ### Sponsors
319
+ Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/mocha#sponsor)]
320
+
321
+ <a href="https://opencollective.com/mocha/sponsor/0/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/0/avatar.svg"></a>
322
+ <a href="https://opencollective.com/mocha/sponsor/1/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/1/avatar.svg"></a>
323
+ <a href="https://opencollective.com/mocha/sponsor/2/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/2/avatar.svg"></a>
324
+ <a href="https://opencollective.com/mocha/sponsor/3/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/3/avatar.svg"></a>
325
+ <a href="https://opencollective.com/mocha/sponsor/4/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/4/avatar.svg"></a>
326
+ <a href="https://opencollective.com/mocha/sponsor/5/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/5/avatar.svg"></a>
327
+ <a href="https://opencollective.com/mocha/sponsor/6/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/6/avatar.svg"></a>
328
+ <a href="https://opencollective.com/mocha/sponsor/7/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/7/avatar.svg"></a>
329
+ <a href="https://opencollective.com/mocha/sponsor/8/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/8/avatar.svg"></a>
330
+ <a href="https://opencollective.com/mocha/sponsor/9/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/9/avatar.svg"></a>
331
+ <a href="https://opencollective.com/mocha/sponsor/10/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/10/avatar.svg"></a>
332
+ <a href="https://opencollective.com/mocha/sponsor/11/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/11/avatar.svg"></a>
333
+ <a href="https://opencollective.com/mocha/sponsor/12/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/12/avatar.svg"></a>
334
+ <a href="https://opencollective.com/mocha/sponsor/13/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/13/avatar.svg"></a>
335
+ <a href="https://opencollective.com/mocha/sponsor/14/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/14/avatar.svg"></a>
336
+ <a href="https://opencollective.com/mocha/sponsor/15/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/15/avatar.svg"></a>
337
+ <a href="https://opencollective.com/mocha/sponsor/16/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/16/avatar.svg"></a>
338
+ <a href="https://opencollective.com/mocha/sponsor/17/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/17/avatar.svg"></a>
339
+ <a href="https://opencollective.com/mocha/sponsor/18/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/18/avatar.svg"></a>
340
+ <a href="https://opencollective.com/mocha/sponsor/19/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/19/avatar.svg"></a>
341
+ <a href="https://opencollective.com/mocha/sponsor/20/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/20/avatar.svg"></a>
342
+ <a href="https://opencollective.com/mocha/sponsor/21/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/21/avatar.svg"></a>
343
+ <a href="https://opencollective.com/mocha/sponsor/22/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/22/avatar.svg"></a>
344
+ <a href="https://opencollective.com/mocha/sponsor/23/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/23/avatar.svg"></a>
345
+ <a href="https://opencollective.com/mocha/sponsor/24/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/24/avatar.svg"></a>
346
+ <a href="https://opencollective.com/mocha/sponsor/25/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/25/avatar.svg"></a>
347
+ <a href="https://opencollective.com/mocha/sponsor/26/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/26/avatar.svg"></a>
348
+ <a href="https://opencollective.com/mocha/sponsor/27/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/27/avatar.svg"></a>
349
+ <a href="https://opencollective.com/mocha/sponsor/28/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/28/avatar.svg"></a>
350
+ <a href="https://opencollective.com/mocha/sponsor/29/website" target="_blank"><img src="https://opencollective.com/mocha/sponsor/29/avatar.svg"></a>
351
+
265
352
  ### Translations
266
353
 
267
354
  * [Serbo-Croatian](http://science.webhostinggeeks.com/mocha) by [WHG Team](http://webhostinggeeks.com/). (may be out-of-date)
data/RELEASE.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Release Notes
2
2
 
3
+ ## 1.2.0
4
+
5
+ * Always use prepended module to stub class & instance methods for Ruby v2+ - thanks to @grosser & @chrisroos (43d56671, #244)
6
+ * Always use prepended module to stub AnyInstance methods in Ruby v2+ - thanks to @chrisroos (#262)
7
+ * Always set visibility of stub method to match stubbed method on included module - thanks to @grosser & @chrisroos (e87c03b0, #248)
8
+ * Always set visibility to stub method to match stubbed method on superclass - thanks to @chrisroos (38d902ad)
9
+ * Allow stubbing of method to which any instance responds (#200)
10
+ * Allow `includes` matcher to take matcher arguments - thanks to @lazyatom (#217)
11
+ * Avoid exception in older version of Rubygems - thanks to @chrisroos (78d930a7)
12
+ * Add licenses to gemspec as requested by @coreyhaines (#201)
13
+ * Fix typo in README - thanks to @jaredbeck (6119460d)
14
+ * Added section about using Mocha with RSpec & Rails to README (#221)
15
+ * Fix documentation for Mocha::API#stub method - thanks to @raeno (599b1dcd)
16
+ * Added backers and sponsors from OpenCollective - thanks to @piamancini (#253)
17
+ * Fix typo in docs for equals - thanks to @alexcoco (#254)
18
+ * Add known issue for Ruby v1.8 to README - thanks to @chrisroos (2c642096)
19
+
3
20
  ## 1.1.0
4
21
 
5
22
  * Set visibility of any instance stub method.
data/Rakefile CHANGED
@@ -2,6 +2,8 @@ require "bundler"
2
2
  Bundler::GemHelper.install_tasks
3
3
  require "bundler/setup"
4
4
 
5
+ MOCHA_DOCS_HOST = ENV['MOCHA_DOCS_HOST'] || 'gofreerange.com'
6
+
5
7
  require 'rake/testtask'
6
8
 
7
9
  desc "Run all tests"
@@ -87,10 +89,18 @@ end
87
89
 
88
90
  def benchmark_test_case(klass, iterations)
89
91
  require 'benchmark'
92
+ require 'mocha/detection/mini_test'
90
93
 
91
94
  if defined?(MiniTest)
92
- MiniTest::Unit.output = StringIO.new
93
- Benchmark.realtime { iterations.times { |i| MiniTest::Unit.new.run([klass]) } }
95
+ minitest_version = Gem::Version.new(Mocha::Detection::MiniTest.version)
96
+ if Gem::Requirement.new('>= 5.0.0').satisfied_by?(minitest_version)
97
+ result = Benchmark.realtime { iterations.times { |i| klass.run(MiniTest::CompositeReporter.new) } }
98
+ MiniTest::Runnable.runnables.delete(klass)
99
+ result
100
+ else
101
+ MiniTest::Unit.output = StringIO.new
102
+ Benchmark.realtime { iterations.times { |i| MiniTest::Unit.new.run([klass]) } }
103
+ end
94
104
  else
95
105
  load 'test/unit/ui/console/testrunner.rb' unless defined?(Test::Unit::UI::Console::TestRunner)
96
106
  unless $silent_option
@@ -105,7 +115,7 @@ def benchmark_test_case(klass, iterations)
105
115
  end
106
116
  end
107
117
 
108
- unless ENV["MOCHA_NO_DOCS"]
118
+ if ENV["MOCHA_GENERATE_DOCS"]
109
119
  require 'yard'
110
120
 
111
121
  desc 'Remove generated documentation'
@@ -127,10 +137,10 @@ unless ENV["MOCHA_NO_DOCS"]
127
137
  desc "Generate documentation"
128
138
  task 'generate_docs' => ['clobber_yardoc', 'yardoc']
129
139
 
130
- desc "Publish docs to gofreerange.com/docs/mocha"
140
+ desc "Publish docs to #{MOCHA_DOCS_HOST}/docs/mocha"
131
141
  task 'publish_docs' => 'generate_docs' do
132
142
  path = "/home/freerange/docs/mocha"
133
- system %{ssh gofreerange.com "sudo rm -fr #{path} && mkdir -p #{path}" && scp -r doc/* gofreerange.com:#{path}}
143
+ system %{ssh #{MOCHA_DOCS_HOST} "sudo rm -fr #{path} && mkdir -p #{path}" && scp -r doc/* #{MOCHA_DOCS_HOST}:#{path}}
134
144
  end
135
145
  end
136
146
 
@@ -33,7 +33,6 @@ def run(ruby_version, gemfile, task = "test")
33
33
  ENV["RBENV_VERSION"] = ruby_version
34
34
  ENV["BUNDLE_GEMFILE"] = gemfile
35
35
  ENV["MOCHA_OPTIONS"] = "debug"
36
- ENV["MOCHA_NO_DOCS"] = "true"
37
36
  reset_bundle
38
37
  execute(
39
38
  with_rbenv("bundle install --gemfile=#{gemfile}"),
@@ -3,5 +3,9 @@ source 'https://rubygems.org'
3
3
  gemspec :path=>"../"
4
4
 
5
5
  group :development do
6
- gem "test-unit"
6
+ if RUBY_VERSION < '1.9'
7
+ gem "test-unit", "~> 2"
8
+ else
9
+ gem "test-unit"
10
+ end
7
11
  end
@@ -1,3 +1,4 @@
1
+ require 'mocha/ruby_version'
1
2
  require 'mocha/class_method'
2
3
 
3
4
  module Mocha
@@ -13,20 +14,17 @@ module Mocha
13
14
  end
14
15
 
15
16
  def hide_original_method
16
- if method_exists?(method)
17
+ if @original_visibility = method_visibility(method)
17
18
  begin
18
19
  @original_method = stubbee.instance_method(method)
19
- if @original_method && @original_method.owner == stubbee
20
- @original_visibility = :public
21
- if stubbee.protected_instance_methods.include?(method)
22
- @original_visibility = :protected
23
- elsif stubbee.private_instance_methods.include?(method)
24
- @original_visibility = :private
20
+ if RUBY_V2_PLUS
21
+ @definition_target = PrependedModule.new
22
+ stubbee.__send__ :prepend, @definition_target
23
+ else
24
+ if @original_method && @original_method.owner == stubbee
25
+ stubbee.send(:remove_method, method)
25
26
  end
26
- stubbee.send(:remove_method, method)
27
27
  end
28
-
29
- include_prepended_module if RUBY_VERSION >= '2.0'
30
28
  rescue NameError
31
29
  # deal with nasties like ActiveRecord::Associations::AssociationProxy
32
30
  end
@@ -49,32 +47,22 @@ module Mocha
49
47
  end
50
48
 
51
49
  def restore_original_method
52
- if @original_method && @original_method.owner == stubbee
53
- stubbee.send(:define_method, method, @original_method)
54
- Module.instance_method(@original_visibility).bind(stubbee).call(method)
50
+ unless RUBY_V2_PLUS
51
+ if @original_method && @original_method.owner == stubbee
52
+ stubbee.send(:define_method, method, @original_method)
53
+ Module.instance_method(@original_visibility).bind(stubbee).call(method)
54
+ end
55
55
  end
56
56
  end
57
57
 
58
- def method_exists?(method)
59
- return true if stubbee.public_instance_methods(false).include?(method)
60
- return true if stubbee.protected_instance_methods(false).include?(method)
61
- return true if stubbee.private_instance_methods(false).include?(method)
62
- return false
58
+ def method_visibility(method)
59
+ (stubbee.public_instance_methods(true).include?(method) && :public) ||
60
+ (stubbee.protected_instance_methods(true).include?(method) && :protected) ||
61
+ (stubbee.private_instance_methods(true).include?(method) && :private)
63
62
  end
64
63
 
65
64
  private
66
65
 
67
- def include_prepended_module
68
- possible_prepended_modules = stubbee.ancestors.take_while do |mod|
69
- !(Class === mod)
70
- end
71
-
72
- if possible_prepended_modules.any?
73
- @definition_target = PrependedModule.new
74
- stubbee.__send__ :prepend, @definition_target
75
- end
76
- end
77
-
78
66
  def definition_target
79
67
  @definition_target ||= stubbee
80
68
  end
@@ -70,7 +70,7 @@ module Mocha
70
70
  #
71
71
  # @example Using stubbed_methods_vs_return_values Hash to setup stubbed methods.
72
72
  # def test_motor_starts_and_stops
73
- # motor = mock('motor', :start => true, :stop => true)
73
+ # motor = stub('motor', :start => true, :stop => true)
74
74
  # assert motor.start
75
75
  # assert motor.stop
76
76
  # # an error will not be raised even if either Motor#start or Motor#stop has not been called
@@ -78,7 +78,7 @@ module Mocha
78
78
  #
79
79
  # @example Using the optional block to setup expectations & stubbed methods.
80
80
  # def test_motor_starts_and_stops
81
- # motor = mock('motor') do
81
+ # motor = stub('motor') do
82
82
  # expects(:start).with(100.rpm).returns(true)
83
83
  # stubs(:stop).returns(true)
84
84
  # end
@@ -1,3 +1,4 @@
1
+ require 'mocha/ruby_version'
1
2
  require 'metaclass'
2
3
 
3
4
  module Mocha
@@ -11,7 +12,7 @@ module Mocha
11
12
  def initialize(stubbee, method)
12
13
  @stubbee = stubbee
13
14
  @original_method, @original_visibility = nil, nil
14
- @method = RUBY_VERSION < '1.9' ? method.to_s : method.to_sym
15
+ @method = PRE_RUBY_V19 ? method.to_s : method.to_sym
15
16
  end
16
17
 
17
18
  def stub
@@ -37,20 +38,17 @@ module Mocha
37
38
  end
38
39
 
39
40
  def hide_original_method
40
- if method_exists?(method)
41
+ if @original_visibility = method_visibility(method)
41
42
  begin
42
43
  @original_method = stubbee._method(method)
43
- @original_visibility = :public
44
- if stubbee.__metaclass__.protected_instance_methods.include?(method)
45
- @original_visibility = :protected
46
- elsif stubbee.__metaclass__.private_instance_methods.include?(method)
47
- @original_visibility = :private
44
+ if RUBY_V2_PLUS
45
+ @definition_target = PrependedModule.new
46
+ stubbee.__metaclass__.__send__ :prepend, @definition_target
47
+ else
48
+ if @original_method && @original_method.owner == stubbee.__metaclass__
49
+ stubbee.__metaclass__.send(:remove_method, method)
50
+ end
48
51
  end
49
- if @original_method && @original_method.owner == stubbee.__metaclass__
50
- stubbee.__metaclass__.send(:remove_method, method)
51
- end
52
-
53
- include_prepended_module if RUBY_VERSION >= '2.0'
54
52
  rescue NameError
55
53
  # deal with nasties like ActiveRecord::Associations::AssociationProxy
56
54
  end
@@ -73,18 +71,20 @@ module Mocha
73
71
  end
74
72
 
75
73
  def restore_original_method
76
- if @original_method && @original_method.owner == stubbee.__metaclass__
77
- if RUBY_VERSION < '1.9'
78
- original_method = @original_method
79
- stubbee.__metaclass__.send(:define_method, method) do |*args, &block|
80
- original_method.call(*args, &block)
74
+ unless RUBY_V2_PLUS
75
+ if @original_method && @original_method.owner == stubbee.__metaclass__
76
+ if PRE_RUBY_V19
77
+ original_method = @original_method
78
+ stubbee.__metaclass__.send(:define_method, method) do |*args, &block|
79
+ original_method.call(*args, &block)
80
+ end
81
+ else
82
+ stubbee.__metaclass__.send(:define_method, method, @original_method)
81
83
  end
82
- else
83
- stubbee.__metaclass__.send(:define_method, method, @original_method)
84
84
  end
85
- end
86
- if @original_visibility
87
- Module.instance_method(@original_visibility).bind(stubbee.__metaclass__).call(method)
85
+ if @original_visibility
86
+ Module.instance_method(@original_visibility).bind(stubbee.__metaclass__).call(method)
87
+ end
88
88
  end
89
89
  end
90
90
 
@@ -99,25 +99,17 @@ module Mocha
99
99
  "#{stubbee}.#{method}"
100
100
  end
101
101
 
102
- def method_exists?(method)
102
+ def method_visibility(method)
103
103
  symbol = method.to_sym
104
- __metaclass__ = stubbee.__metaclass__
105
- __metaclass__.public_method_defined?(symbol) || __metaclass__.protected_method_defined?(symbol) || __metaclass__.private_method_defined?(symbol)
104
+ metaclass = stubbee.__metaclass__
105
+
106
+ (metaclass.public_method_defined?(symbol) && :public) ||
107
+ (metaclass.protected_method_defined?(symbol) && :protected) ||
108
+ (metaclass.private_method_defined?(symbol) && :private)
106
109
  end
107
110
 
108
111
  private
109
112
 
110
- def include_prepended_module
111
- possible_prepended_modules = stubbee.__metaclass__.ancestors.take_while do |mod|
112
- !(Class === mod)
113
- end
114
-
115
- if possible_prepended_modules.any?
116
- @definition_target = PrependedModule.new
117
- stubbee.__metaclass__.__send__ :prepend, @definition_target
118
- end
119
- end
120
-
121
113
  def definition_target
122
114
  @definition_target ||= stubbee.__metaclass__
123
115
  end
@@ -34,6 +34,7 @@ module Mocha
34
34
  def method_exists?(method, include_public_methods = true)
35
35
  if include_public_methods
36
36
  return true if @stubba_object.public_instance_methods(include_superclass_methods = true).include?(method)
37
+ return true if @stubba_object.allocate.respond_to?(method.to_sym)
37
38
  end
38
39
  return true if @stubba_object.protected_instance_methods(include_superclass_methods = true).include?(method)
39
40
  return true if @stubba_object.private_instance_methods(include_superclass_methods = true).include?(method)
@@ -4,13 +4,21 @@ module Mocha
4
4
  module Integration
5
5
  module MonkeyPatcher
6
6
  def self.apply(mod, run_method_patch)
7
- unless mod < Mocha::API
7
+ if mod < Mocha::API
8
+ Debug.puts "Mocha::API already included in #{mod}"
9
+ else
8
10
  mod.send(:include, Mocha::API)
9
11
  end
10
- unless mod.method_defined?(:run_before_mocha)
11
- mod.send(:alias_method, :run_before_mocha, :run)
12
- mod.send(:remove_method, :run)
13
- mod.send(:include, run_method_patch)
12
+ if mod.method_defined?(:run_before_mocha)
13
+ Debug.puts "#{mod}#run_before_mocha method already defined"
14
+ else
15
+ if mod.method_defined?(:run)
16
+ mod.send(:alias_method, :run_before_mocha, :run)
17
+ mod.send(:remove_method, :run)
18
+ mod.send(:include, run_method_patch)
19
+ else
20
+ raise "Unable to monkey-patch #{mod}, because it does not define a `#run` method"
21
+ end
14
22
  end
15
23
  end
16
24
  end