rspec-expectations 2.0.0.beta.22 → 2.6.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.
Files changed (93) hide show
  1. data/.gitignore +1 -1
  2. data/.travis.yml +7 -0
  3. data/Gemfile +35 -13
  4. data/Guardfile +5 -0
  5. data/License.txt +1 -1
  6. data/README.md +43 -0
  7. data/Rakefile +51 -9
  8. data/cucumber.yml +9 -2
  9. data/features/.nav +29 -0
  10. data/features/Changelog.md +101 -0
  11. data/features/README.markdown +45 -8
  12. data/features/built_in_matchers/README.md +71 -0
  13. data/features/built_in_matchers/be.feature +135 -0
  14. data/features/built_in_matchers/be_within.feature +43 -0
  15. data/features/built_in_matchers/cover.feature +45 -0
  16. data/features/{matchers → built_in_matchers}/equality.feature +16 -13
  17. data/features/built_in_matchers/exist.feature +43 -0
  18. data/features/built_in_matchers/expect_change.feature +59 -0
  19. data/features/built_in_matchers/expect_error.feature +105 -0
  20. data/features/built_in_matchers/have.feature +103 -0
  21. data/features/built_in_matchers/include.feature +121 -0
  22. data/features/built_in_matchers/match.feature +50 -0
  23. data/features/built_in_matchers/operators.feature +221 -0
  24. data/features/built_in_matchers/predicates.feature +128 -0
  25. data/features/built_in_matchers/respond_to.feature +78 -0
  26. data/features/built_in_matchers/satisfy.feature +31 -0
  27. data/features/built_in_matchers/throw_symbol.feature +85 -0
  28. data/features/built_in_matchers/types.feature +114 -0
  29. data/features/{matchers → custom_matchers}/access_running_example.feature +2 -2
  30. data/features/{matchers → custom_matchers}/define_diffable_matcher.feature +1 -1
  31. data/features/{matchers → custom_matchers}/define_matcher.feature +91 -9
  32. data/features/{matchers → custom_matchers}/define_matcher_outside_rspec.feature +1 -1
  33. data/features/{matchers → custom_matchers}/define_matcher_with_fluent_interface.feature +8 -11
  34. data/features/customized_message.feature +22 -0
  35. data/features/{expectations/diffing.feature → diffing.feature} +16 -16
  36. data/features/{expectations/implicit_docstrings.feature → implicit_docstrings.feature} +4 -4
  37. data/features/step_definitions/additional_cli_steps.rb +22 -0
  38. data/features/support/env.rb +5 -1
  39. data/features/test_frameworks/test_unit.feature +46 -0
  40. data/lib/rspec/expectations/backward_compatibility.rb +22 -1
  41. data/lib/rspec/expectations/deprecation.rb +36 -0
  42. data/lib/rspec/expectations/extensions.rb +0 -1
  43. data/lib/rspec/expectations/version.rb +1 -1
  44. data/lib/rspec/expectations.rb +2 -1
  45. data/lib/rspec/matchers/be.rb +4 -4
  46. data/lib/rspec/matchers/be_close.rb +2 -17
  47. data/lib/rspec/matchers/be_within.rb +40 -0
  48. data/lib/rspec/matchers/block_aliases.rb +19 -0
  49. data/lib/rspec/matchers/change.rb +74 -49
  50. data/lib/rspec/matchers/cover.rb +35 -0
  51. data/lib/rspec/matchers/exist.rb +13 -3
  52. data/lib/rspec/matchers/has.rb +15 -11
  53. data/lib/rspec/matchers/have.rb +5 -5
  54. data/lib/rspec/matchers/include.rb +14 -5
  55. data/lib/rspec/matchers/matcher.rb +39 -13
  56. data/lib/rspec/matchers/method_missing.rb +6 -3
  57. data/lib/rspec/matchers/operator_matcher.rb +12 -3
  58. data/lib/rspec/matchers/respond_to.rb +23 -9
  59. data/lib/rspec/matchers/satisfy.rb +4 -0
  60. data/lib/rspec/matchers/throw_symbol.rb +43 -26
  61. data/lib/rspec/matchers.rb +15 -3
  62. data/rspec-expectations.gemspec +2 -6
  63. data/spec/rspec/matchers/be_close_spec.rb +11 -39
  64. data/spec/rspec/matchers/be_spec.rb +8 -8
  65. data/spec/rspec/matchers/be_within_spec.rb +64 -0
  66. data/spec/rspec/matchers/change_spec.rb +88 -9
  67. data/spec/rspec/matchers/cover_spec.rb +65 -0
  68. data/spec/rspec/matchers/description_generation_spec.rb +41 -25
  69. data/spec/rspec/matchers/exist_spec.rb +90 -51
  70. data/spec/rspec/matchers/has_spec.rb +2 -2
  71. data/spec/rspec/matchers/have_spec.rb +291 -291
  72. data/spec/rspec/matchers/include_spec.rb +318 -65
  73. data/spec/rspec/matchers/matcher_spec.rb +91 -0
  74. data/spec/rspec/matchers/matchers_spec.rb +29 -0
  75. data/spec/rspec/matchers/method_missing_spec.rb +23 -0
  76. data/spec/rspec/matchers/operator_matcher_spec.rb +36 -10
  77. data/spec/rspec/matchers/respond_to_spec.rb +177 -1
  78. data/spec/rspec/matchers/satisfy_spec.rb +4 -0
  79. data/spec/rspec/matchers/throw_symbol_spec.rb +27 -10
  80. data/spec/spec_helper.rb +10 -35
  81. data/spec/support/classes.rb +1 -1
  82. data/spec/support/matchers.rb +22 -0
  83. data/spec/support/ruby_version.rb +10 -0
  84. metadata +95 -114
  85. data/History.md +0 -16
  86. data/README.markdown +0 -23
  87. data/features/expectations/attribute_of_subject.feature +0 -19
  88. data/features/expectations/customized_message.feature +0 -54
  89. data/features/matchers/expect_change.feature +0 -65
  90. data/features/matchers/expect_error.feature +0 -44
  91. data/lib/rspec/expectations/extensions/rspec/core/example_group.rb +0 -19
  92. data/spec/suite.rb +0 -1
  93. /data/{Upgrade.markdown → features/Upgrade.md} +0 -0
