rspec-expectations 2.99.0.beta2 → 2.99.0.rc1

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 (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)