shoulda-matchers 2.2.0 → 2.3.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 (35) hide show
  1. data/.travis.yml +3 -0
  2. data/Gemfile.lock +1 -1
  3. data/NEWS.md +25 -1
  4. data/README.md +1 -2
  5. data/gemfiles/3.0.gemfile.lock +1 -1
  6. data/gemfiles/3.1.gemfile.lock +1 -1
  7. data/gemfiles/3.2.gemfile.lock +1 -1
  8. data/lib/shoulda/matchers/action_controller.rb +1 -0
  9. data/lib/shoulda/matchers/action_controller/rescue_from_matcher.rb +81 -0
  10. data/lib/shoulda/matchers/active_model/comparison_matcher.rb +1 -1
  11. data/lib/shoulda/matchers/active_model/disallow_value_matcher.rb +5 -0
  12. data/lib/shoulda/matchers/active_model/ensure_inclusion_of_matcher.rb +15 -1
  13. data/lib/shoulda/matchers/active_model/validate_acceptance_of_matcher.rb +1 -1
  14. data/lib/shoulda/matchers/active_model/validate_numericality_of_matcher.rb +1 -1
  15. data/lib/shoulda/matchers/active_model/validate_uniqueness_of_matcher.rb +2 -8
  16. data/lib/shoulda/matchers/active_model/validation_matcher.rb +2 -0
  17. data/lib/shoulda/matchers/active_record.rb +5 -0
  18. data/lib/shoulda/matchers/active_record/association_matcher.rb +90 -113
  19. data/lib/shoulda/matchers/active_record/association_matchers/counter_cache_matcher.rb +35 -0
  20. data/lib/shoulda/matchers/active_record/association_matchers/dependent_matcher.rb +35 -0
  21. data/lib/shoulda/matchers/active_record/association_matchers/model_reflector.rb +37 -0
  22. data/lib/shoulda/matchers/active_record/association_matchers/order_matcher.rb +35 -0
  23. data/lib/shoulda/matchers/active_record/association_matchers/through_matcher.rb +57 -0
  24. data/lib/shoulda/matchers/version.rb +1 -1
  25. data/spec/shoulda/matchers/action_controller/rescue_from_matcher_spec.rb +63 -0
  26. data/spec/shoulda/matchers/active_model/allow_value_matcher_spec.rb +1 -1
  27. data/spec/shoulda/matchers/active_model/comparison_matcher_spec.rb +5 -0
  28. data/spec/shoulda/matchers/active_model/disallow_value_matcher_spec.rb +18 -0
  29. data/spec/shoulda/matchers/active_model/ensure_inclusion_of_matcher_spec.rb +10 -0
  30. data/spec/shoulda/matchers/active_model/ensure_length_of_matcher_spec.rb +3 -3
  31. data/spec/shoulda/matchers/active_model/validate_numericality_of_matcher_spec.rb +13 -0
  32. data/spec/shoulda/matchers/active_model/validate_presence_of_matcher_spec.rb +14 -0
  33. data/spec/shoulda/matchers/active_model/validate_uniqueness_of_matcher_spec.rb +49 -1
  34. data/spec/shoulda/matchers/active_record/association_matcher_spec.rb +39 -4
  35. metadata +11 -3
data/.travis.yml CHANGED
@@ -1,5 +1,8 @@
1
1
  script: "bundle exec rake spec cucumber"
2
2
 
3
+ install:
4
+ "bundle install"
5
+
3
6
  rvm:
4
7
  - 1.9.2
5
8
  - 1.9.3
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- shoulda-matchers (2.2.0)
4
+ shoulda-matchers (2.3.0)
5
5
  activesupport (>= 3.0.0)
6
6
 
7
7
  GEM
data/NEWS.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # HEAD
2
2
 