@@ -1,23 +1,21 @@
1
1
  module RSpec
2
2
  module Matchers
3
-
4
- #Based on patch from Wilson Bilkovich
5
3
  class Change #:nodoc:
6
4
  def initialize(receiver=nil, message=nil, &block)
7
5
  @message = message
8
6
  @value_proc = block || lambda {receiver.__send__(message)}
9
- @to = @from = @minimum = @maximum = @amount = nil
10
- @given_from = @given_to = false
7
+ @expected_after = @expected_before = @minimum = @maximum = @expected_delta = nil
8
+ @eval_before = @eval_after = false
11
9
  end
12
10
 
13
11
  def matches?(event_proc)
14
12
  raise_block_syntax_error if block_given?
15
13
 
16
- @before = evaluate_value_proc
14
+ @actual_before = evaluate_value_proc
17
15
  event_proc.call
18
- @after = evaluate_value_proc
19
-
20
- changed? && matches_before? && matches_after? && matches_amount? && matches_min? && matches_max?
16
+ @actual_after = evaluate_value_proc
17
+
18
+ (!change_expected? || changed?) && matches_before? && matches_after? && matches_expected_delta? && matches_min? && matches_max?
21
19
  end
22
20
 
23
21
  def raise_block_syntax_error
@@ -28,35 +26,40 @@ MESSAGE
28
26
  end
29
27
 
30
28
  def evaluate_value_proc
31
- @value_proc.call
29
+ case val = @value_proc.call
30
+ when Array, Hash
31
+ val.dup
32
+ else
33
+ val
34
+ end
32
35
  end
33
36
 
34
37
  def failure_message_for_should
35
- if @given_from && @before != @from
36
- "#{message} should have initially been #{@from.inspect}, but was #{@before.inspect}"
37
- elsif @given_to && @to != @after
38
- "#{message} should have been changed to #{@to.inspect}, but is now #{@after.inspect}"
39
- elsif @amount
40
- "#{message} should have been changed by #{@amount.inspect}, but was changed by #{actual_delta.inspect}"
38
+ if @eval_before && !expected_matches_actual?(@expected_before, @actual_before)
39
+ "#{message} should have initially been #{@expected_before.inspect}, but was #{@actual_before.inspect}"
40
+ elsif @eval_after && !expected_matches_actual?(@expected_after, @actual_after)
41
+ "#{message} should have been changed to #{@expected_after.inspect}, but is now #{@actual_after.inspect}"
42
+ elsif @expected_delta
43
+ "#{message} should have been changed by #{@expected_delta.inspect}, but was changed by #{actual_delta.inspect}"
41
44
  elsif @minimum
