Skip to content
This repository

Blocks provided to `with` are used as implementation. #426

Merged
merged 1 commit into from 7 months ago

3 participants

Xavier Shay Coveralls Myron Marston
Xavier Shay
Collaborator

It is confusing to have different behaviour depending on whether the
block has arguments or not, and there are better ways to do this.

This behaviour matches that of other message expectations.

Fixes #377.

Xavier Shay
Collaborator

This is a breaking change. Deprecation added to 2-99 branch in #425.

Coveralls

Coverage Status

Coverage decreased (-0.08%) when pulling 2e7a97b on issue-377 into 8e1a653 on master.

lib/rspec/mocks/message_expectation.rb
... ...
@@ -353,8 +353,13 @@ def raise_out_of_order_error
353 353
       #   cart.add(Book.new(:isbn => 1934356379))
354 354
       #   # => passes
355 355
       def with(*args, &block)
356  
-        self.inner_implementation_action = block if block_given? unless args.empty?
357  
-        @argument_list_matcher = ArgumentListMatcher.new(*args, &block)
  356
+        if args.empty?
  357
+          raise ArgumentError,
  358
+            "`with` must have at least one argument. Use `no_args` matcher to set this expectation."
1
Myron Marston Owner

I think "this expectation" is a little odd (it's not clear what expectation the user is trying to set to me -- it may just be that they hit their editors key binding that ran the specs before finishing typing the expression). Maybe instead say '...to set the expectation of receiving no arguments'?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
spec/rspec/mocks/failing_argument_matchers_spec.rb
((6 lines not shown))
101 101
         expect do
102 102
           @double.should_receive(:msg).with {|arg| expect(arg).to eq :received }
103  
-          @double.msg :no_msg_for_you
104  
-        end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected: :received.*\s*.*got: :no_msg_for_you/)
  103
+        end.to raise_error(ArgumentError,
  104
+          "`with` must have at least one argument. Use `no_args` matcher to set this expectation.")
2
Myron Marston Owner

FWIW, I don't usually spell out the entire exception message...I'd probably just do to raise_error(ArgumentError, /must have at least one arg/) -- that way we can tweak phrasing w/o necessarily having to tweak it here as well.

Xavier Shay Collaborator

cool, I like doing that too but was copying another match I saw elsewhere. Will change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Myron Marston
Owner

LGTM. Left a couple minor suggestions but this is good to merge otherwise.

Xavier Shay Blocks provided to `with` are used as implementation.
It is confusing to have different behaviour depending on whether the
block has arguments or not, and there are better ways to do this.

This behaviour matches that of other message expectations.
7ef80f5
Coveralls

Coverage Status

Coverage decreased (-0.08%) when pulling 7ef80f5 on issue-377 into 8e1a653 on master.

Xavier Shay xaviershay merged commit 253eeed into from October 01, 2013
Xavier Shay xaviershay closed this October 01, 2013
Xavier Shay xaviershay deleted the branch October 01, 2013
Myron Marston myronmarston referenced this pull request from a commit November 19, 2013
Myron Marston Remove support for ArgumentListMatcher block.
This feature was removed in #426, but this bit of
the implementation of that feature remained.
83d34c3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 2 authors.

Oct 01, 2013
Xavier Shay Blocks provided to `with` are used as implementation.
It is confusing to have different behaviour depending on whether the
block has arguments or not, and there are better ways to do this.

This behaviour matches that of other message expectations.
7ef80f5
This page is out of date. Refresh to see the latest.
1  Changelog.md
Source Rendered
@@ -18,6 +18,7 @@ Breaking Changes for 3.0.0:
18 18
 * Make `at_least(0)` raise an error. (Sam Phippen)
19 19
 * Remove support for `require 'spec/mocks'` which had been kept
20 20
   in place for backwards compatibility with rspec 1 (Myron Marston).
  21
+* Blocks provided to `with` are always used as implementation (Xavier Shay).
21 22
 
22 23
 Enhancements:
23 24
 
9  lib/rspec/mocks/message_expectation.rb
@@ -353,8 +353,13 @@ def raise_out_of_order_error
353 353
       #   cart.add(Book.new(:isbn => 1934356379))
354 354
       #   # => passes
355 355
       def with(*args, &block)
356  
-        self.inner_implementation_action = block if block_given? unless args.empty?
357  
-        @argument_list_matcher = ArgumentListMatcher.new(*args, &block)
  356
+        if args.empty?
  357
+          raise ArgumentError,
  358
+            "`with` must have at least one argument. Use `no_args` matcher to set the expectation of receiving no arguments."
  359
