shoulda-matchers 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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