42
45
  "#{message} should have been changed by at least #{@minimum.inspect}, but was changed by #{actual_delta.inspect}"
43
46
  elsif @maximum
44
47
  "#{message} should have been changed by at most #{@maximum.inspect}, but was changed by #{actual_delta.inspect}"
45
48
  else
46
- "#{message} should have changed, but is still #{@before.inspect}"
49
+ "#{message} should have changed, but is still #{@actual_before.inspect}"
47
50
  end
48
51
  end
49
52
 
50
53
  def actual_delta
51
- @after - @before
54
+ @actual_after - @actual_before
52
55
  end
53
56
 
54
57
  def failure_message_for_should_not
55
- "#{message} should not have changed, but did change from #{@before.inspect} to #{@after.inspect}"
58
+ "#{message} should not have changed, but did change from #{@actual_before.inspect} to #{@actual_after.inspect}"
56
59
  end
57
60
 
58
- def by(amount)
59
- @amount = amount
61
+ def by(expected_delta)
62
+ @expected_delta = expected_delta
60
63
  self
61
64
  end
62
65
 
@@ -71,14 +74,14 @@ MESSAGE
71
74
  end
72
75
 
73
76
  def to(to)
74
- @given_to = true
75
- @to = to
77
+ @eval_after = true
78
+ @expected_after = to
76
79
  self
77
80
  end
78
81
 
79
- def from (from)
80
- @given_from = true
81
- @from = from
82
+ def from (before)
83
+ @eval_before = true
84
+ @expected_before = before
82
85
  self
83
86
  end
84
87
 
@@ -92,39 +95,59 @@ MESSAGE
92
95
  @message || "result"
93
96
  end
94
97
 
98
+ def change_expected?
99
+ @expected_delta != 0
100
+ end
101
+
95
102
  def changed?
96
- @before != @after
103
+ @actual_before != @actual_after
97
104
  end
98
105
 
99
106
  def matches_before?
100
- @given_from ? @from == @before : true
107
+ @eval_before ? expected_matches_actual?(@expected_before, @actual_before) : true
101
108
  end
102
109
 
103
110
  def matches_after?
104
- @given_to ? @to == @after : true
111
+ @eval_after ? expected_matches_actual?(@expected_after, @actual_after) : true
105
112
  end
106
113
 
107
- def matches_amount?
108
- @amount ? (@before + @amount == @after) : true
114
+ def matches_expected_delta?
115
+ @expected_delta ? (@actual_before + @expected_delta == @actual_after) : true
109
116
  end
110
117
 
111
118
  def matches_min?
112
- @minimum ? (@after - @before >= @minimum) : true
119
+ @minimum ? (@actual_after - @actual_before >= @minimum) : true
113
120
  end
114
121
 
115
122
  def matches_max?
116
- @maximum ? (@after - @before <= @maximum) : true
123
+ @maximum ? (@actual_after - @actual_before <= @maximum) : true
117
124
  end
118
125
 
126
+ def expected_matches_actual?(expected, actual)
127
+ expected === actual
128
+ end
119
129
  end
120
130
 
121
131
  # :call-seq:
122
- # should change(receiver, message, &block)
123
- # should change(receiver, message, &block).by(value)
124
- # should change(receiver, message, &block).from(old).to(new)
125
- # should_not change(receiver, message, &block)
132
+ # should change(receiver, message)
133
+ # should change(receiver, message).by(value)
134
+ # should change(receiver, message).from(old).to(new)
135
+ # should_not change(receiver, message)
126
136
  #
127
- # Allows you to specify that a Proc will cause some value to change.
137
+ # should change {...}
138
+ # should change {...}.by(value)
139
+ # should change {...}.from(old).to(new)
140
+ # should_not change {...}
141
+ #
142
+ # Applied to a proc, specifies that its execution will cause some value to
143
+ # change.
144
+ #
145
+ # You can either pass <tt>receiver</tt> and <tt>message</tt>, or a block,
146
+ # but not both.
147
+ #
148
+ # When passing a block, it must use the <tt>{ ... }</tt> format, not
149
+ # do/end, as <tt>{ ... }</tt> binds to the +change+ method, whereas do/end
150
+ # would errantly bind to the +should+ or +should_not+ method.
128
151
  #