+        end
  360
+
  361
+        self.inner_implementation_action = block
  362
+        @argument_list_matcher = ArgumentListMatcher.new(*args)
358 363
         self
359 364
       end
360 365
 
7  lib/rspec/mocks/verifying_message_expecation.rb
@@ -26,14 +26,13 @@ def initialize(*args)
26 26
       # @override
27 27
       def with(*args, &block)
28 28
         unless ArgumentMatchers::AnyArgsMatcher === args.first
29  
-          expected_arity = if block
30  
-            block.arity
31  
-          elsif ArgumentMatchers::NoArgsMatcher === args.first
  29
+          expected_arity = if ArgumentMatchers::NoArgsMatcher === args.first
32 30
             0
33 31
           elsif args.length > 0
34 32
             args.length
35 33
           else
36  
-            raise ArgumentError, "No arguments nor block given."
  34
+            # No arguments given, this will raise.
  35
+            super
37 36
           end
38 37
 
39 38
           ensure_arity!(expected_arity)
6  spec/rspec/mocks/block_return_value_spec.rb
@@ -31,6 +31,12 @@
31 31
       obj.stub(:foo).with('baz') { 'bar' }
32 32
       expect(obj.foo('baz')).to eq('bar')
33 33
     end
  34
+
  35
+    it "returns the value of executing the block with given argument" do
  36
+      obj = Object.new
  37
+      obj.stub(:foo).with('baz') {|x| 'bar' + x }
  38
+      expect(obj.foo('baz')).to eq('barbaz')
  39
+    end
34 40
   end
35 41
 
36 42
   %w[once twice ordered and_return].each do |method|
5  spec/rspec/mocks/failing_argument_matchers_spec.rb
@@ -97,11 +97,10 @@ module Mocks
97 97
          end.to raise_error(/array_including\(1,2,3\)/)
98 98
       end
99 99
 
100  
-      it "fails with block matchers" do
  100
+      it "fails with zero arguments" do
101 101
         expect do
102 102
           @double.should_receive(:msg).with {|arg| expect(arg).to eq :received }
103  
-          @double.msg :no_msg_for_you
104  
-        end.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected: :received.*\s*.*got: :no_msg_for_you/)
  103
+        end.to raise_error(ArgumentError, /must have at least one argument/)
105 104
       end
106 105
 
107 106
       it "fails with sensible message when args respond to #description" do
20  spec/rspec/mocks/passing_argument_matchers_spec.rb
@@ -89,26 +89,6 @@ module Mocks
89 89
         end
90 90
       end
91 91
 
92  
-      context "handling block matchers" do
93  
-        it "matches arguments against RSpec expectations" do
94  
-          @double.should_receive(:random_call).with {|arg1, arg2, arr, *rest|
95  
-            expect(arg1).to eq 5
96  
-            expect(arg2.length).to be >= 3
97  
-            expect(arg2.length).to be <= 10
98  
-            expect(arr.map {|i| i * 2}).to eq [2,4,6]
99  
-            expect(rest).to eq [:fee, "fi", 4]
100  
-          }
101  
-          @double.random_call 5, "hello", [1,2,3], :fee, "fi", 4
102  
-        end
103  
-
104  
-        it "does not eval the block as the return value" do
105  
-          eval_count = 0
106  
-          @double.should_receive(:msg).with {|a| eval_count += 1}
107  
-          @double.msg(:ignore)
108  
-          expect(eval_count).to eq(1)
109  
-        end
110  
-      end
111  
-
112 92
       context "handling non-matcher arguments" do
113 93
         it "matches non special symbol (can be removed when deprecated symbols are removed)" do
114 94
           @double.should_receive(:random_call).with(:some_symbol)
12  spec/rspec/mocks/verifying_message_expecation_spec.rb
@@ -55,21 +55,11 @@ module Mocks
55 55
           end
56 56
         end
57 57
 
58  
-        describe 'when called with a block' do
59  
-          it 'matches arity against the arity of the block' do
60  
-            subject.method_finder = Proc.new { lambda {|_| } }
61  
-            expect(error_generator).to receive(:raise_arity_error).
62  
-              with(instance_of(ArityCalculator), 2)
63  
-
64  
-            subject.with {|x, y| }
65  
-          end
66  
-        end
67  
-
68 58
         describe 'when called with no arguments and no block' do
69 59
           it 'raises' do
70 60
             expect {
71 61
               subject.with
72  
-            }.to raise_error(ArgumentError, "No arguments nor block given.")
  62
+            }.to raise_error(ArgumentError)
73 63
           end
74 64
         end
75 65
       end
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.