rspec-expectations 2.99.0.beta2 → 2.99.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/Changelog.md +55 -32
  3. data/features/README.md +2 -1
  4. data/lib/rspec-expectations.rb +5 -0
  5. data/lib/rspec/expectations.rb +1 -1
  6. data/lib/rspec/{matchers → expectations}/configuration.rb +5 -3
  7. data/lib/rspec/expectations/expectation_target.rb +75 -8
  8. data/lib/rspec/expectations/syntax.rb +3 -5
  9. data/lib/rspec/expectations/version.rb +1 -1
  10. data/lib/rspec/matchers.rb +12 -5
  11. data/lib/rspec/matchers/built_in/base_matcher.rb +11 -3
  12. data/lib/rspec/matchers/built_in/be.rb +15 -4
  13. data/lib/rspec/matchers/built_in/be_within.rb +6 -1
  14. data/lib/rspec/matchers/built_in/change.rb +4 -2
  15. data/lib/rspec/matchers/built_in/has.rb +38 -6
  16. data/lib/rspec/matchers/built_in/include.rb +1 -1
  17. data/lib/rspec/matchers/built_in/match_array.rb +1 -1
  18. data/lib/rspec/matchers/built_in/raise_error.rb +5 -0
  19. data/lib/rspec/matchers/built_in/respond_to.rb +5 -0
  20. data/lib/rspec/matchers/built_in/satisfy.rb +5 -0
  21. data/lib/rspec/matchers/built_in/throw_symbol.rb +8 -1
  22. data/lib/rspec/matchers/built_in/yield.rb +21 -1
  23. data/lib/rspec/matchers/dsl.rb +2 -1
  24. data/lib/rspec/matchers/matcher.rb +28 -7
  25. data/lib/rspec/matchers/pretty.rb +4 -0
  26. data/spec/rspec/{matchers → expectations}/configuration_spec.rb +21 -2
  27. data/spec/rspec/expectations/expectation_target_spec.rb +62 -0
  28. data/spec/rspec/expectations/extensions/kernel_spec.rb +4 -0
  29. data/spec/rspec/expectations_spec.rb +7 -0
  30. data/spec/rspec/matchers/be_spec.rb +21 -0
  31. data/spec/rspec/matchers/description_generation_spec.rb +1 -1
  32. data/spec/rspec/matchers/has_spec.rb +24 -0
  33. data/spec/rspec/matchers/matcher_spec.rb +52 -0
  34. data/spec/rspec/matchers/pretty_spec.rb +23 -0
  35. data/spec/spec_helper.rb +2 -2
  36. data/spec/support/helper_methods.rb +6 -0
  37. metadata +64 -75
@@ -79,11 +79,9 @@ module RSpec
79
79
  def enable_expect(syntax_host = ::RSpec::Matchers)
80
80
  return if expect_enabled?(syntax_host)
81
81
 
82
- syntax_host.module_eval do
83
- def expect(*target, &target_block)
84
- target << target_block if block_given?
85
- raise ArgumentError.new("You must pass an argument or a block to #expect but not both.") unless target.size == 1
86
- ::RSpec::Expectations::ExpectationTarget.new(target.first)
82
+ syntax_host.module_exec do
83
+ def expect(value=::RSpec::Expectations::ExpectationTarget::UndefinedValue, &block)
84
+ ::RSpec::Expectations::ExpectationTarget.for(value, block)
87
85
  end
88
86
  end
89
87
 
@@ -2,7 +2,7 @@ module RSpec
2
2
  module Expectations
3
3
  # @private
4
4
  module Version
5
- STRING = '2.99.0.beta2'
5
+ STRING = '2.99.0.rc1'
6
6
  end
7
7
  end
8
8
  end
@@ -25,6 +25,7 @@ module RSpec
25
25
  # does_not_match?(actual)
26
26
  # failure_message_for_should_not
27
27
  # description
28
+ # supports_block_expectations?
28
29
  #
29
30
  # ## Predicates
30
31
  #