129
152
  # == Examples
130
153
  #
@@ -157,22 +180,24 @@ MESSAGE
157
180
  # employee.develop_great_new_social_networking_app
158
181
  # }.should change(employee, :title).from("Mail Clerk").to("CEO")
159
182
  #
160
- # Evaluates <tt>receiver.message</tt> or <tt>block</tt> before and after
161
- # it evaluates the c object (generated by the lambdas in the examples
162
- # above).
183
+ # lambda {
184
+ # doctor.leave_office
185
+ # }.should change(doctor, :sign).from(/is in/).to(/is out/)
163
186
  #
164
- # Then compares the values before and after the <tt>receiver.message</tt>
165
- # and evaluates the difference compared to the expected difference.
187
+ # user = User.new(:type => "admin")
188
+ # lambda {
189
+ # user.symbolize_type
190
+ # }.should change(user, :type).from(String).to(Symbol)
166
191
  #
167
- # == WARNING
168
- # <tt>should_not change</tt> only supports the form with no
169
- # subsequent calls to <tt>by</tt>, <tt>by_at_least</tt>,
170
- # <tt>by_at_most</tt>, <tt>to</tt> or <tt>from</tt>.
192
+ # == Notes
171
193
  #
172
- # blocks passed to <tt>should</tt> <tt>change</tt> and <tt>should_not</tt>
173
- # <tt>change</tt> must use the <tt>{}</tt> form (<tt>do/end</tt> is not
174
- # supported).
194
+ # Evaluates <tt>receiver.message</tt> or <tt>block</tt> before and after it
195
+ # evaluates the proc object (generated by the lambdas in the examples
196
+ # above).
175
197
  #
198
+ # <tt>should_not change</tt> only supports the form with no subsequent
199
+ # calls to <tt>by</tt>, <tt>by_at_least</tt>, <tt>by_at_most</tt>,
200
+ # <tt>to</tt> or <tt>from</tt>.
176
201
  def change(receiver=nil, message=nil, &block)
177
202
  Matchers::Change.new(receiver, message, &block)
178
203
  end
@@ -0,0 +1,35 @@
1
+ module RSpec
2
+ module Matchers
3
+ # :call-seq:
4
+ # should cover(expected)
5
+ # should_not cover(expected)
6
+ #
7
+ # Passes if actual covers expected. This works for
8
+ # Ranges. You can also pass in multiple args
9
+ # and it will only pass if all args are found in Range.
10
+ #
11
+ # == Examples
12
+ # (1..10).should cover(5)
13
+ # (1..10).should cover(4, 6)
14
+ # (1..10).should cover(4, 6, 11) # will fail
15
+ # (1..10).should_not cover(11)
16
+ # (1..10).should_not cover(5) # will fail
17
+ #
18
+ # == Warning: Ruby >= 1.9 only
19
+ def cover(*values)
20
+ Matcher.new :cover, *values do |*_values|
21
+ match_for_should do |range|
22
+ _values.all? &covered_by(range)
23
+ end
24
+
25
+ match_for_should_not do |range|
26
+ _values.none? &covered_by(range)
27
+ end
28
+
29
+ def covered_by(range)
30
+ lambda {|value| range.cover?(value)}
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -4,11 +4,21 @@ module RSpec
4
4
  # should exist
5
5
  # should_not exist
6
6
  #
7
- # Passes if actual.exist?
8
- def exist(arg=nil)
7
+ # Passes if actual.exist? or actual.exists?
8
+ def exist(*args)
9
9
  Matcher.new :exist do
10
10
  match do |actual|
11
- arg ? actual.exist?(arg) : actual.exist?
11
+ predicates = [:exist?, :exists?].select { |p| actual.respond_to?(p) }
12
+ existance_values = predicates.map { |p| actual.send(p, *args) }
13
+ uniq_truthy_values = existance_values.map { |v| !!v }.uniq
14
+
15
+ case uniq_truthy_values.size
16
+ when 0; raise NoMethodError.new("#{actual.inspect} does not respond to either #exist? or #exists?")
17
+ when 1; existance_values.first
18
+ else raise "#exist? and #exists? returned different values:\n\n" +
19
+ " exist?: #{existance_values.first}\n" +
20
+ "exists?: #{existance_values.last}"
21
+ end
12
22
  end
