rspec-mocks 2.99.4 → 3.0.0.beta1

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.
Files changed (133) hide show
  1. checksums.yaml +14 -6
  2. checksums.yaml.gz.sig +2 -0
  3. data.tar.gz.sig +1 -0
  4. data/Changelog.md +89 -105
  5. data/License.txt +1 -0
  6. data/README.md +77 -57
  7. data/features/argument_matchers/explicit.feature +5 -5
  8. data/features/argument_matchers/general_matchers.feature +10 -10
  9. data/features/argument_matchers/type_matchers.feature +3 -3
  10. data/features/message_expectations/allow_any_instance_of.feature +1 -1
  11. data/features/message_expectations/any_instance.feature +27 -5
  12. data/features/message_expectations/call_original.feature +2 -2
  13. data/features/message_expectations/expect_message_using_expect.feature +2 -2
  14. data/features/message_expectations/expect_message_using_should_receive.feature +2 -2
  15. data/features/message_expectations/receive_counts.feature +7 -7
  16. data/features/message_expectations/warn_when_expectation_is_set_on_nil.feature +3 -3
  17. data/features/method_stubs/README.md +3 -0
  18. data/features/method_stubs/any_instance.feature +11 -11
  19. data/features/method_stubs/as_null_object.feature +4 -4
  20. data/features/method_stubs/simple_return_value_with_stub.feature +7 -7
  21. data/features/method_stubs/stub_chain.feature +3 -3
  22. data/features/method_stubs/stub_implementation.feature +2 -2
  23. data/features/method_stubs/to_ary.feature +2 -2
  24. data/features/mutating_constants/hiding_defined_constant.feature +2 -2
  25. data/features/mutating_constants/stub_defined_constant.feature +5 -5
  26. data/features/mutating_constants/stub_undefined_constant.feature +6 -6
  27. data/features/outside_rspec/configuration.feature +0 -2
  28. data/features/outside_rspec/standalone.feature +1 -1
  29. data/features/spies/spy_partial_mock_method.feature +2 -2
  30. data/features/spies/spy_pure_mock_method.feature +5 -5
  31. data/features/spies/spy_unstubbed_method.feature +1 -1
  32. data/features/support/env.rb +10 -1
  33. data/features/test_frameworks/test_unit.feature +1 -1
  34. data/features/verifying_doubles/class_doubles.feature +88 -0
  35. data/features/verifying_doubles/dynamic_classes.feature +72 -0
  36. data/features/verifying_doubles/introduction.feature +85 -0
  37. data/features/verifying_doubles/object_doubles.feature +65 -0
  38. data/features/verifying_doubles/partial_doubles.feature +34 -0
  39. data/lib/rspec/mocks.rb +8 -34
  40. data/lib/rspec/mocks/any_instance/chain.rb +4 -34
  41. data/lib/rspec/mocks/any_instance/expectation_chain.rb +14 -4
  42. data/lib/rspec/mocks/any_instance/message_chains.rb +27 -12
  43. data/lib/rspec/mocks/any_instance/recorder.rb +23 -31
  44. data/lib/rspec/mocks/any_instance/stub_chain.rb +9 -4
  45. data/lib/rspec/mocks/argument_list_matcher.rb +8 -1
  46. data/lib/rspec/mocks/argument_matchers.rb +26 -12
  47. data/lib/rspec/mocks/arity_calculator.rb +66 -0
  48. data/lib/rspec/mocks/configuration.rb +42 -14
  49. data/lib/rspec/mocks/error_generator.rb +34 -10
  50. data/lib/rspec/mocks/example_methods.rb +64 -19
  51. data/lib/rspec/mocks/extensions/marshal.rb +0 -15
  52. data/lib/rspec/mocks/framework.rb +4 -4
  53. data/lib/rspec/mocks/instance_method_stasher.rb +80 -62
  54. data/lib/rspec/mocks/matchers/have_received.rb +18 -14
  55. data/lib/rspec/mocks/matchers/receive.rb +29 -7
  56. data/lib/rspec/mocks/matchers/receive_messages.rb +72 -0
  57. data/lib/rspec/mocks/message_expectation.rb +95 -148
  58. data/lib/rspec/mocks/method_double.rb +77 -139
  59. data/lib/rspec/mocks/method_reference.rb +95 -0
  60. data/lib/rspec/mocks/mock.rb +1 -1
  61. data/lib/rspec/mocks/mutate_const.rb +12 -9
  62. data/lib/rspec/mocks/object_reference.rb +90 -0
  63. data/lib/rspec/mocks/order_group.rb +49 -7
  64. data/lib/rspec/mocks/proxy.rb +72 -33
  65. data/lib/rspec/mocks/proxy_for_nil.rb +2 -2
  66. data/lib/rspec/mocks/space.rb +13 -18
  67. data/lib/rspec/mocks/stub_chain.rb +2 -2
  68. data/lib/rspec/mocks/syntax.rb +61 -36
  69. data/lib/rspec/mocks/targets.rb +40 -19
  70. data/lib/rspec/mocks/test_double.rb +12 -56
  71. data/lib/rspec/mocks/verifying_double.rb +77 -0
  72. data/lib/rspec/mocks/verifying_message_expecation.rb +60 -0
  73. data/lib/rspec/mocks/verifying_proxy.rb +151 -0
  74. data/lib/rspec/mocks/version.rb +1 -1
  75. data/spec/rspec/mocks/and_call_original_spec.rb +34 -30
  76. data/spec/rspec/mocks/and_yield_spec.rb +2 -2
  77. data/spec/rspec/mocks/any_instance/message_chains_spec.rb +1 -1
  78. data/spec/rspec/mocks/any_instance_spec.rb +53 -260
  79. data/spec/rspec/mocks/argument_expectation_spec.rb +4 -4
  80. data/spec/rspec/mocks/arity_calculator_spec.rb +95 -0
  81. data/spec/rspec/mocks/array_including_matcher_spec.rb +41 -0
  82. data/spec/rspec/mocks/at_least_spec.rb +4 -32
  83. data/spec/rspec/mocks/block_return_value_spec.rb +4 -135
  84. data/spec/rspec/mocks/combining_implementation_instructions_spec.rb +10 -11
  85. data/spec/rspec/mocks/configuration_spec.rb +79 -0
  86. data/spec/rspec/mocks/double_spec.rb +10 -78
  87. data/spec/rspec/mocks/extensions/marshal_spec.rb +0 -8
  88. data/spec/rspec/mocks/failing_argument_matchers_spec.rb +49 -4
  89. data/spec/rspec/mocks/instance_method_stasher_spec.rb +20 -3
  90. data/spec/rspec/mocks/matchers/have_received_spec.rb +74 -0
  91. data/spec/rspec/mocks/matchers/receive_messages_spec.rb +140 -0
  92. data/spec/rspec/mocks/matchers/receive_spec.rb +82 -42
  93. data/spec/rspec/mocks/methods_spec.rb +1 -1
  94. data/spec/rspec/mocks/{bug_report_830_spec.rb → mock_expectation_error_spec.rb} +4 -3
  95. data/spec/rspec/mocks/mock_ordering_spec.rb +11 -0
  96. data/spec/rspec/mocks/mock_space_spec.rb +10 -1
  97. data/spec/rspec/mocks/mock_spec.rb +26 -82
  98. data/spec/rspec/mocks/multiple_return_value_spec.rb +1 -1
  99. data/spec/rspec/mocks/mutate_const_spec.rb +18 -5
  100. data/spec/rspec/mocks/null_object_mock_spec.rb +6 -4
  101. data/spec/rspec/mocks/options_hash_spec.rb +3 -3
  102. data/spec/rspec/mocks/order_group_spec.rb +27 -0
  103. data/spec/rspec/mocks/partial_mock_spec.rb +101 -1
  104. data/spec/rspec/mocks/passing_argument_matchers_spec.rb +3 -20
  105. data/spec/rspec/mocks/record_messages_spec.rb +4 -4
  106. data/spec/rspec/mocks/serialization_spec.rb +4 -6
  107. data/spec/rspec/mocks/space_spec.rb +3 -3
  108. data/spec/rspec/mocks/stub_chain_spec.rb +0 -12
  109. data/spec/rspec/mocks/stub_spec.rb +23 -44
  110. data/spec/rspec/mocks/test_double_spec.rb +3 -22
  111. data/spec/rspec/mocks/verifying_double_spec.rb +327 -0
  112. data/spec/rspec/mocks/verifying_message_expecation_spec.rb +68 -0
  113. data/spec/rspec/mocks_spec.rb +16 -39
  114. data/spec/spec_helper.rb +29 -18
  115. metadata +131 -86
  116. metadata.gz.sig +1 -0
  117. data/features/message_expectations/expect_any_instance_of.feature +0 -27
  118. data/lib/rspec/mocks/caller_filter.rb +0 -60
  119. data/lib/rspec/mocks/deprecation.rb +0 -26
  120. data/lib/rspec/mocks/extensions/instance_exec.rb +0 -34
  121. data/lib/rspec/mocks/extensions/proc.rb +0 -63
  122. data/lib/spec/mocks.rb +0 -4
  123. data/spec/rspec/mocks/and_return_spec.rb +0 -17
  124. data/spec/rspec/mocks/any_number_of_times_spec.rb +0 -36
  125. data/spec/rspec/mocks/before_all_spec.rb +0 -74
  126. data/spec/rspec/mocks/bug_report_10260_spec.rb +0 -8
  127. data/spec/rspec/mocks/bug_report_10263_spec.rb +0 -27
  128. data/spec/rspec/mocks/bug_report_11545_spec.rb +0 -32
  129. data/spec/rspec/mocks/bug_report_496_spec.rb +0 -17
  130. data/spec/rspec/mocks/bug_report_600_spec.rb +0 -22
  131. data/spec/rspec/mocks/bug_report_7611_spec.rb +0 -16
  132. data/spec/rspec/mocks/bug_report_8165_spec.rb +0 -31
  133. data/spec/rspec/mocks/bug_report_957_spec.rb +0 -22