3
+ # v 2.3.0
4
+
5
+ * Fix a bug in `ensure_inclusion_of` that would cause issues with using
6
+ `in_array` with an integer value.
7
+
8
+ * Add support for PostgreSQL UUID columns to `validates_uniqueness_of` (#334).
9
+
10
+ * Fix `validates_numericality_of` so that `is_equal_to` submatcher works
11
+ correctly (#326).
12
+
13
+ * Fix context support for validation matchers and disallowed values (#313).
14
+
15
+ * Add a `counter_cache` submatcher for `belongs_to` associations (#311).
16
+
17
+ * Add a `rescue_from` matcher for Rails controllers which checks that the
18
+ correct ActiveSupport call has been made and that the handlers exist without
19
+ actually throwing an exception (#287).
20
+
21
+ * Changed the scope of AssociationMatcher methods from protected to private.
22
+
23
+ * Extracted `#order`, `#through`, and `#dependent` from AssociationMatcher as
24
+ their own submatchers.
25
+
3
26
  # v 2.2.0
4
27
 
5
28
  * Fix `have_and_belong_to_many` matcher issue for Rails 4.
@@ -15,7 +38,8 @@
15
38
  * Add missing `failure_message_for_should_not` implementations to
16
39
  `validate_numericality_of` and its submatchers
17
40
 
18
- * Support validation contexts for testing validations `on: :create` and when using custom contexts like `model.valid?(:my_context)`.
41
+ * Support validation contexts for testing validations `on: :create` and when
42
+ using custom contexts like `model.valid?(:my_context)`.
19
43
 
20
44
  * Fix a bug in validations with autosaved models.
21
45
 
data/README.md CHANGED
@@ -51,8 +51,6 @@ Matchers to test common patterns:
51
51
 
52
52
  ```ruby
53
53
  describe PostsController, "#show" do
54
- it { should permit(:title, :body).for(:create) }
55
-
56
54
  context "for a fictional user" do
57
55
  before do
58
56
  get :show, :id => 1
@@ -61,6 +59,7 @@ describe PostsController, "#show" do
61
59
  it { should respond_with(:success) }
62
60
  it { should render_template(:show) }
63
61
  it { should_not set_the_flash }
62
+ it { should rescue_from(ActiveRecord::RecordNotFound).with(:render_404) }
64
63
  end
65
64
  end
66
65
  ```
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- shoulda-matchers (2.2.0)
4
+ shoulda-matchers (2.3.0)
5
5
  activesupport (>= 3.0.0)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- shoulda-matchers (2.2.0)
4
+ shoulda-matchers (2.3.0)
5
5
  activesupport (>= 3.0.0)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- shoulda-matchers (2.2.0)
4
+ shoulda-matchers (2.3.0)
5
5
  activesupport (>= 3.0.0)
6
6
 
7
7
  GEM
@@ -6,6 +6,7 @@ require 'shoulda/matchers/action_controller/set_session_matcher'
6
6
  require 'shoulda/matchers/action_controller/route_matcher'
7
7
  require 'shoulda/matchers/action_controller/redirect_to_matcher'
8
8
  require 'shoulda/matchers/action_controller/render_template_matcher'
9
+ require 'shoulda/matchers/action_controller/rescue_from_matcher'
9
10
 
10
11
  module Shoulda
11
12
  module Matchers
@@ -0,0 +1,81 @@
1
+ module Shoulda
2
+ module Matchers
3
+ module ActionController
4
+ def rescue_from(exception)
5
+ RescueFromMatcher.new exception
6
+ end
7
+
8
+ class RescueFromMatcher
9
+ def initialize(exception)
10
+ @exception = exception
11
+ end
12
+
13
+ def with(method)
14
+ @expected_method = method
15
+ self
16
+ end
17
+
18
+ def matches?(controller)
19
+ @controller = controller
20
+ rescues_from_exception? && method_name_matches? && handler_exists?
21
+ end
22
+
23
+ def description
24
+ description = "rescues from #{exception}"
25
+ description << " with ##{expected_method}" if expected_method
26
+ description
27
+ end
28
+
29
+ def failure_message_for_should
30
+ "Expected #{expectation}"
31
+ end
32
+
33
+ def failure_message_for_should_not
34
+ "Did not expect #{expectation}"
35
+ end
36
+
37
+ private
38
+
39
+ attr_reader :controller, :exception, :expected_method, :handlers
40
+
41
+ def expectation
42
+ expectation = "#{controller} to rescue from #{exception}"
43
+
44
+ if expected_method && !method_name_matches?
45
+ expectation << " with ##{expected_method}"
46
+ end
47
+
48
+ unless handler_exists?
49
+ expectation << " but #{controller} does not respond to #{expected_method}"
50
+ end
51
+ expectation
52
+ end
53
+
54
+ def rescues_from_exception?
55
+ @handlers = controller.rescue_handlers.select do |handler|
56
+ handler.first == exception.to_s
57
+ end
58
+ handlers.any?
59
+ end
60
+
61
+ def method_name_matches?
62
+ if expected_method.present?
63
+ handlers.any? do |handler|
64
+ handler.last == expected_method
65
+ end
66
+ else
67
+ true
68
+ end
69
+ end
70
+
71
+ def handler_exists?
72
+ if expected_method.present?
73
+ controller.respond_to? expected_method
74
+ else
75
+ true
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -31,7 +31,7 @@ module Shoulda # :nodoc:
31
31
  case @operator
32
32
  when :> then [@value, @value - 1].sample
33
33
  when :>= then @value - 1
34
- when :== then @value
34
+ when :== then @value + 1
35
35
  when :< then [@value, @value + 1].sample
36
36
  when :<= then @value + 1
37
37
  end
@@ -15,6 +15,11 @@ module Shoulda # :nodoc:
15
15
  self
16
16
  end
17
17
 
18
+ def on(context)
19
+ @allow_matcher.on(context)
20
+ self
21
+ end
22
+
18
23
  def with_message(message)
19
24
  @allow_matcher.with_message(message)
20
25
  self
@@ -23,6 +23,7 @@ module Shoulda # :nodoc:
23
23
 
24
24
  class EnsureInclusionOfMatcher < ValidationMatcher # :nodoc:
25
25
  ARBITRARY_OUTSIDE_STRING = 'shouldamatchersteststring'
26
+ ARBITRARY_OUTSIDE_FIXNUM = 123456789
26
27
 
27
28
  def initialize(attribute)
28
29
  super(attribute)
@@ -144,8 +145,21 @@ module Shoulda # :nodoc:
144
145
  end
145
146
 
146
147
  def value_outside_of_array
147
- if @array.include?(ARBITRARY_OUTSIDE_STRING)
148
+ if @array.include?(outside_value)
148
149
  raise CouldNotDetermineValueOutsideOfArray
150
+ else
151
+ outside_value
152
+ end
153
+ end
154
+
155
+ def outside_value
156
+ @outside_value ||= find_outside_value
157
+ end
158
+
159
+ def find_outside_value
160
+ case @subject.send(@attribute.to_s)
161
+ when Fixnum
162
+ ARBITRARY_OUTSIDE_FIXNUM
149
163
  else
150
164
  ARBITRARY_OUTSIDE_STRING
151
165
  end
@@ -2,7 +2,7 @@ module Shoulda # :nodoc:
2
2
  module Matchers
3
3
  module ActiveModel # :nodoc:
4
4
 
5
- # Ensures that the model cannot be saved the given attribute is not
5
+ # Ensures that the model cannot be saved if the given attribute is not
6
6
  # accepted.
7
7
  #
8
8
  # Options:
@@ -122,7 +122,7 @@ module Shoulda # :nodoc:
122
122
  end
123
123
 
124
124
  def failing_submatchers
125
- @failing_submatchers ||= @submatchers.select { |matcher| !matcher.matches?(@subject.dup) }
125
+ @failing_submatchers ||= @submatchers.select { |matcher| !matcher.matches?(@subject) }
126
126
  end
127
127
 
128
128
  def allowed_types
@@ -77,14 +77,6 @@ module Shoulda # :nodoc:
77
77
  allows_nil?
78
78
  end
79
79
 
80
- def description
81
- result = 'require '
82
- result << 'case sensitive ' unless @options[:case_insensitive]
83
- result << "unique value for #{@attribute}"
84
- result << " scoped to #{@options[:scopes].join(', ')}" if @options[:scopes].present?
85
- result
86
- end
87
-
88
80
  private
89
81
 
90
82
  def allows_nil?
@@ -197,6 +189,8 @@ module Shoulda # :nodoc:
197
189
  '0'
198
190
  elsif column.type == :datetime
199
191
  DateTime.now
192
+ elsif column.type == :uuid
193
+ SecureRandom.uuid
200
194
  else
201
195
  0
202
196
  end
@@ -58,6 +58,7 @@ module Shoulda # :nodoc:
58
58
  matcher = AllowValueMatcher.
59
59
  new(value).
60
60
  for(@attribute).
61
+ on(@context).
61
62
  with_message(message)
62
63
 
63
64
  if strict?
@@ -71,6 +72,7 @@ module Shoulda # :nodoc:
71
72
  matcher = DisallowValueMatcher.
72
73
  new(value).
73
74
  for(@attribute).
75
+ on(@context).
74
76
  with_message(message)
75
77
 
76
78
  if strict?
@@ -1,4 +1,9 @@
1
1
  require 'shoulda/matchers/active_record/association_matcher'
2
+ require 'shoulda/matchers/active_record/association_matchers/counter_cache_matcher'
3
+ require 'shoulda/matchers/active_record/association_matchers/order_matcher'
4
+ require 'shoulda/matchers/active_record/association_matchers/through_matcher'
5
+ require 'shoulda/matchers/active_record/association_matchers/dependent_matcher'
6
+ require 'shoulda/matchers/active_record/association_matchers/model_reflector'
2
7
  require 'shoulda/matchers/active_record/have_db_column_matcher'
3
8
  require 'shoulda/matchers/active_record/have_db_index_matcher'
4
9
  require 'shoulda/matchers/active_record/have_readonly_attribute_matcher'
@@ -76,20 +76,31 @@ module Shoulda # :nodoc:
76
76
  @macro = macro
77
77
  @name = name
78
78
  @options = {}
79
+ @submatchers = []
80
+ @missing = ''
79
81
  end
80
82
 
81
83
  def through(through)
82
- @options[:through] = through
84
+ through_matcher = AssociationMatchers::ThroughMatcher.new(through, name)
85
+ add_submatcher(through_matcher)
83
86
  self
84
87
  end
85
88
 
86
89
  def dependent(dependent)
87
- @options[:dependent] = dependent
90
+ dependent_matcher = AssociationMatchers::DependentMatcher.new(dependent, name)
91
+ add_submatcher(dependent_matcher)
88
92
  self
89
93
  end
90
94
 
91
95
  def order(order)
92
- @options[:order] = order
96
+ order_matcher = AssociationMatchers::OrderMatcher.new(order, name)
97
+ add_submatcher(order_matcher)
98
+ self
99
+ end
100
+
101
+ def counter_cache(counter_cache = true)
102
+ counter_cache_matcher = AssociationMatchers::CounterCacheMatcher.new(counter_cache, name)
103
+ add_submatcher(counter_cache_matcher)
93
104
  self
94
105
  end
95
106
 
@@ -118,51 +129,83 @@ module Shoulda # :nodoc:
118
129
  self
119
130
  end
120
131
 
132
+ def description
133
+ description = "#{macro_description} #{name}"
134
+ description += " class_name => #{options[:class_name]}" if options.key?(:class_name)
135
+ [description, submatchers.map(&:description)].flatten.join(' ')
136
+ end
137
+
138
+ def failure_message_for_should
139
+ "Expected #{expectation} (#{missing_options})"
140
+ end
141
+
142
+ def failure_message_for_should_not
143
+ "Did not expect #{expectation}"
144
+ end
145
+
121
146
  def matches?(subject)
122
147
  @subject = subject
123
148
  association_exists? &&
124
149
  macro_correct? &&
125
150
  foreign_key_exists? &&
126
- through_association_valid? &&
127
- dependent_correct? &&
128
151
  class_name_correct? &&
129
- order_correct? &&
130
152
  conditions_correct? &&
131
153
  join_table_exists? &&
132
154
  validate_correct? &&
133
- touch_correct?
155
+ touch_correct? &&
156
+ submatchers_match?
134
157
  end
135
158
 
136
- def failure_message_for_should
137
- "Expected #{expectation} (#{@missing})"
159
+ private
160
+
161
+ attr_reader :submatchers, :missing, :subject, :macro, :name, :options
162
+
163
+ def add_submatcher(matcher)
164
+ @submatchers << matcher
138
165
  end
139
166
 
140
- def failure_message_for_should_not
141
- "Did not expect #{expectation}"
167
+ def macro_description
168
+ case macro.to_s
169
+ when 'belongs_to'
170
+ 'belong to'
171
+ when 'has_many'
172
+ 'have many'
173
+ when 'has_one'
174
+ 'have one'
175
+ when 'has_and_belongs_to_many'
176
+ 'have and belong to many'
177
+ end
142
178
  end
143
179
 
144
- def description
145
- description = "#{macro_description} #{@name}"
146
- description += " through #{@options[:through]}" if @options.key?(:through)
147
- description += " dependent => #{@options[:dependent]}" if @options.key?(:dependent)
148
- description += " class_name => #{@options[:class_name]}" if @options.key?(:class_name)
149
- description += " order => #{@options[:order]}" if @options.key?(:order)
150
- description
180
+ def expectation
181
+ "#{model_class.name} to have a #{macro} association called #{name}"
182
+ end
183
+
184
+ def missing_options
185
+ [missing, failing_submatchers.map(&:missing_option)].flatten.join
151
186
  end
152
187
 
153
- protected
188
+ def failing_submatchers
189
+ @failing_submatchers ||= submatchers.select do |matcher|
190
+ !matcher.matches?(subject)
191
+ end
192
+ end
154
193
 
155
194
  def association_exists?
156
195
  if reflection.nil?
157
- @missing = "no association called #{@name}"
196
+ @missing = "no association called #{name}"
158
197
  false
159
198
  else
160
199
  true
161
200
  end
162
201
  end
163
202
 
203
+ def reflection
204
+ @reflection ||= model_class.reflect_on_association(name)
205
+ end
206
+
164
207
  def macro_correct?
165
- if reflection.macro == @macro
208
+ if reflection.macro == macro
166
209
  true
167
210
  else
168
211
  @missing = "actual association type was #{reflection.macro}"
@@ -175,66 +218,33 @@ module Shoulda # :nodoc:
175
218
  end
176
219
 
177
220
  def belongs_foreign_key_missing?
178
- @macro == :belongs_to && !class_has_foreign_key?(model_class)
221
+ macro == :belongs_to && !class_has_foreign_key?(model_class)
222
+ end
223
+
224
+ def model_class
225
+ subject.class
179
226
  end
180
227
 
181
228
  def has_foreign_key_missing?
182
- [:has_many, :has_one].include?(@macro) &&
229
+ [:has_many, :has_one].include?(macro) &&
183
230
  !through? &&
184
231
  !class_has_foreign_key?(associated_class)
185
232
  end
186
233
 
187
- def through_association_valid?
188
- @options[:through].nil? || (through_association_exists? && through_association_correct?)
189
- end
190
-
191
- def through_association_exists?
192
- if through_reflection.nil?
193
- @missing = "#{model_class.name} does not have any relationship to #{@options[:through]}"
194
- false
195
- else
196
- true
197
- end
198
- end
199
-
200
- def through_association_correct?
201
- if @options[:through] == reflection.options[:through]
202
- true
203
- else
204
- @missing = "Expected #{model_class.name} to have #{@name} through #{@options[:through]}, " +
205
- "but got it through #{reflection.options[:through]}"
206
- false
207
- end
234
+ def through?
235
+ reflection.options[:through]
208
236
  end
209
237
 
210
- def dependent_correct?
211
- if @options[:dependent].nil? || @options[:dependent].to_s == reflection.options[:dependent].to_s
212
- true
213
- else
214
- @missing = "#{@name} should have #{@options[:dependent]} dependency"
215
- false
216
- end
238
+ def associated_class
239
+ reflection.klass
217
240
  end
218
241
 
219
242
  def class_name_correct?
220
- if @options.key?(:class_name)
221
- if @options[:class_name].to_s == reflection.klass.to_s
243
+ if options.key?(:class_name)
244
+ if options[:class_name].to_s == reflection.klass.to_s
222
245
  true
223
246
  else
224
- @missing = "#{@name} should resolve to #{@options[:class_name]} for class_name"
225
- false
226
- end
227
- else
228
- true
229
- end
230
- end
231
-
232
- def order_correct?
233
- if @options.key?(:order)
234
- if @options[:order].to_s == reflection.options[:order].to_s
235
- true
236
- else
237
- @missing = "#{@name} should be ordered by #{@options[:order]}"
247
+ @missing = "#{name} should resolve to #{options[:class_name]} for class_name"
238
248
  false
239
249
  end
240
250
  else
@@ -243,11 +253,11 @@ module Shoulda # :nodoc:
243
253
  end
244
254
 
245
255
  def conditions_correct?
246
- if @options.key?(:conditions)
247
- if @options[:conditions].to_s == reflection.options[:conditions].to_s
256
+ if options.key?(:conditions)
257
+ if options[:conditions].to_s == reflection.options[:conditions].to_s
248
258
  true
249
259
  else
250
- @missing = "#{@name} should have the following conditions: #{@options[:conditions]}"
260
+ @missing = "#{name} should have the following conditions: #{options[:conditions]}"
251
261
  false
252
262
  end
253
263
  else
@@ -256,7 +266,7 @@ module Shoulda # :nodoc:
256
266
  end
257
267
 
258
268
  def join_table_exists?
259
- if @macro != :has_and_belongs_to_many ||
269
+ if macro != :has_and_belongs_to_many ||
260
270
  model_class.connection.tables.include?(join_table)
261
271
  true
262
272
  else
@@ -269,7 +279,7 @@ module Shoulda # :nodoc:
269
279
  if option_correct?(:validate)
270
280
  true
271
281
  else
272
- @missing = "#{@name} should have :validate => #{@options[:validate]}"
282
+ @missing = "#{name} should have :validate => #{options[:validate]}"
273
283
  false
274
284
  end
275
285
  end
@@ -278,22 +288,22 @@ module Shoulda # :nodoc:
278
288
  if option_correct?(:touch)
279
289
  true
280
290
  else
281
- @missing = "#{@name} should have :touch => #{@options[:touch]}"
291
+ @missing = "#{name} should have :touch => #{options[:touch]}"
282
292
  false
283
293
  end
284
294
  end
285
295
 
286
296
  def option_correct?(key)
287
- !@options.key?(key) || reflection_set_properly_for?(key)
297
+ !options.key?(key) || reflection_set_properly_for?(key)
288
298
  end
289
299
 
290
300
  def reflection_set_properly_for?(key)
291
- @options[key] == !!reflection.options[key]
301
+ options[key] == !!reflection.options[key]
292
302
  end
293
303
 
294
304
  def class_has_foreign_key?(klass)
295
- if @options.key?(:foreign_key)
296
- reflection.options[:foreign_key] == @options[:foreign_key]
305
+ if options.key?(:foreign_key)
306
+ reflection.options[:foreign_key] == options[:foreign_key]
297
307
  else
298
308
  if klass.column_names.include?(foreign_key)
299
309
  true
@@ -304,10 +314,6 @@ module Shoulda # :nodoc:
304
314
  end
305
315
  end
306
316
 
307
- def model_class
308
- @subject.class
309
- end
310
-
311
317
  def join_table
312
318
  if reflection.respond_to? :join_table
313
319
  reflection.join_table.to_s
@@ -316,10 +322,6 @@ module Shoulda # :nodoc:
316
322
  end
317
323
  end
318
324
 
319
- def associated_class
320
- reflection.klass
321
- end
322
-
323
325
  def foreign_key
324
326
  if foreign_key_reflection
325
327
  if foreign_key_reflection.respond_to?(:foreign_key)
@@ -330,41 +332,16 @@ module Shoulda # :nodoc:
330
332
  end
331
333
  end
332
334
 
333
- def through?
334
- reflection.options[:through]
335
- end
336
-
337
- def reflection
338
- @reflection ||= model_class.reflect_on_association(@name)
339
- end
340
-
341
335
  def foreign_key_reflection
342
- if [:has_one, :has_many].include?(@macro) && reflection.options.include?(:inverse_of)
336
+ if [:has_one, :has_many].include?(macro) && reflection.options.include?(:inverse_of)
343
337
  associated_class.reflect_on_association(reflection.options[:inverse_of])
344
338
  else
345
339
  reflection
346
340
  end
347
341
  end
348
342
 
349
- def through_reflection
350
- @through_reflection ||= model_class.reflect_on_association(@options[:through])
351
- end
352
-
353
- def expectation
354
- "#{model_class.name} to have a #{@macro} association called #{@name}"
355
- end
356
-
357
- def macro_description
358
- case @macro.to_s
359
- when 'belongs_to'
360
- 'belong to'
361
- when 'has_many'
362
- 'have many'
363
- when 'has_one'
364
- 'have one'
365
- when 'has_and_belongs_to_many'
366
- 'have and belong to many'
367
- end
343
+ def submatchers_match?
344
+ failing_submatchers.empty?
368
345
  end
369
346
  end
370
347
  end