remarkable_activerecord 3.0.1 → 3.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/CHANGELOG +46 -46
  2. data/LICENSE +1 -1
  3. data/README +64 -64
  4. data/lib/remarkable_activerecord.rb +1 -1
  5. data/lib/remarkable_activerecord/base.rb +40 -40
  6. data/lib/remarkable_activerecord/human_names.rb +24 -24
  7. data/lib/remarkable_activerecord/matchers/allow_mass_assignment_of_matcher.rb +14 -14
  8. data/lib/remarkable_activerecord/matchers/allow_values_for_matcher.rb +70 -70
  9. data/lib/remarkable_activerecord/matchers/association_matcher.rb +197 -197
  10. data/lib/remarkable_activerecord/matchers/have_column_matcher.rb +29 -29
  11. data/lib/remarkable_activerecord/matchers/have_index_matcher.rb +20 -20
  12. data/lib/remarkable_activerecord/matchers/have_readonly_attributes_matcher.rb +7 -7
  13. data/lib/remarkable_activerecord/matchers/have_scope_matcher.rb +34 -34
  14. data/lib/remarkable_activerecord/matchers/validate_acceptance_of_matcher.rb +37 -37
  15. data/lib/remarkable_activerecord/matchers/validate_associated_matcher.rb +75 -75
  16. data/lib/remarkable_activerecord/matchers/validate_confirmation_of_matcher.rb +44 -44
  17. data/lib/remarkable_activerecord/matchers/validate_exclusion_of_matcher.rb +17 -17
  18. data/lib/remarkable_activerecord/matchers/validate_inclusion_of_matcher.rb +20 -20
  19. data/lib/remarkable_activerecord/matchers/validate_numericality_of_matcher.rb +14 -14
  20. data/lib/remarkable_activerecord/matchers/validate_uniqueness_of_matcher.rb +80 -61
  21. data/locale/en.yml +253 -253
  22. data/spec/allow_mass_assignment_of_matcher_spec.rb +50 -50
  23. data/spec/allow_values_for_matcher_spec.rb +45 -45
  24. data/spec/association_matcher_spec.rb +612 -612
  25. data/spec/have_column_matcher_spec.rb +67 -67
  26. data/spec/have_index_matcher_spec.rb +61 -61
  27. data/spec/have_readonly_attributes_matcher_spec.rb +40 -40
  28. data/spec/have_scope_matcher_spec.rb +60 -60
  29. data/spec/model_builder.rb +101 -101
  30. data/spec/spec_helper.rb +25 -25
  31. data/spec/validate_acceptance_of_matcher_spec.rb +64 -64
  32. data/spec/validate_associated_matcher_spec.rb +118 -118
  33. data/spec/validate_confirmation_of_matcher_spec.rb +54 -54
  34. data/spec/validate_exclusion_of_matcher_spec.rb +76 -76
  35. data/spec/validate_inclusion_of_matcher_spec.rb +72 -72
  36. data/spec/validate_numericality_of_matcher_spec.rb +100 -100
  37. data/spec/validate_presence_of_matcher_spec.rb +40 -40
  38. data/spec/validate_uniqueness_of_matcher_spec.rb +158 -139
  39. metadata +3 -3
@@ -1,92 +1,92 @@
1
1
  module Remarkable
2
2
  module ActiveRecord
3
- module Matchers
3
+ module Matchers
4
4
  class AllowValuesForMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
- arguments :collection => :attributes, :as => :attribute
6
-
7
- optional :message
8
- optional :in, :splat => true
5
+ arguments :collection => :attributes, :as => :attribute
6
+
7
+ optional :message
8
+ optional :in, :splat => true
9
9
  optional :allow_nil, :allow_blank, :default => true
10
-
11
- collection_assertions :is_valid?, :is_invalid?, :allow_nil?, :allow_blank?
12
-
13
- default_options :message => :invalid
14
-
15
- before_assert do
16
- first_value = @options[:in].is_a?(Array) ? @options[:in].first : @options[:in]
17
- @in_range = first_value.is_a?(Range)
18
-
19
- @options[:in] = if @in_range
20
- first_value.to_a[0,2] + first_value.to_a[-2,2]
21
- else
22
- [*@options[:in]].compact
23
- end
24
-
25
- @options[:in].uniq!
26
- end
27
-
28
- protected
29
-
30
- def is_valid?
31
- valid_values.each do |value|
32
- return false, :value => value.inspect unless good?(value)
33
- end
34
- true
35
- end
36
-
37
- def is_invalid?
38
- invalid_values.each do |value|
39
- return false, :value => value.inspect unless bad?(value)
40
- end
41
- true
42
- end
43
-
44
- def valid_values
45
- @options[:in]
46
- end
47
-
48
- def invalid_values
49
- []
50
- end
51
-
52
- def interpolation_options
53
- options = if @in_range
54
- { :in => (@options[:in].first..@options[:in].last).inspect }
55
- elsif @options[:in].is_a?(Array)
56
- { :in => @options[:in].map(&:inspect).to_sentence }
57
- else
58
- { :in => @options[:in].inspect }
59
- end
60
-
61
- options.merge!(:behavior => @behavior.to_s)
62
- end
10
+
11
+ collection_assertions :is_valid?, :is_invalid?, :allow_nil?, :allow_blank?
12
+
13
+ default_options :message => :invalid
14
+
15
+ before_assert do
16
+ first_value = @options[:in].is_a?(Array) ? @options[:in].first : @options[:in]
17
+ @in_range = first_value.is_a?(Range)
18
+
19
+ @options[:in] = if @in_range
20
+ first_value.to_a[0,2] + first_value.to_a[-2,2]
21
+ else
22
+ [*@options[:in]].compact
23
+ end
24
+
25
+ @options[:in].uniq!
26
+ end
27
+
28
+ protected
29
+
30
+ def is_valid?
31
+ valid_values.each do |value|
32
+ return false, :value => value.inspect unless good?(value)
33
+ end
34
+ true
35
+ end
36
+
37
+ def is_invalid?
38
+ invalid_values.each do |value|
39
+ return false, :value => value.inspect unless bad?(value)
40
+ end
41
+ true
42
+ end
43
+
44
+ def valid_values
45
+ @options[:in]
46
+ end
47
+
48
+ def invalid_values
49
+ []
50
+ end
51
+
52
+ def interpolation_options
53
+ options = if @in_range
54
+ { :in => (@options[:in].first..@options[:in].last).inspect }
55
+ elsif @options[:in].is_a?(Array)
56
+ { :in => @options[:in].map(&:inspect).to_sentence }
57
+ else
58
+ { :in => @options[:in].inspect }
59
+ end
60
+
61
+ options.merge!(:behavior => @behavior.to_s)
62
+ end
63
63
 
64
64
  end
65
65
 
66
66
  # Ensures that the attribute can be set to the given values.
67
67
  #
68
- # Note: this matcher accepts at once just one attribute to test.
69
- # Note: this matcher is also aliased as "validate_format_of".
70
- #
71
- # == Options
72
- #
68
+ # Note: this matcher accepts at once just one attribute to test.
69
+ # Note: this matcher is also aliased as "validate_format_of".
70
+ #
71
+ # == Options
72
+ #
73
73
  # * <tt>:allow_nil</tt> - when supplied, validates if it allows nil or not.
74
- # * <tt>:allow_blank</tt> - when supplied, validates if it allows blank or not.
75
- # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
74
+ # * <tt>:allow_blank</tt> - when supplied, validates if it allows blank or not.
75
+ # * <tt>:message</tt> - value the test expects to find in <tt>errors.on(:attribute)</tt>.
76
76
  # Regexp, string or symbol. Default = <tt>I18n.translate('activerecord.errors.messages.invalid')</tt>
77
77
  #
78
- # == Examples
79
- #
78
+ # == Examples
79
+ #
80
80
  # should_allow_values_for :isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0"
81
- # should_not_allow_values_for :isbn, "bad 1", "bad 2"
81
+ # should_not_allow_values_for :isbn, "bad 1", "bad 2"
82
82
  #
83
83
  # it { should allow_values_for(:isbn, "isbn 1 2345 6789 0", "ISBN 1-2345-6789-0") }
84
84
  # it { should_not allow_values_for(:isbn, "bad 1", "bad 2") }
85
85
  #
86
- def allow_values_for(attribute, *args)
86
+ def allow_values_for(attribute, *args)
87
87
  options = args.extract_options!
88
88
  AllowValuesForMatcher.new(attribute, options.merge!(:in => args)).spec(self)
89
- end
89
+ end
90
90
  alias :validate_format_of :allow_values_for
91
91
 
92
92
  end
@@ -1,230 +1,230 @@
1
1
  module Remarkable
2
2
  module ActiveRecord
3
3
  module Matchers
4
- class AssociationMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
- arguments :macro, :collection => :associations, :as => :association
6
-
7
- optionals :through, :class_name, :foreign_key, :dependent, :join_table, :as
8
- optionals :uniq, :readonly, :validate, :autosave, :polymorphic, :counter_cache, :default => true
9
-
10
- # Stores optionals declared above in a CONSTANT to generate assertions
11
- ASSOCIATION_OPTIONS = self.matcher_optionals
12
-
13
- collection_assertions :association_exists?, :macro_matches?, :through_exists?,
14
- :join_table_exists?, :foreign_key_exists?, :polymorphic_exists?,
15
- :counter_cache_exists?
16
-
17
- protected
18
-
19
- def association_exists?
4
+ class AssociationMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
+ arguments :macro, :collection => :associations, :as => :association
6
+
7
+ optionals :through, :class_name, :foreign_key, :dependent, :join_table, :as
8
+ optionals :uniq, :readonly, :validate, :autosave, :polymorphic, :counter_cache, :default => true
9
+
10
+ # Stores optionals declared above in a CONSTANT to generate assertions
11
+ ASSOCIATION_OPTIONS = self.matcher_optionals
12
+
13
+ collection_assertions :association_exists?, :macro_matches?, :through_exists?,
14
+ :join_table_exists?, :foreign_key_exists?, :polymorphic_exists?,
15
+ :counter_cache_exists?
16
+
17
+ protected
18
+
19
+ def association_exists?
20
20
  reflection
21
21
  end
22
22
 
23
23
  def macro_matches?
24
24
  reflection.macro == @macro
25
- end
26
-
27
- def through_exists?
28
- return true unless @options.key?(:through)
29
- subject_class.reflect_on_association(@options[:through])
30
- end
31
-
32
- def join_table_exists?
33
- return true unless has_join_table?
25
+ end
26
+
27
+ def through_exists?
28
+ return true unless @options.key?(:through)
29
+ subject_class.reflect_on_association(@options[:through])
30
+ end
31
+
32
+ def join_table_exists?
33
+ return true unless has_join_table?
34
34
  ::ActiveRecord::Base.connection.tables.include?(reflection_join_table)
35
35
  end
36
-
37
- def foreign_key_exists?
38
- table_has_column?(foreign_key_table, reflection_foreign_key)
39
- end
40
-
41
- def polymorphic_exists?
42
- return true unless @options[:polymorphic]
43
- table_has_column?(subject_class.table_name, reflection_foreign_key.sub(/_id$/, '_type'))
44
- end
45
-
46
- def counter_cache_exists?
47
- return true unless @options[:counter_cache]
36
+
37
+ def foreign_key_exists?
38
+ table_has_column?(foreign_key_table, reflection_foreign_key)
39
+ end
40
+
41
+ def polymorphic_exists?
42
+ return true unless @options[:polymorphic]
43
+ table_has_column?(subject_class.table_name, reflection_foreign_key.sub(/_id$/, '_type'))
44
+ end
45
+
46
+ def counter_cache_exists?
47
+ return true unless @options[:counter_cache]
48
48
  table_has_column?(reflection.klass.table_name, reflection.counter_cache_column.to_s)
49
- end
50
-
51
- ASSOCIATION_OPTIONS.each do |option|
52
- collection_assertion :"#{option}_matches?"
53
-
54
- class_eval <<-METHOD, __FILE__, __LINE__
55
- def #{option}_matches?
56
- return true unless @options.key?(#{option.inspect})
57
- actual_value = respond_to?(:reflection_#{option}, true) ? reflection_#{option} : reflection.options[#{option.inspect}].to_s
58
-
59
- return true if @options[#{option.inspect}].to_s == actual_value
60
- end
61
- METHOD
62
- end
63
-
64
- private
65
-
49
+ end
50
+
51
+ ASSOCIATION_OPTIONS.each do |option|
52
+ collection_assertion :"#{option}_matches?"
53
+
54
+ class_eval <<-METHOD, __FILE__, __LINE__
55
+ def #{option}_matches?
56
+ return true unless @options.key?(#{option.inspect})
57
+ actual_value = respond_to?(:reflection_#{option}, true) ? reflection_#{option} : reflection.options[#{option.inspect}].to_s
58
+
59
+ return true if @options[#{option.inspect}].to_s == actual_value
60
+ end
61
+ METHOD
62
+ end
63
+
64
+ private
65
+
66
66
  def reflection
67
67
  @reflection ||= subject_class.reflect_on_association(@association.to_sym)
68
- end
69
-
70
- # Rescue nil to avoid raising errors in invalid through associations
71
- def reflection_class_name
72
- reflection.class_name.to_s rescue nil
73
- end
74
-
68
+ end
69
+
70
+ # Rescue nil to avoid raising errors in invalid through associations
71
+ def reflection_class_name
72
+ reflection.class_name.to_s rescue nil
73
+ end
74
+
75
75
  def reflection_foreign_key
76
76
  reflection.primary_key_name.to_s
77
- end
78
-
79
- def reflection_join_table
80
- (reflection.options[:join_table] || reflection.options[:through]).to_s
81
- end
82
-
77
+ end
78
+
79
+ def reflection_join_table
80
+ (reflection.options[:join_table] || reflection.options[:through]).to_s
81
+ end
82
+
83
83
  def has_join_table?
84
84
  reflection.options.key?(:through) || reflection.macro == :has_and_belongs_to_many
85
- end
86
-
87
- def table_has_column?(table_name, column)
85
+ end
86
+
87
+ def table_has_column?(table_name, column)
88
88
  ::ActiveRecord::Base.connection.columns(table_name, 'Remarkable column retrieval').any?{|c| c.name == column }
89
- end
90
-
91
- # In cases a join table exists (has_and_belongs_to_many and through
92
- # associations), we check the foreign key in the join table.
93
- #
94
- # On belongs to, the foreign_key is in the subject class table and in
95
- # other cases it's on the reflection class table.
96
- #
97
- def foreign_key_table
98
- if has_join_table?
99
- reflection_join_table
100
- elsif reflection.macro == :belongs_to
101
- subject_class.table_name
102
- else
103
- reflection.klass.table_name
104
- end
105
- end
106
-
107
- def interpolation_options
108
- options = { :macro => Remarkable.t(@macro, :scope => matcher_i18n_scope, :default => @macro.to_s) }
109
-
110
- if @subject && reflection
111
- options.merge!(
112
- :actual_macro => Remarkable.t(reflection.macro, :scope => matcher_i18n_scope, :default => reflection.macro.to_s),
113
- :subject_table => subject_class.table_name.inspect,
114
- :reflection_table => reflection.klass.table_name.inspect,
115
- :foreign_key_table => foreign_key_table.inspect,
116
- :polymorphic_column => reflection_foreign_key.sub(/_id$/, '_type').inspect,
117
- :counter_cache_column => reflection.counter_cache_column.to_s.inspect
118
- ) rescue nil # rescue to allow specs to run properly
119
-
120
- ASSOCIATION_OPTIONS.each do |option|
121
- value_to_compare = respond_to?(:"reflection_#{option}", true) ? send(:"reflection_#{option}") : reflection.options[option].to_s
122
- options[:"actual_#{option}"] = value_to_compare.inspect
123
- end
124
-
125
- end
126
-
127
- options
89
+ end
90
+
91
+ # In cases a join table exists (has_and_belongs_to_many and through
92
+ # associations), we check the foreign key in the join table.
93
+ #
94
+ # On belongs to, the foreign_key is in the subject class table and in
95
+ # other cases it's on the reflection class table.
96
+ #
97
+ def foreign_key_table
98
+ if has_join_table?
99
+ reflection_join_table
100
+ elsif reflection.macro == :belongs_to
101
+ subject_class.table_name
102
+ else
103
+ reflection.klass.table_name
104
+ end
105
+ end
106
+
107
+ def interpolation_options
108
+ options = { :macro => Remarkable.t(@macro, :scope => matcher_i18n_scope, :default => @macro.to_s) }
109
+
110
+ if @subject && reflection
111
+ options.merge!(
112
+ :actual_macro => Remarkable.t(reflection.macro, :scope => matcher_i18n_scope, :default => reflection.macro.to_s),
113
+ :subject_table => subject_class.table_name.inspect,
114
+ :reflection_table => reflection.klass.table_name.inspect,
115
+ :foreign_key_table => foreign_key_table.inspect,
116
+ :polymorphic_column => reflection_foreign_key.sub(/_id$/, '_type').inspect,
117
+ :counter_cache_column => reflection.counter_cache_column.to_s.inspect
118
+ ) rescue nil # rescue to allow specs to run properly
119
+
120
+ ASSOCIATION_OPTIONS.each do |option|
121
+ value_to_compare = respond_to?(:"reflection_#{option}", true) ? send(:"reflection_#{option}") : reflection.options[option].to_s
122
+ options[:"actual_#{option}"] = value_to_compare.inspect
123
+ end
124
+
125
+ end
126
+
127
+ options
128
128
  end
129
129
  end
130
-
131
- # Ensure that the belongs_to relationship exists. Will also test that the
132
- # subject table has the association_id column.
133
- #
134
- # == Options
135
- #
136
- # * <tt>:class_name</tt> - the expected associted class name.
137
- # * <tt>:foreign_key</tt> - the expected foreign key in the subject table.
138
- # * <tt>:dependent</tt> - the expected dependent value for the association.
139
- # * <tt>:readonly</tt> - checks wether readonly is true or false.
140
- # * <tt>:validate</tt> - checks wether validate is true or false.
141
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
142
- # * <tt>:counter_cache</tt> - the expected dependent value for the association.
143
- # It also checks if the column actually exists in the table.
144
- # * <tt>:polymorphic</tt> - if the association should be polymorphic or not.
145
- # When true it also checks for the association_type column in the subject table.
146
- #
147
- # == Examples
148
- #
149
- # should_belong_to :parent, :polymorphic => true
150
- # it { should belong_to(:parent) }
151
- #
130
+
131
+ # Ensure that the belongs_to relationship exists. Will also test that the
132
+ # subject table has the association_id column.
133
+ #
134
+ # == Options
135
+ #
136
+ # * <tt>:class_name</tt> - the expected associted class name.
137
+ # * <tt>:foreign_key</tt> - the expected foreign key in the subject table.
138
+ # * <tt>:dependent</tt> - the expected dependent value for the association.
139
+ # * <tt>:readonly</tt> - checks wether readonly is true or false.
140
+ # * <tt>:validate</tt> - checks wether validate is true or false.
141
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
142
+ # * <tt>:counter_cache</tt> - the expected dependent value for the association.
143
+ # It also checks if the column actually exists in the table.
144
+ # * <tt>:polymorphic</tt> - if the association should be polymorphic or not.
145
+ # When true it also checks for the association_type column in the subject table.
146
+ #
147
+ # == Examples
148
+ #
149
+ # should_belong_to :parent, :polymorphic => true
150
+ # it { should belong_to(:parent) }
151
+ #
152
152
  def belong_to(*associations)
153
153
  AssociationMatcher.new(:belongs_to, *associations).spec(self)
154
154
  end
155
-
156
- # Ensures that the has_and_belongs_to_many relationship exists, if the join
157
- # table is in place and if the foreign_key column exists.
158
- #
159
- # == Options
160
- #
161
- # * <tt>:class_name</tt> - the expected associted class name.
162
- # * <tt>:join_table</tt> - the expected join table name.
163
- # * <tt>:foreign_key</tt> - the expected foreign key in the association table.
164
- # * <tt>:uniq</tt> - checks wether uniq is true or false.
165
- # * <tt>:readonly</tt> - checks wether readonly is true or false.
166
- # * <tt>:validate</tt> - checks wether validate is true or false.
167
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
168
- #
169
- # == Examples
170
- #
171
- # should_have_and_belong_to_many :posts, :cars
172
- # it{ should have_and_belong_to_many :posts, :cars }
155
+
156
+ # Ensures that the has_and_belongs_to_many relationship exists, if the join
157
+ # table is in place and if the foreign_key column exists.
158
+ #
159
+ # == Options
160
+ #
161
+ # * <tt>:class_name</tt> - the expected associted class name.
162
+ # * <tt>:join_table</tt> - the expected join table name.
163
+ # * <tt>:foreign_key</tt> - the expected foreign key in the association table.
164
+ # * <tt>:uniq</tt> - checks wether uniq is true or false.
165
+ # * <tt>:readonly</tt> - checks wether readonly is true or false.
166
+ # * <tt>:validate</tt> - checks wether validate is true or false.
167
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
168
+ #
169
+ # == Examples
170
+ #
171
+ # should_have_and_belong_to_many :posts, :cars
172
+ # it{ should have_and_belong_to_many :posts, :cars }
173
173
  #
174
174
  def have_and_belong_to_many(*associations)
175
175
  AssociationMatcher.new(:has_and_belongs_to_many, *associations).spec(self)
176
- end
177
-
178
- # Ensures that the has_many relationship exists. Will also test that the
179
- # associated table has the required columns. It works by default with
180
- # polymorphic association (:as does not have to be supplied).
181
- #
182
- # == Options
183
- #
184
- # * <tt>:class_name</tt> - the expected associted class name.
185
- # * <tt>:through</tt> - the expected join model which to perform the query.
186
- # It also checks if the through table exists.
187
- # * <tt>:foreign_key</tt> - the expected foreign key in the associated table.
188
- # When used with :through, it will check for the foreign key in the join table.
189
- # * <tt>:dependent</tt> - the expected dependent value for the association.
190
- # * <tt>:uniq</tt> - checks wether uniq is true or false.
191
- # * <tt>:readonly</tt> - checks wether readonly is true or false.
192
- # * <tt>:validate</tt> - checks wether validate is true or false.
193
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
194
- #
195
- # == Examples
196
- #
197
- # should_have_many :friends
198
- # should_have_many :enemies, :through => :friends
199
- # should_have_many :enemies, :dependent => :destroy
200
- #
201
- # it{ should have_many(:friends) }
202
- # it{ should have_many(:enemies, :through => :friends) }
203
- # it{ should have_many(:enemies, :dependent => :destroy) }
176
+ end
177
+
178
+ # Ensures that the has_many relationship exists. Will also test that the
179
+ # associated table has the required columns. It works by default with
180
+ # polymorphic association (:as does not have to be supplied).
181
+ #
182
+ # == Options
183
+ #
184
+ # * <tt>:class_name</tt> - the expected associted class name.
185
+ # * <tt>:through</tt> - the expected join model which to perform the query.
186
+ # It also checks if the through table exists.
187
+ # * <tt>:foreign_key</tt> - the expected foreign key in the associated table.
188
+ # When used with :through, it will check for the foreign key in the join table.
189
+ # * <tt>:dependent</tt> - the expected dependent value for the association.
190
+ # * <tt>:uniq</tt> - checks wether uniq is true or false.
191
+ # * <tt>:readonly</tt> - checks wether readonly is true or false.
192
+ # * <tt>:validate</tt> - checks wether validate is true or false.
193
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
194
+ #
195
+ # == Examples
196
+ #
197
+ # should_have_many :friends
198
+ # should_have_many :enemies, :through => :friends
199
+ # should_have_many :enemies, :dependent => :destroy
200
+ #
201
+ # it{ should have_many(:friends) }
202
+ # it{ should have_many(:enemies, :through => :friends) }
203
+ # it{ should have_many(:enemies, :dependent => :destroy) }
204
204
  #
205
205
  def have_many(*associations)
206
206
  AssociationMatcher.new(:has_many, *associations).spec(self)
207
207
  end
208
-
209
- # Ensures that the has_many relationship exists. Will also test that the
210
- # associated table has the required columns. It works by default with
211
- # polymorphic association (:as does not have to be supplied).
212
- #
213
- # == Options
214
- #
215
- # * <tt>:class_name</tt> - the expected associted class name.
216
- # * <tt>:through</tt> - the expected join model which to perform the query.
217
- # It also checks if the through table exists.
218
- # * <tt>:foreign_key</tt> - the expected foreign key in the associated table.
219
- # When used with :through, it will check for the foreign key in the join table.
220
- # * <tt>:dependent</tt> - the expected dependent value for the association.
221
- # * <tt>:validate</tt> - checks wether validate is true or false.
222
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
223
- #
224
- # == Examples
225
- #
226
- # should_have_one :universe
227
- # it{ should have_one(:universe) }
208
+
209
+ # Ensures that the has_many relationship exists. Will also test that the
210
+ # associated table has the required columns. It works by default with
211
+ # polymorphic association (:as does not have to be supplied).
212
+ #
213
+ # == Options
214
+ #
215
+ # * <tt>:class_name</tt> - the expected associted class name.
216
+ # * <tt>:through</tt> - the expected join model which to perform the query.
217
+ # It also checks if the through table exists.
218
+ # * <tt>:foreign_key</tt> - the expected foreign key in the associated table.
219
+ # When used with :through, it will check for the foreign key in the join table.
220
+ # * <tt>:dependent</tt> - the expected dependent value for the association.
221
+ # * <tt>:validate</tt> - checks wether validate is true or false.
222
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
223
+ #
224
+ # == Examples
225
+ #
226
+ # should_have_one :universe
227
+ # it{ should have_one(:universe) }
228
228
  #
229
229
  def have_one(*associations)
230
230
  AssociationMatcher.new(:has_one, *associations).spec(self)