13
23
  end
14
24
  end
@@ -1,35 +1,39 @@
1
1
  module RSpec
2
2
  module Matchers
3
-
4
3
  class Has
5
-
6
4
  def initialize(expected, *args)
7
5
  @expected, @args = expected, args
8
6
  end
9
-
7
+
10
8
  def matches?(actual)
11
9
  actual.__send__(predicate(@expected), *@args)
12
10
  end
13
-
11
+
14
12
  def failure_message_for_should
15
13
  "expected ##{predicate(@expected)}(#{@args[0].inspect}) to return true, got false"
16
14
  end
17
-
15
+
18
16
  def failure_message_for_should_not
19
17
  "expected ##{predicate(@expected)}(#{@args[0].inspect}) to return false, got true"
20
18
  end
21
-
19
+
22
20
  def description
23
- "have key #{@args[0].inspect}"
21
+ [method_description(@expected), args_description(@args)].compact.join(' ')
24
22
  end
25
-
23
+
26
24
  private
27
-
28
25
  def predicate(sym)
29
26
  "#{sym.to_s.sub("have_","has_")}?".to_sym
30
27
  end
31
-
28
+
29
+ def method_description(method)
30
+ method.to_s.gsub('_', ' ')
31
+ end
32
+
33
+ def args_description(args)
34
+ return nil if args.empty?
35
+ args.map { |arg| arg.inspect }.join(', ')
36
+ end
32
37
  end
33
-
34
38
  end
35
39
  end
@@ -4,7 +4,7 @@ module RSpec
4
4
  def initialize(expected, relativity=:exactly)
5
5
  @expected = (expected == :no ? 0 : expected)
6
6
  @relativity = relativity
7
- @actual = nil
7
+ @actual = @collection_name = @plural_collection_name = nil
8
8
  end
9
9
 
10
10
  def relativities
@@ -73,10 +73,10 @@ EOF
73
73
 
74
74
  private
75
75
 