@@ -0,0 +1,65 @@
1
+ Feature: Using an object double
2
+
3
+ `object_double` can be used to create a double from an existing "template"
4
+ object, from which it verifies that any stubbed methods on the double also
5
+ exist on the template. This is useful for objects that are readily
6
+ constructable, but may have far-reaching side-effects such as talking to a
7
+ database or external API. In this case, using a double rather than the real
8
+ thing allows you to focus on the communication patterns of the object's
9
+ interface without having to worry about accidentally causing side-effects.
10
+ Object doubles can also be used to verify methods defined on an object using
11
+ `method_missing`, which is not possible with `instance_double`.
12
+
13
+ In addition, `object_double` can be used with specific constant values, as
14
+ shown below. This is for niche situations, such as when dealing with
15
+ singleton objects.
16
+
17
+ Scenario: doubling an existing object
18
+ Given a file named "spec/user_spec.rb" with:
19
+ """ruby
20
+ class User
21
+ # Don't want to accidentally trigger this!
22
+ def save; sleep 100; end
23
+ end
24
+
25
+ def save_user(user)
26
+ "saved!" if user.save
27
+ end
28
+
29
+ describe '#save_user' do
30
+ it 'renders message on success' do
31
+ user = object_double(User.new, :save => true)
32
+ expect(save_user(user)).to eq("saved!")
33
+ end
34
+ end
35
+ """
36
+ When I run `rspec spec/user_spec.rb`
37
+ Then the examples should all pass
38
+
39
+
40
+ Scenario: doubling a constant object
41
+ Given a file named "spec/email_spec.rb" with:
42
+ """ruby
43
+ require 'logger'
44
+
45
+ module MyApp
46
+ LOGGER = Logger.new("myapp")
47
+ end
48
+
49
+ class Email
50
+ def self.send_to(recipient)
51
+ MyApp::LOGGER.info("Sent to #{recipient}")
52
+ # other emailing logic
53
+ end
54
+ end
55
+
56
+ describe Email do
57
+ it 'logs a message when sending' do
58
+ logger = object_double("MyApp::LOGGER", :info => nil).as_stubbed_const
59
+ Email.send_to('hello@foo.com')
60
+ expect(logger).to have_received(:info).with("Sent to hello@foo.com")
61
+ end
62
+ end
63
+ """
64
+ When I run `rspec spec/email_spec.rb`
65
+ Then the examples should all pass
@@ -0,0 +1,34 @@
1
+ Feature: Partial doubles
2
+
3
+ When the `verify_partial_doubles` configuration option is set, the same arity
4
+ and method existince checks that are performed for `object_double` are also
5
+ performed on partial doubles. You should set this unless you have a good
6
+ reason not to. It defaults to off only for backwards compatibility.
7
+
8
+ Scenario: doubling an existing object
9
+ Given a file named "spec/user_spec.rb" with:
10
+ """ruby
11
+ class User
12
+ def save; false; end
13
+ end
14
+
15
+ def save_user(user)
16
+ "saved!" if user.save
17
+ end
18
+
19
+ RSpec.configure do |config|
20
+ config.mock_with :rspec do |mocks|
21
+ mocks.verify_partial_doubles = true
22
+ end
23
+ end
24
+
25
+ describe '#save_user' do
26
+ it 'renders message on success' do
27
+ user = User.new
28
+ expect(user).to receive(:saave).and_return(true) # Typo in name
29
+ expect(save_user(user)).to eq("saved!")
30
+ end
31
+ end
32
+ """
33
+ When I run `rspec spec/user_spec.rb`
34
+ Then the output should contain "1 example, 1 failure"
@@ -2,25 +2,16 @@ require 'rspec/mocks/framework'
2
2
  require 'rspec/mocks/version'
3
3
 
4
4
  module RSpec
5
+
5
6
  module Mocks
6
7
  class << self
7
8
  attr_accessor :space
8
9
 
9
- def setup(host=nil)
10
- host_is_from_rspec_core = defined?(::RSpec::Core::ExampleGroup) && host.is_a?(::RSpec::Core::ExampleGroup)
11
- if host
12
- unless host_is_from_rspec_core
13
- RSpec.deprecate(
14
- "The host argument to `RSpec::Mocks.setup`",
15
- :replacement => "`include RSpec::Mocks::ExampleMethods` in #{host.inspect}"
16
- )
17
- end
18
-
19
- (class << host; self; end).class_eval do
20
- include RSpec::Mocks::ExampleMethods
21
- end
10
+ def setup(host)
11
+ (class << host; self; end).class_exec do
12
+ include RSpec::Mocks::ExampleMethods
22
13
  end
23
- space.outside_example = false
14
+ self.space ||= RSpec::Mocks::Space.new
24
15
  end
25
16
 
26
17
  def verify
@@ -29,7 +20,6 @@ module RSpec
29
20
 
30
21
  def teardown
31
22
  space.reset_all
32
- space.outside_example = true
33
23
  end
34
24
 
35
25
  def proxy_for(object)
@@ -61,7 +51,7 @@ module RSpec
61
51
  CallerFilter.first_non_rspec_line