@@ -711,11 +712,17 @@ module RSpec
711
712
  BuiltIn::OperatorMatcher.register(Enumerable, '=~', BuiltIn::MatchArray)
712
713
 
713
714
  def self.const_missing(name)
714
- return super unless name == :OperatorMatcher
715
-
716
- RSpec.deprecate("RSpec::Matchers::OperatorMatcher",
717
- :replacement => "RSpec::Matchers::BuiltIn::OperatorMatcher")
718
- BuiltIn::OperatorMatcher
715
+ case name
716
+ when :OperatorMatcher
717
+ RSpec.deprecate("`RSpec::Matchers::OperatorMatcher`",
718
+ :replacement => "`RSpec::Matchers::BuiltIn::OperatorMatcher`")
719
+ BuiltIn::OperatorMatcher
720
+ when :Configuration
721
+ RSpec.deprecate("`RSpec::Matchers::Configuration`",
722
+ :replacement => "`RSpec::Expectations::Configuration`")
723
+ Expectations::Configuration
724
+ else super
725
+ end
719
726
  end
720
727
  end
721
728
  end
@@ -40,12 +40,12 @@ module RSpec
40
40
 
41
41
  def failure_message_for_should
42
42
  assert_ivars :@actual
43
- "expected #{@actual.inspect} to #{name_to_sentence}#{expected_to_sentence}"
43
+ "expected #{@actual.inspect} to #{name_to_sentence}#{to_sentence expected}"
44
44
  end
45
45
 
46
46
  def failure_message_for_should_not
47
47
  assert_ivars :@actual
48
- "expected #{@actual.inspect} not to #{name_to_sentence}#{expected_to_sentence}"
48
+ "expected #{@actual.inspect} not to #{name_to_sentence}#{to_sentence expected}"
49
49
  end
50
50
 
51
51
  def description
@@ -56,7 +56,15 @@ module RSpec
56
56
  false
57
57
  end
58
58
 
59
- private
59
+ # @api private
60
+ # Most matchers are value matchers (i.e. meant to work with `expect(value)`)
61
+ # rather than block matchers (i.e. meant to work with `expect { }`), so
62
+ # this defaults to false. Block matchers must override this to return true.
63
+ def supports_block_expectations?
64
+ false
65
+ end
66
+
67
+ private
60
68
 
61
69
  def assert_ivars *ivars
62
70
  raise "#{self.class.name} needs to supply #{to_sentence ivars}" unless ivars.all? { |v| instance_variables.map(&:intern).include? v }
@@ -149,13 +149,17 @@ it is a bit confusing.
149
149
  end
150
150
 
151
151
  begin
152
- return @result = actual.__send__(predicate, *@args, &@block)
152
+ @result = actual.__send__(predicate, *@args, &@block)
153
+ check_respond_to(predicate)
154
+ return @result
153
155
  rescue NameError => predicate_missing_error
154
156
  "this needs to be here or rcov will not count this branch even though it's executed in a code example"
155
157
  end
156
158
 
157
159
  begin
158
- return @result = actual.__send__(present_tense_predicate, *@args, &@block)
160
+ @result = actual.__send__(present_tense_predicate, *@args, &@block)
161
+ check_respond_to(present_tense_predicate)
162
+ return @result
159
163
  rescue NameError
160
164
  raise predicate_missing_error
161
165
  end
@@ -175,10 +179,10 @@ it is a bit confusing.
175
179
  "#{prefix_to_sentence}#{expected_to_sentence}#{args_to_sentence}"
176
180
  end
177
181
 
178
- private
182
+ private
179
183
 
180
184
  # support 1.8.7
181
- if methods.first.is_a? String
185
+ if String === methods.first
182
186
  def is_private_on? actual
183
187
  actual.private_methods.include? predicate.to_s
184
188
  end
@@ -209,6 +213,13 @@ it is a bit confusing.
209
213
  def prefix_to_sentence
210
214
  split_words(@prefix)
211
215
  end
