File: receive.rb

package info (click to toggle)
ruby-rspec-mocks 2.14.5-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 868 kB
  • ctags: 725
  • sloc: ruby: 8,227; makefile: 4
file content (97 lines) | stat: -rw-r--r-- 3,342 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
module RSpec
  module Mocks
    module Matchers
      class Receive
        def initialize(message, block)
          @message                 = message
          @block                   = block
          @recorded_customizations = []

          # MRI, JRuby and RBX report the caller inconsistently; MRI
          # reports an extra "in `new'" line in the backtrace that the
          # others do not include. The safest way to find the right
          # line is to search for the first line BEFORE rspec/mocks/syntax.rb.
          @backtrace_line          = caller.find do |line|
            !line.split(':').first.end_with?('rspec/mocks/syntax.rb')
          end
        end

        def setup_expectation(subject, &block)
          setup_mock_proxy_method_substitute(subject, :add_message_expectation, block)
        end
        alias matches? setup_expectation

        def setup_negative_expectation(subject, &block)
          # ensure `never` goes first for cases like `never.and_return(5)`,
          # where `and_return` is meant to raise an error
          @recorded_customizations.unshift Customization.new(:never, [], nil)

          setup_expectation(subject, &block)
        end
        alias does_not_match? setup_negative_expectation

        def setup_allowance(subject, &block)
          setup_mock_proxy_method_substitute(subject, :add_stub, block)
        end

        def setup_any_instance_expectation(subject, &block)
          setup_any_instance_method_substitute(subject, :should_receive, block)
        end

        def setup_any_instance_negative_expectation(subject, &block)
          setup_any_instance_method_substitute(subject, :should_not_receive, block)
        end

        def setup_any_instance_allowance(subject, &block)
          setup_any_instance_method_substitute(subject, :stub, block)
        end

        MessageExpectation.public_instance_methods(false).each do |method|
          next if method_defined?(method)

          class_eval(<<-RUBY)
            def #{method}(*args, &block)
              @recorded_customizations << Customization.new(#{method.inspect}, args, block)
              self
            end
          RUBY
        end

      private

        def setup_mock_proxy_method_substitute(subject, method, block)
          proxy = ::RSpec::Mocks.proxy_for(subject)
          setup_method_substitute(proxy, method, block, @backtrace_line)
        end

        def setup_any_instance_method_substitute(subject, method, block)
          any_instance_recorder = ::RSpec::Mocks.any_instance_recorder_for(subject)
          setup_method_substitute(any_instance_recorder, method, block)
        end

        def setup_method_substitute(host, method, block, *args)
          args << @message.to_sym
          expectation = host.__send__(method, *args, &(@block || block))

          @recorded_customizations.each do |customization|
            customization.playback_onto(expectation)
          end
          expectation
        end

        class Customization
          def initialize(method_name, args, block)
            @method_name = method_name
            @args        = args
            @block       = block
          end

          def playback_onto(expectation)
            expectation.__send__(@method_name, *@args, &@block)
          end
        end
      end
    end
  end
end