62
52
  }
63
53
  ::RSpec::Mocks.proxy_for(subject).
64
- add_stub(orig_caller, message.to_sym, opts, &block)
54
+ add_stub(orig_caller, message, opts, &block)
65
55
  end
66
56
 
67
57
  # Sets a message expectation on `subject`.
@@ -80,7 +70,7 @@ module RSpec
80
70
  CallerFilter.first_non_rspec_line
81
71
  }
82
72
  ::RSpec::Mocks.proxy_for(subject).
83
- add_message_expectation(orig_caller, message.to_sym, opts, &block)
73
+ add_message_expectation(orig_caller, message, opts, &block)
84
74
  end
85
75
 
86
76
  # @api private
@@ -105,22 +95,6 @@ module RSpec
105
95
 
106
96
  # @private
107
97
  IGNORED_BACKTRACE_LINE = 'this backtrace line is ignored'
108
-
109
- self.space = RSpec::Mocks::Space.new
110
-
111
- DEPRECATED_CONSTANTS =
112
- {
113
- :Mock => Double,
114
- :ConstantStubber => ConstantMutator,
115
- }
116
-
117
- def self.const_missing(name)
118
- if const = DEPRECATED_CONSTANTS[name]
119
- RSpec.deprecate("RSpec::Mocks::#{name}", :replacement => const.name)
120
- const
121
- else
122
- super
123
- end
124
- end
125
98
  end
126
99
  end
100
+
@@ -6,8 +6,6 @@ module RSpec
6
6
  @recorder = recorder
7
7
  @expectation_args = args
8
8
  @expectation_block = block
9
- @source_line = CallerFilter.first_non_rspec_line
10
- ensure_expectation_block_has_source_location
11
9
  end
12
10
 
13
11
  module Customizations
@@ -19,11 +17,9 @@ module RSpec
19
17
  # @see RSpec::Mocks::MessageExpectation#$1
20
18
  #
21
19
  def self.record(method_name)
22
- class_eval(<<-EOM, __FILE__, __LINE__ + 1)
23
- def #{method_name}(*args, &block)
24
- record(:#{method_name}, *args, &block)
25
- end
26
- EOM
20
+ define_method(method_name) do |*args, &block|
21
+ record(method_name, *args, &block)
22
+ end
27
23
  end
28
24
 
29
25
  record :and_return
@@ -73,21 +69,8 @@ module RSpec
73
69
 
74
70
  private
75
71
 
76
- def create_message_expectation_on(instance)
77
- me = yield(::RSpec::Mocks.proxy_for(instance), IGNORED_BACKTRACE_LINE)
78
-
79
- if RSpec::Mocks.configuration.should_warn_about_any_instance_blocks?
80
- me.warn_about_receiver_passing(@source_line)
81
- me.display_any_instance_deprecation_warning_if_necessary(@expectation_block)
82
- elsif RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?
83
- me.and_yield_receiver_to_implementation
84
- end
85
-
86
- me
87
- end
88
-
89
72
  def negated?
90
- messages.any? { |(message, *_), _| message.to_sym == :never }
73
+ messages.any? { |(message, *_), _| message == :never }
91
74
  end
92
75
 
93
76
  def messages
@@ -103,19 +86,6 @@ module RSpec
103
86
  messages << [args.unshift(rspec_method_name), block]
104
87
  self
105
88
  end
106
-
107
- if Proc.method_defined?(:source_location)
108
- def ensure_expectation_block_has_source_location; end
109
- else
110
- def ensure_expectation_block_has_source_location
111
- return unless @expectation_block
112
- source_location = CallerFilter.first_non_rspec_line.split(':')
113
-
114
- @expectation_block.extend Module.new {
115
- define_method(:source_location) { source_location }
116
- }
117
- end
118
- end
119
89
  end
120
90
  end
121
91
  end
@@ -12,15 +12,25 @@ module RSpec
12
12
  super
13
13
  end
14
14
 
15
- private
16
-
15
+ private
17
16
  def verify_invocation_order(rspec_method_name, *args, &block)
18
17
  end
18
+ end
19
+
20
+ # @api private
21
+ class PositiveExpectationChain < ExpectationChain
22
+
23
+ private
19
24
 
20
25
  def create_message_expectation_on(instance)
21
- super do |proxy, expected_from|
22
- proxy.add_message_expectation(expected_from, *@expectation_args, &@expectation_block)
26
+ proxy = ::RSpec::Mocks.proxy_for(instance)
27
+ expected_from = IGNORED_BACKTRACE_LINE
28
+ me = proxy.add_message_expectation(expected_from, *@expectation_args, &@expectation_block)
29
+ if RSpec::Mocks.configuration.yield_receiver_to_any_instance_implementation_blocks?
30
+ me.and_yield_receiver_to_implementation
23
31
  end
32
+
33
+ me
24
34
  end
25
35
 
26
36
  def invocation_order
@@ -2,55 +2,70 @@ module RSpec
2
2
  module Mocks
3
3
  module AnyInstance
4
4
  # @private
5
- class MessageChains < Hash
5
+ class MessageChains
6
6
  def initialize
7
- super {|h,k| h[k] = []}
7
+ @chains_by_method_name = Hash.new { |h, k| h[k] = [] }
8
+ end
9
+
10
+ # @private
11
+ def [](method_name)
12
+ @chains_by_method_name[method_name]
8
13
  end
9
14
 
10
15
  # @private
11
16
  def add(method_name, chain)
12
- self[method_name] << chain
17
+ @chains_by_method_name[method_name] << chain
13
18
  chain
14
19
  end
15
20
 
16
21
  # @private
17
22
  def remove_stub_chains_for!(method_name)
18
- self[method_name].reject! {|chain| chain.is_a?(StubChain)}
23
+ @chains_by_method_name[method_name].reject! do |chain|
24
+ StubChain === chain
25
+ end
19
26
  end
20
27
 
21
28
  # @private
22
29
  def has_expectation?(method_name)
23
- self[method_name].find {|chain| chain.is_a?(ExpectationChain)}
30
+ @chains_by_method_name[method_name].find do |chain|
31
+ ExpectationChain === chain
32
+ end
24
33
  end
25
34
 
26
35
  # @private
27
36
  def all_expectations_fulfilled?
28
- all? {|method_name, chains| chains.all? {|chain| chain.expectation_fulfilled?}}
37
+ @chains_by_method_name.all? do |method_name, chains|
38
+ chains.all? { |chain| chain.expectation_fulfilled? }
39
+ end
29
40
  end
30
41
 
31
42
  # @private
32
43
  def unfulfilled_expectations
33
- map do |method_name, chains|
34
- method_name.to_s if chains.last.is_a?(ExpectationChain) unless chains.last.expectation_fulfilled?
44
+ @chains_by_method_name.map do |method_name, chains|
45
+ method_name.to_s if ExpectationChain === chains.last unless chains.last.expectation_fulfilled?
35
46
  end.compact
36
47
  end
37
48
 
38
49
  # @private
39
50
  def received_expected_message!(method_name)
40
- self[method_name].each {|chain| chain.expectation_fulfilled!}
51
+ @chains_by_method_name[method_name].each do |chain|
52
+ chain.expectation_fulfilled!
53
+ end
41
54
  end
42
55
 
43
56
  # @private
44
57
  def playback!(instance, method_name)
45
58
  raise_if_second_instance_to_receive_message(instance)
46
- self[method_name].each {|chain| chain.playback!(instance)}
59
+ @chains_by_method_name[method_name].each do |chain|
60
+ chain.playback!(instance)
61
+ end
47
62
  end
48
63
 
49
64
  private
50
65
 
51
66
  def raise_if_second_instance_to_receive_message(instance)
52
- @instance_with_expectation ||= instance if instance.is_a?(ExpectationChain)
53
- if instance.is_a?(ExpectationChain) && !@instance_with_expectation.equal?(instance)
67
+ @instance_with_expectation ||= instance if ExpectationChain === instance
68
+ if ExpectationChain === instance && !@instance_with_expectation.equal?(instance)
54
69
  raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{unfulfilled_expectations.sort.join(', ')}"
55
70
  end
56
71
  end
@@ -11,7 +11,7 @@ module RSpec
11
11
  # @see Chain
12
12
  class Recorder
13
13
  # @private
14
- attr_reader :message_chains, :stubs
14
+ attr_reader :message_chains, :stubs, :klass
15
15
 
16
16
  def initialize(klass)
17
17
  @message_chains = MessageChains.new
@@ -27,7 +27,7 @@ module RSpec
27
27
  #
28
28
  # @see Methods#stub
29
29
  def stub(method_name_or_method_map, &block)
30
- if method_name_or_method_map.is_a?(Hash)
30
+ if Hash === method_name_or_method_map
31
31
  method_name_or_method_map.each do |method_name, return_value|
32
32
  stub(method_name).and_return(return_value)
33
33
  end
@@ -57,7 +57,7 @@ module RSpec
57
57
  def should_receive(method_name, &block)
58
58
  @expectation_set = true
59
59
  observe!(method_name)
60
- message_chains.add(method_name, ExpectationChain.new(self, method_name, &block))
60
+ message_chains.add(method_name, PositiveExpectationChain.new(self, method_name, &block))
61
61
  end
62
62
 
63
63
  def should_not_receive(method_name, &block)
@@ -88,16 +88,9 @@ module RSpec
88
88
  if @expectation_set && !message_chains.all_expectations_fulfilled?
89
89
  raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{message_chains.unfulfilled_expectations.sort.join(', ')}"
90
90
  end
91
- end
92
-
93
- # @private
94
- def stub!(*)
95
- raise "stub! is not supported on any_instance. Use stub instead."
96
- end
97
-
98
- # @private
99
- def unstub!(*)
100
- raise "unstub! is not supported on any_instance. Use unstub instead."
91
+ ensure
92
+ stop_all_observation!
93
+ ::RSpec::Mocks.space.remove_any_instance_recorder_for(@klass)
101
94
  end
102
95
 
103
96
  # @private
@@ -149,7 +142,7 @@ module RSpec
149
142
 
150
143
  def restore_original_method!(method_name)
151
144
  alias_method_name = build_alias_method_name(method_name)
152
- @klass.class_eval do
145
+ @klass.class_exec do
153
146
  remove_method method_name
154
147
  alias_method method_name, alias_method_name
155
148
  remove_method alias_method_name
@@ -157,14 +150,14 @@ module RSpec
157
150
  end
158
151
 
159
152
  def remove_dummy_method!(method_name)
160
- @klass.class_eval do
153
+ @klass.class_exec do
161
154
  remove_method method_name
162
155
  end
163
156
  end
164
157
 
165
158
  def backup_method!(method_name)
166
159
  alias_method_name = build_alias_method_name(method_name)
167
- @klass.class_eval do
160
+ @klass.class_exec do
168
161
  alias_method alias_method_name, method_name
169
162
  end if public_protected_or_private_method_defined?(method_name)
170
163
  end
@@ -179,28 +172,27 @@ module RSpec
179
172
  end
180
173
 
181
174
  def observe!(method_name)
175
+ if RSpec::Mocks.configuration.verify_partial_doubles?
176
+ raise MockExpectationError unless @klass.method_defined?(method_name)
177
+ end
178
+
182
179
  stop_observing!(method_name) if already_observing?(method_name)
183
180
  @observed_methods << method_name
184
181
  backup_method!(method_name)
185
- @klass.class_eval(<<-EOM, __FILE__, __LINE__ + 1)
186
- def #{method_name}(*args, &blk)
187
- klass = ::RSpec::Mocks.method_handle_for(self, :#{method_name}).owner
188
- ::RSpec::Mocks.any_instance_recorder_for(klass).playback!(self, :#{method_name})
189
- self.__send__(:#{method_name}, *args, &blk)
190
- end
191
- EOM
182
+ @klass.__send__(:define_method, method_name) do |*args, &blk|
183
+ klass = ::RSpec::Mocks.method_handle_for(self, method_name).owner
184
+ ::RSpec::Mocks.any_instance_recorder_for(klass).playback!(self, method_name)
185
+ self.__send__(method_name, *args, &blk)
186
+ end
192
187
  end
193
188
 
194
189
  def mark_invoked!(method_name)
195
190
  backup_method!(method_name)
196
- @klass.class_eval(<<-EOM, __FILE__, __LINE__ + 1)
197
- def #{method_name}(*args, &blk)
198
- method_name = :#{method_name}
199
- klass = ::RSpec::Mocks.method_handle_for(self, :#{method_name}).owner
200
- invoked_instance = ::RSpec::Mocks.any_instance_recorder_for(klass).instance_that_received(method_name)
201
- raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by \#{self.inspect} but has already been received by \#{invoked_instance}"
202
- end
203
- EOM
191
+ @klass.__send__(:define_method, method_name) do |*args, &blk|
192
+ klass = ::RSpec::Mocks.method_handle_for(self, method_name).owner
193
+ invoked_instance = ::RSpec::Mocks.any_instance_recorder_for(klass).instance_that_received(method_name)
194
+ raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by #{self.inspect} but has already been received by #{invoked_instance}"
195
+ end
204
196
  end
205
197
  end
206
198
  end