216
+
217
+ def check_respond_to(method)
218
+ RSpec.deprecate(
219
+ "Matching with #{@prefix}#{@expected} on an object that doesn't respond to `#{method}`",
220
+ :replacement => "`respond_to_missing?` or `respond_to?` on your object"
221
+ ) unless actual.respond_to?(method)
222
+ end
212
223
  end
213
224
  end
214
225
  end
@@ -41,7 +41,12 @@ module RSpec
41
41
  "be within #{@delta}#{@unit} of #{@expected}"
42
42
  end
43
43
 
44
- private
44
+ # @private
45
+ def supports_block_expectations?
46
+ false
47
+ end
48
+
49
+ private
45
50
 
46
51
  def needs_subtractable
47
52
  ArgumentError.new "The actual value (#{@actual.inspect}) must respond to `-`"
@@ -40,7 +40,6 @@ module RSpec
40
40
 
41
41
  unless matches_before?
42
42
  RSpec.warn_deprecation(<<-EOS.gsub(/^\s+\|/, ''))
43
- |--------------------------------------------------------------------
44
43
  |The semantics of `expect { }.not_to change { }.from()` are changing
45
44
  |in RSpec 3. In RSpec 2.x, this would pass if the value changed but
46
45
  |the starting value was not what you specified with `from()`. In
@@ -49,7 +48,6 @@ module RSpec
49
48
  |
50
49
  |You have an expectation that relies upon the old RSpec 2.x semantics
51
50
  |at: #{CallerFilter.first_non_rspec_line}"
52
- |--------------------------------------------------------------------
53
51
  EOS
54
52
  end
55
53
 
@@ -126,6 +124,10 @@ MESSAGE
126
124
  "change ##{message}"
127
125
  end
128
126
 
127
+ def supports_block_expectations?
128
+ true
129
+ end
130
+
129
131
  private
130
132
 
131
133
  def failure_message_for_expected_after
@@ -9,25 +9,50 @@ module RSpec
9
9
  end
10
10
 
11
11
  def matches?(actual)
12
- actual.__send__(predicate(@expected), *@args)
12
+ method = predicate
13
+
14
+ if is_private_on?(actual)
15
+ RSpec.deprecate "matching with #{@expected} on private method #{predicate}",
16
+ :replacement => "`expect(object.send(#{predicate.inspect})).to be_true` or change the method's visibility to public"
17
+ end
18
+
19
+ result = actual.__send__(method, *@args)
20
+ check_respond_to(actual, method)
21
+ result
13
22
  end
14
23
 
15
24
  def failure_message_for_should
16
- "expected ##{predicate(@expected)}#{failure_message_args_description} to return true, got false"
25
+ "expected ##{predicate}#{failure_message_args_description} to return true, got false"
17
26
  end
18
27
 
19
28
  def failure_message_for_should_not
20
- "expected ##{predicate(@expected)}#{failure_message_args_description} to return false, got true"
29
+ "expected ##{predicate}#{failure_message_args_description} to return false, got true"
21
30
  end
22
31
 
23
32
  def description
24
33
  [method_description(@expected), args_description].compact.join(' ')
25
34
  end
26
35
 
27
- private
36
+ # @private
37
+ def supports_block_expectations?
38
+ false
39
+ end
40
+
41
+ private
28
42
 
29
- def predicate(sym)
30
- "#{sym.to_s.sub("have_","has_")}?".to_sym
43
+ # support 1.8.7
44
+ if String === methods.first
45
+ def is_private_on? actual
46
+ actual.private_methods.include? predicate.to_s
47
+ end
48
+ else
49
+ def is_private_on? actual
50
+ actual.private_methods.include? predicate
51
+ end
52
+ end
53
+
54
+ def predicate
55
+ "#{@expected.to_s.sub("have_","has_")}?".to_sym
31
56
  end
32
57
 
33
58
  def method_description(method)
@@ -43,6 +68,13 @@ module RSpec
43
68
  desc = args_description
44
69
  "(#{desc})" if desc
45
70
  end
71
+
72
+ def check_respond_to(actual, method)
73
+ RSpec.deprecate(
74
+ "Matching with #{@expected} on an object that doesn't respond to `#{method}`",
75
+ :replacement => "`respond_to_missing?` or `respond_to?` on your object"
76
+ ) unless actual.respond_to?(method)
77
+ end
46
78
  end
47
79
  end
48
80
  end
@@ -17,7 +17,7 @@ module RSpec
17
17
  end
18
18
 
19
19
  def description
20
- "include#{expected_to_sentence}"
20
+ "include#{to_sentence expected}"
21
21
  end
22
22
 
23
23
  def diffable?
@@ -27,7 +27,7 @@ module RSpec
27
27
  end
28
28
 
29
29
  def description
30
- "contain exactly #{_pretty_print(expected)}"
30
+ "contain exactly#{to_sentence(expected)}"
31
31
  end
32
32
 
33
33
  private
@@ -91,6 +91,11 @@ module RSpec
91
91
  "raise #{expected_error}"
92
92
  end
93
93
 
94
+ # @private
95
+ def supports_block_expectations?
96
+ true
97
+ end
98
+
94
99
  private
95
100
 
96
101
  def expected_error
@@ -39,6 +39,11 @@ module RSpec
39
39
  end
40
40
  alias :arguments :argument
41
41
 
42
+ # @private
43
+ def supports_block_expectations?
44
+ false
45
+ end
46
+
42
47
  private
43
48
 
44
49
  def find_failing_method_names(actual, filter_method)
@@ -25,6 +25,11 @@ module RSpec
25
25
  def description
26
26
  "satisfy block"
27
27
  end
28
+
29
+ # @private
30
+ def supports_block_expectations?
31
+ false
32
+ end
28
33
  end
29
34
  end
30
35
  end
@@ -66,7 +66,14 @@ module RSpec
66
66
  "throw #{expected}"
67
67
  end
68
68
 
69
- private
69
+ # @api private
70
+ # Indicates this matcher matches against a block.
71
+ # @return [True]
72
+ def supports_block_expectations?
73
+ true
74
+ end
75
+
76
+ private
70
77
 
71
78
  def expected(symbol_desc = 'a Symbol')
72
79
  throw_description(@expected_symbol || symbol_desc, @expected_arg)
@@ -121,7 +121,12 @@ module RSpec
121
121
  end
122
122
  end
123
123
 
124
- private
124
+ # @private
125
+ def supports_block_expectations?
126
+ true
127
+ end
128
+
129
+ private
125
130
 
126
131
  def set_expected_yields_count(relativity, n)
127
132
  @expectation_type = relativity
@@ -169,6 +174,11 @@ module RSpec
169
174
  "expected given block not to yield with no arguments, but did"
170
175
  end
171
176
 
177
+ # @private
178
+ def supports_block_expectations?
179
+ true
180
+ end
181
+
172
182
  private
173
183
 
174
184
  def failure_reason
@@ -207,6 +217,11 @@ module RSpec
207
217
  desc
208
218
  end
209
219
 
220
+ # @private
221
+ def supports_block_expectations?
222
+ true
223
+ end
224
+
210
225
  private
211
226
 
212
227
  def positive_failure_reason
@@ -282,6 +297,11 @@ module RSpec
282
297
  desc
283
298
  end
284
299
 
300
+ # @private
301
+ def supports_block_expectations?
302
+ true
303
+ end
304
+
285
305
  private
286
306
 
287
307
  def args_match?
@@ -7,7 +7,8 @@ module RSpec
7
7
  matcher_template = RSpec::Matchers::DSL::Matcher.new(name, &declarations)
8
8
  define_method name do |*expected|
9
9
  matcher = matcher_template.for_expected(*expected)
10
- matcher.matcher_execution_context = @matcher_execution_context ||= self
10
+ @matcher_execution_context ||= self
11
+ matcher.instance_variable_set(:@matcher_execution_context, @matcher_execution_context)
11
12
  matcher
12
13
  end
13
14
  end
@@ -12,7 +12,6 @@ module RSpec
12
12
  include RSpec::Matchers
13
13
 
14
14
  attr_reader :actual, :rescued_exception
15
- attr_accessor :matcher_execution_context
16
15
 
17
16
  # @api private
18
17
  def initialize(name, &declarations)
@@ -20,16 +19,19 @@ module RSpec
20
19
  @declarations = declarations
21
20
  @actual = nil
22
21
  @diffable = false
22
+ @supports_block_expectations = false
23
23
  @expected_exception, @rescued_exception = nil, nil
24
24
  @match_for_should_not_block = nil
25
25
  @messages = {}
26
26
  @define_block_executed = false
27
27
  @block_method_differentiator = nil
28
28
  @deprecated_methods = Set.new
29
+ @matcher_execution_context = nil
29
30
  end
30
31
 
31
32
  PERSISTENT_INSTANCE_VARIABLES = [
32
33
  :@name, :@declarations, :@diffable,
34
+ :@supports_block_expectations,
33
35
  :@match_block, :@match_for_should_not_block,
34
36
  :@expected_exception
35
37
  ].to_set
@@ -51,6 +53,16 @@ module RSpec
51
53
  @expected
52
54
  end
53
55
 
56
+ def matcher_execution_context=(value)
57
+ RSpec.deprecate("`matcher_execution_context=` on custom matchers")
58
+ @matcher_execution_context = value
59
+ end
60
+
61
+ def matcher_execution_context
62
+ RSpec.deprecate("`matcher_execution_context` on custom matchers")
63
+ @matcher_execution_context
64
+ end
65
+
54
66
  # @api private
55
67
  def for_expected(*expected)
56
68
  @expected = expected
@@ -209,6 +221,10 @@ module RSpec
209
221
  @diffable = true
210
222
  end
211
223
 
224
+ def supports_block_expectations
225
+ @supports_block_expectations = true
226
+ end
227
+
212
228
  # Convenience for defining methods on this matcher to create a fluent
213
229
  # interface. The trick about fluent interfaces is that each method must
214
230
  # return self in order to chain methods together. `chain` handles that
@@ -240,6 +256,11 @@ module RSpec
240
256
  @diffable
241
257
  end
242
258
 
259
+ # @api private
260
+ def supports_block_expectations?
261
+ @supports_block_expectations
262
+ end
263
+
243
264
  # @api private
244
265
  # Used internally by +should_not+
245
266
  def does_not_match?(actual)
@@ -250,14 +271,14 @@ module RSpec
250
271
  end
251
272
 
252
273
  def respond_to?(method, include_private=false)
253
- super || matcher_execution_context.respond_to?(method, include_private)
274
+ super || @matcher_execution_context.respond_to?(method, include_private)
254
275
  end
255
276
 
256
277
  private
257
278
 
258
279
  def method_missing(method, *args, &block)
259
- if matcher_execution_context.respond_to?(method)
260
- matcher_execution_context.__send__ method, *args, &block
280
+ if @matcher_execution_context.respond_to?(method)
281
+ @matcher_execution_context.__send__ method, *args, &block
261
282
  else
262
283
  super(method, *args, &block)
263
284
  end
@@ -334,15 +355,15 @@ module RSpec
334
355
  end
335
356
 
336
357
  def default_description
337
- "#{name_to_sentence}#{expected_to_sentence}"
358
+ "#{name_to_sentence}#{to_sentence expected_as_array}"
338
359
  end
339
360
 
340
361
  def default_failure_message_for_should
341
- "expected #{actual.inspect} to #{name_to_sentence}#{expected_to_sentence}"
362
+ "expected #{actual.inspect} to #{name_to_sentence}#{to_sentence expected_as_array}"
342
363
  end
343
364
 
344
365
  def default_failure_message_for_should_not
345
- "expected #{actual.inspect} not to #{name_to_sentence}#{expected_to_sentence}"
366
+ "expected #{actual.inspect} not to #{name_to_sentence}#{to_sentence expected_as_array}"
346
367
  end
347
368
 
348
369
  unless method_defined?(:singleton_class)