76
- def method_missing(sym, *args, &block)
77
- @collection_name = sym
78
- if inflector = (defined?(ActiveSupport::Inflector) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
79
- @plural_collection_name = inflector.pluralize(sym.to_s)
76
+ def method_missing(method, *args, &block)
77
+ @collection_name = method
78
+ if inflector = (defined?(ActiveSupport::Inflector) && ActiveSupport::Inflector.respond_to?(:pluralize) ? ActiveSupport::Inflector : (defined?(Inflector) ? Inflector : nil))
79
+ @plural_collection_name = inflector.pluralize(method.to_s)
80
80
  end
81
81
  @args = args
82
82
  @block = block
@@ -18,10 +18,21 @@ module RSpec
18
18
  # "spread".should_not include("red")
19
19
  def include(*expected)
20
20
  Matcher.new :include, *expected do |*_expected|
21
- match do |actual|
22
- _expected.all? do |expected|
21
+
22
+ diffable
23
+
24
+ match_for_should do |actual|
25
+ perform_match(:all?, :all?, actual, _expected)
26
+ end
27
+
28
+ match_for_should_not do |actual|
29
+ perform_match(:none?, :any?, actual, _expected)
30
+ end
31
+
32
+ def perform_match(predicate, hash_predicate, actual, _expected)
33
+ _expected.send(predicate) do |expected|
23
34
  if comparing_hash_values?(actual, expected)
24
- expected.all? {|k,v| actual[k] == v}
35
+ expected.send(hash_predicate) {|k,v| actual[k] == v}
25
36
  elsif comparing_hash_keys?(actual, expected)
26
37
  actual.has_key?(expected)
27
38
  else
@@ -37,9 +48,7 @@ module RSpec
37
48
  def comparing_hash_values?(actual, expected) # :nodoc:
38
49
  actual.is_a?(Hash) && expected.is_a?(Hash)
39
50
  end
40
-
41
51
  end
42
-
43
52
  end
44
53
  end
45
54
  end
@@ -11,7 +11,9 @@ module RSpec
11
11
  @expected = expected
12
12
  @actual = nil
13
13
  @diffable = false
14
- @expected_exception, @rescued_exception = nil
14
+ @expected_exception, @rescued_exception = nil, nil
15
+ @match_for_should_not_block = nil
16
+
15
17
  @messages = {
16
18
  :description => lambda {"#{name_to_sentence}#{expected_to_sentence}"},
17
19
  :failure_message_for_should => lambda {|actual| "expected #{actual.inspect} to #{name_to_sentence}#{expected_to_sentence}"},
@@ -22,7 +24,7 @@ module RSpec
22
24
  end
23
25
  end
24
26
 
25
- #Used internally by objects returns by +should+ and +should_not+.
27
+ #Used internally by +should+ and +should_not+.
26
28
  def matches?(actual)
27
29
  @actual = actual
28
30
  if @expected_exception
@@ -41,10 +43,32 @@ module RSpec
41
43
  end
42
44
  end
43
45
 
46
+ # Used internally by +should_not+
47
+ def does_not_match?(actual)
48
+ @actual = actual
49
+ @match_for_should_not_block ?
50
+ instance_exec(actual, &@match_for_should_not_block) :
51
+ !matches?(actual)
52
+ end
53
+
54
+ def include(*args)
55
+ singleton_class.__send__(:include, *args)
56
+ end
57
+
58
+ def define_method(name, &block) # :nodoc:
59
+ singleton_class.__send__(:define_method, name, &block)
60
+ end
61
+
44
62
  # See RSpec::Matchers
45
63
  def match(&block)
46
64
  @match_block = block
47
65
  end
66
+ alias match_for_should match
67
+
68
+ # See RSpec::Matchers
69
+ def match_for_should_not(&block)
70
+ @match_for_should_not_block = block
71
+ end
48
72
 
49
73
  # See RSpec::Matchers
50
74
  def match_unless_raises(exception=Exception, &block)
@@ -79,21 +103,19 @@ module RSpec
79
103
 
80
104
  # See RSpec::Matchers
81
105
  def chain(method, &block)
82
- self.class.class_eval do
83
- define_method method do |*args|
84
- block.call(*args)
85
- self
86
- end
106
+ define_method method do |*args|
107
+ block.call(*args)
108
+ self
87
109
  end
88
110
  end
89
111
 
90
112
  private
91
113
 
92
- def method_missing(name, *args, &block)
93
- if $matcher_execution_context.respond_to?(name)
94
- $matcher_execution_context.send name, *args, &block
114
+ def method_missing(method, *args, &block)
115
+ if $matcher_execution_context.respond_to?(method)
116
+ $matcher_execution_context.send method, *args, &block
95
117
  else
96
- super(name, *args, &block)
118
+ super(method, *args, &block)
97
119
  end
98
120
  end
99
121
 
@@ -110,8 +132,7 @@ module RSpec
110
132
  # cause features to fail and that will make users unhappy. So don't.
111
133
  orig_private_methods = private_methods
112
134
  yield
113
- st = (class << self; self; end)
114
- (private_methods - orig_private_methods).each {|m| st.__send__ :public, m}
135
+ (private_methods - orig_private_methods).each {|m| singleton_class.__send__ :public, m}
115
136
  end
116
137
 
117
138
  def cache_or_call_cached(key, &block)
@@ -134,6 +155,11 @@ module RSpec
134
155
  to_sentence(@expected)
135
156
  end
136
157
 
158
+ unless method_defined?(:singleton_class)
159
+ def singleton_class
160
+ class << self; self; end
161
+ end
162
+ end
137
163
  end
138
164
  end
139
165
  end
@@ -1,8 +1,11 @@
1
1
  module RSpec
2
2
  module Matchers
3
- def method_missing(sym, *args, &block) # :nodoc:
4
- return Matchers::BePredicate.new(sym, *args, &block) if sym.to_s =~ /^be_/
5
- return Matchers::Has.new(sym, *args, &block) if sym.to_s =~ /^have_/
3
+
4
+ private
5
+
6
+ def method_missing(method, *args, &block) # :nodoc:
7
+ return Matchers::BePredicate.new(method, *args, &block) if method.to_s =~ /^be_/
8
+ return Matchers::Has.new(method, *args, &block) if method.to_s =~ /^have_/
6
9
  super
7
10
  end
8
11
  end
@@ -29,6 +29,15 @@ module RSpec
29
29
  eval_match(@actual, operator, expected)
30
30
  end
31
31
  end
32
+
33
+ negative_operator = operator.sub(/^=/, '!')
34
+ if negative_operator != operator && respond_to?(negative_operator)
35
+ define_method(negative_operator) do |expected|
36
+ opposite_should = ::RSpec::Matchers.last_should == :should ? :should_not : :should
37
+ raise "RSpec does not support `#{::RSpec::Matchers.last_should} #{negative_operator} expected`. " +
38
+ "Use `#{opposite_should} #{operator} expected` instead."
39
+ end
40
+ end
32
41
  end
33
42
 
34
43
  ['==', '===', '=~', '>', '>=', '<', '<='].each do |operator|
@@ -58,9 +67,9 @@ module RSpec
58
67
  if actual.__send__(operator, expected)
59
68
  true
60
69
  elsif ['==','===', '=~'].include?(operator)
61
- fail_with_message("expected: #{expected.inspect},\n got: #{actual.inspect} (using #{operator})")
70
+ fail_with_message("expected: #{expected.inspect}\n got: #{actual.inspect} (using #{operator})")
62
71
  else
63
- fail_with_message("expected: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{actual.inspect}")
72
+ fail_with_message("expected: #{operator} #{expected.inspect}\n got: #{operator.gsub(/./, ' ')} #{actual.inspect}")
64
73
  end
65
74
  end
66
75
 
@@ -69,7 +78,7 @@ module RSpec
69
78
  class NegativeOperatorMatcher < OperatorMatcher #:nodoc:
70
79
  def __delegate_operator(actual, operator, expected)
71
80
  return false unless actual.__send__(operator, expected)
72
- return fail_with_message("expected not: #{operator} #{expected.inspect},\n got: #{operator.gsub(/./, ' ')} #{actual.inspect}")
81
+ return fail_with_message("expected not: #{operator} #{expected.inspect}\n got: #{operator.gsub(/./, ' ')} #{actual.inspect}")
73
82
  end
74
83
 
75
84
  end
@@ -5,23 +5,22 @@ module RSpec
5
5
  def initialize(*names)
6
6
  @names = names
7
7
  @expected_arity = nil
8
- @names_not_responded_to = []
9
8
  end
10
9
 
11
10
  def matches?(actual)
12
- @actual = actual
13
- @names.each do |name|
14
- @names_not_responded_to << name unless actual.respond_to?(name) && matches_arity?(actual, name)
15
- end
16
- return @names_not_responded_to.empty?
11
+ find_failing_method_names(actual, :reject).empty?
12
+ end
13
+
14
+ def does_not_match?(actual)
15
+ find_failing_method_names(actual, :select).empty?
17
16
  end
18
17
 
19
18
  def failure_message_for_should
20
- "expected #{@actual.inspect} to respond to #{@names_not_responded_to.collect {|name| name.inspect }.join(', ')}#{with_arity}"
19
+ "expected #{@actual.inspect} to respond to #{@failing_method_names.collect {|name| name.inspect }.join(', ')}#{with_arity}"
21
20
  end
22
21
 
23
22
  def failure_message_for_should_not
24
- "expected #{@actual.inspect} not to respond to #{@names.collect {|name| name.inspect }.join(', ')}"
23
+ failure_message_for_should.sub(/to respond to/, 'not to respond to')
25
24
  end
26
25
 
27
26
  def description
@@ -39,9 +38,24 @@ module RSpec
39
38
  alias :arguments :argument
40
39
 
41
40
  private
41
+
42
+ def find_failing_method_names(actual, filter_method)
43
+ @actual = actual
44
+ @failing_method_names = @names.send(filter_method) do |name|
45
+ @actual.respond_to?(name) && matches_arity?(actual, name)
46
+ end
47
+ end
42
48
 
43
49
  def matches_arity?(actual, name)
44
- @expected_arity.nil?? true : @expected_arity == actual.method(name).arity
50
+ return true unless @expected_arity
51
+
52
+ actual_arity = actual.method(name).arity
53
+ if actual_arity < 0
54
+ # ~ inverts the one's complement and gives us the number of required args
55
+ ~actual_arity <= @expected_arity
56
+ else
57
+ actual_arity == @expected_arity
58
+ end
45
59
  end
46
60
 
47
61
  def with_arity
@@ -19,6 +19,10 @@ module RSpec
19
19
  def failure_message_for_should_not
20
20
  "expected #{@actual} not to satisfy block"
21
21
  end
22
+
23
+ def description
24
+ "satisfy block"
25
+ end
22
26
  end
23
27
 
24
28
  # :call-seq: