remarkable_activerecord 3.0.4 → 3.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/README CHANGED
@@ -4,13 +4,17 @@ Remarkable ActiveRecord is a collection of matchers to ActiveRecord. Why use
4
4
  Remarkable?
5
5
 
6
6
  * The only one with matchers for all ActiveRecord validations, with support to
7
- all options;
7
+ all options (except :on and the option :with in validates_format_of);
8
8
 
9
9
  * Matchers for all ActiveRecord associations. The only one which supports all
10
10
  these options:
11
11
 
12
- :through, :class_name, :foreign_key, :dependent, :join_table, :uniq,
13
- :readonly, :validate, :autosave, :counter_cache, :polymorphic
12
+ :through, :source, :source_type, :class_name, :foreign_key, :dependent,
13
+ :join_table, :uniq, :readonly, :validate, :autosave, :counter_cache, :polymorphic
14
+
15
+ Plus SQL options:
16
+
17
+ :select, :conditions, :include, :group, :having, :order, :limit, :offset
14
18
 
15
19
  Besides in Remarkable 3.0 matchers became much smarter. Whenever :join_table
16
20
  or :through is given as option, it checks if the given table exists. Whenever
@@ -60,14 +60,7 @@ module Remarkable
60
60
  # to be used as default.
61
61
  #
62
62
  def allow_nil?(message_key=:message) #:nodoc:
63
- valid, options = assert_good_or_bad_if_key(:allow_nil, nil, message_key)
64
-
65
- unless valid
66
- default = Remarkable.t "remarkable.active_record.allow_nil", default_i18n_options.except(:scope).merge(options)
67
- return false, options.merge(:default => default)
68
- end
69
-
70
- true
63
+ assert_good_or_bad_if_key(:allow_nil, nil, message_key)
71
64
  end
72
65
 
73
66
  # Default allow_blank? validation. It accepts the message_key which is
@@ -77,14 +70,7 @@ module Remarkable
77
70
  # to be used as default.
78
71
  #
79
72
  def allow_blank?(message_key=:message) #:nodoc:
80
- valid, options = assert_good_or_bad_if_key(:allow_blank, '', message_key)
81
-
82
- unless valid
83
- default = Remarkable.t "remarkable.active_record.allow_blank", default_i18n_options.except(:scope).merge(options)
84
- return false, options.merge(:default => default)
85
- end
86
-
87
- true
73
+ assert_good_or_bad_if_key(:allow_blank, '', message_key)
88
74
  end
89
75
 
90
76
  # Shortcut for assert_good_value.
@@ -4,15 +4,13 @@ module Remarkable
4
4
  class AssociationMatcher < Remarkable::ActiveRecord::Base #:nodoc:
5
5
  arguments :macro, :collection => :associations, :as => :association
6
6
 
7
- optionals :through, :class_name, :foreign_key, :dependent, :join_table, :as
7
+ optionals :through, :source, :source_type, :class_name, :foreign_key, :dependent, :join_table, :as
8
+ optionals :select, :conditions, :include, :group, :having, :order, :limit, :offset, :finder_sql, :counter_sql
8
9
  optionals :uniq, :readonly, :validate, :autosave, :polymorphic, :counter_cache, :default => true
9
10
 
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?,
11
+ collection_assertions :association_exists?, :macro_matches?, :through_exists?, :source_exists?,
14
12
  :join_table_exists?, :foreign_key_exists?, :polymorphic_exists?,
15
- :counter_cache_exists?
13
+ :counter_cache_exists?, :options_match?
16
14
 
17
15
  protected
18
16
 
@@ -25,16 +23,22 @@ module Remarkable
25
23
  end
26
24
 
27
25
  def through_exists?
28
- return true unless @options.key?(:through)
29
- subject_class.reflect_on_association(@options[:through])
26
+ return true unless @options.key?(:through)
27
+ reflection.through_reflection rescue false
28
+ end
29
+
30
+ def source_exists?
31
+ return true unless @options.key?(:through)
32
+ reflection.source_reflection rescue false
30
33
  end
31
34
 
32
35
  def join_table_exists?
33
- return true unless has_join_table?
34
- ::ActiveRecord::Base.connection.tables.include?(reflection_join_table)
36
+ return true unless reflection.macro == :has_and_belongs_to_many
37
+ ::ActiveRecord::Base.connection.tables.include?(reflection.options[:join_table])
35
38
  end
36
39
 
37
- def foreign_key_exists?
40
+ def foreign_key_exists?
41
+ return true unless foreign_key_table
38
42
  table_has_column?(foreign_key_table, reflection_foreign_key)
39
43
  end
40
44
 
@@ -47,18 +51,18 @@ module Remarkable
47
51
  return true unless @options[:counter_cache]
48
52
  table_has_column?(reflection.klass.table_name, reflection.counter_cache_column.to_s)
49
53
  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
54
+
55
+ def options_match?
56
+ actual_options = {}
57
+
58
+ @options.keys.each do |key|
59
+ method = :"reflection_#{key}"
60
+
61
+ @options[key] = @options[key].to_s
62
+ actual_options[key] = (respond_to?(method, true) ? send(method) : reflection.options[key]).to_s
63
+ end
64
+
65
+ return @options == actual_options, :actual => actual_options.inspect
62
66
  end
63
67
 
64
68
  private
@@ -76,27 +80,25 @@ module Remarkable
76
80
  reflection.primary_key_name.to_s
77
81
  end
78
82
 
79
- def reflection_join_table
80
- (reflection.options[:join_table] || reflection.options[:through]).to_s
81
- end
82
-
83
- def has_join_table?
84
- reflection.options.key?(:through) || reflection.macro == :has_and_belongs_to_many
85
- end
86
-
87
83
  def table_has_column?(table_name, column)
88
84
  ::ActiveRecord::Base.connection.columns(table_name, 'Remarkable column retrieval').any?{|c| c.name == column }
89
85
  end
90
86
 
87
+ # In through we don't check the foreign_key, because it's spread
88
+ # accross the through and the source reflection which should be tested
89
+ # with their own macros.
90
+ #
91
91
  # In cases a join table exists (has_and_belongs_to_many and through
92
92
  # associations), we check the foreign key in the join table.
93
93
  #
94
94
  # On belongs to, the foreign_key is in the subject class table and in
95
95
  # other cases it's on the reflection class table.
96
96
  #
97
- def foreign_key_table
98
- if has_join_table?
99
- reflection_join_table
97
+ def foreign_key_table
98
+ if reflection.options.key?(:through)
99
+ nil
100
+ elsif reflection.macro == :has_and_belongs_to_many
101
+ reflection.options[:join_table]
100
102
  elsif reflection.macro == :belongs_to
101
103
  subject_class.table_name
102
104
  else
@@ -105,7 +107,7 @@ module Remarkable
105
107
  end
106
108
 
107
109
  def interpolation_options
108
- options = { :macro => Remarkable.t(@macro, :scope => matcher_i18n_scope, :default => @macro.to_s) }
110
+ options = { :macro => Remarkable.t(@macro, :scope => matcher_i18n_scope, :default => @macro.to_s), :options => @options.inspect }
109
111
 
110
112
  if @subject && reflection
111
113
  options.merge!(
@@ -114,14 +116,10 @@ module Remarkable
114
116
  :reflection_table => reflection.klass.table_name.inspect,
115
117
  :foreign_key_table => foreign_key_table.inspect,
116
118
  :polymorphic_column => reflection_foreign_key.sub(/_id$/, '_type').inspect,
117
- :counter_cache_column => reflection.counter_cache_column.to_s.inspect
119
+ :counter_cache_column => reflection.counter_cache_column.to_s.inspect,
120
+ :join_table => reflection.options[:join_table].inspect,
121
+ :foreign_key => reflection_foreign_key.inspect
118
122
  ) 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
123
  end
126
124
 
127
125
  options
@@ -143,6 +141,9 @@ module Remarkable
143
141
  # It also checks if the column actually exists in the table.
144
142
  # * <tt>:polymorphic</tt> - if the association should be polymorphic or not.
145
143
  # When true it also checks for the association_type column in the subject table.
144
+ #
145
+ # Plus all supported sql conditions options: :select, :conditions, :order,
146
+ # :limit, :offset, :include, :group, :having.
146
147
  #
147
148
  # == Examples
148
149
  #
@@ -164,7 +165,10 @@ module Remarkable
164
165
  # * <tt>:uniq</tt> - checks wether uniq is true or false.
165
166
  # * <tt>:readonly</tt> - checks wether readonly is true or false.
166
167
  # * <tt>:validate</tt> - checks wether validate is true or false.
167
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
168
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
169
+ #
170
+ # Plus all supported sql conditions options: :select, :conditions, :order,
171
+ # :limit, :offset, :include, :group, :having.
168
172
  #
169
173
  # == Examples
170
174
  #
@@ -183,14 +187,19 @@ module Remarkable
183
187
  #
184
188
  # * <tt>:class_name</tt> - the expected associted class name.
185
189
  # * <tt>:through</tt> - the expected join model which to perform the query.
186
- # It also checks if the through table exists.
190
+ # It also checks if the through table exists.
191
+ # * <tt>:source</tt> - the source of the through association.
192
+ # * <tt>:source_type</tt> - the source type of the through association.
187
193
  # * <tt>:foreign_key</tt> - the expected foreign key in the associated table.
188
194
  # When used with :through, it will check for the foreign key in the join table.
189
195
  # * <tt>:dependent</tt> - the expected dependent value for the association.
190
196
  # * <tt>:uniq</tt> - checks wether uniq is true or false.
191
197
  # * <tt>:readonly</tt> - checks wether readonly is true or false.
192
198
  # * <tt>:validate</tt> - checks wether validate is true or false.
193
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
199
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
200
+ #
201
+ # Plus all supported sql conditions options: :select, :conditions, :order,
202
+ # :limit, :offset, :include, :group, :having.
194
203
  #
195
204
  # == Examples
196
205
  #
@@ -214,12 +223,17 @@ module Remarkable
214
223
  #
215
224
  # * <tt>:class_name</tt> - the expected associted class name.
216
225
  # * <tt>:through</tt> - the expected join model which to perform the query.
217
- # It also checks if the through table exists.
226
+ # It also checks if the through table exists.
227
+ # * <tt>:source</tt> - the source of the through association.
228
+ # * <tt>:source_type</tt> - the source type of the through association.
218
229
  # * <tt>:foreign_key</tt> - the expected foreign key in the associated table.
219
230
  # When used with :through, it will check for the foreign key in the join table.
220
231
  # * <tt>:dependent</tt> - the expected dependent value for the association.
221
232
  # * <tt>:validate</tt> - checks wether validate is true or false.
222
- # * <tt>:autosave</tt> - checks wether autosave is true or false.
233
+ # * <tt>:autosave</tt> - checks wether autosave is true or false.
234
+ #
235
+ # Plus all supported sql conditions options: :select, :conditions, :order,
236
+ # :limit, :offset, :include, :group, :having.
223
237
  #
224
238
  # == Examples
225
239
  #
data/locale/en.yml CHANGED
@@ -1,20 +1,21 @@
1
1
  en:
2
2
  remarkable:
3
- active_record:
4
- allow_nil: "{{subject_name}} to {{not}}allow nil values for {{attribute}}"
5
- allow_blank: "{{subject_name}} to {{not}}allow blank values for {{attribute}}"
3
+ active_record:
4
+ expectations:
5
+ allow_nil: "{{subject_name}} to {{not}}allow nil values for {{attribute}}"
6
+ allow_blank: "{{subject_name}} to {{not}}allow blank values for {{attribute}}"
7
+ optionals:
8
+ allow_nil:
9
+ positive: "allowing nil values"
10
+ negative: "not allowing nil values"
11
+ allow_blank:
12
+ positive: "allowing blank values"
13
+ negative: "not allowing blank values"
6
14
 
7
15
  allow_values_for:
8
16
  description: "allow {{in}} as values for {{attributes}}"
9
17
  expectations:
10
18
  is_valid: "{{subject_name}} to be valid when {{attribute}} is set to {{value}}"
11
- optionals:
12
- allow_nil:
13
- positive: "allowing nil values"
14
- negative: "not allowing nil values"
15
- allow_blank:
16
- positive: "allowing blank values"
17
- negative: "not allowing blank values"
18
19
 
19
20
  allow_mass_assignment_of:
20
21
  description: "allow mass assignment of {{attributes}}"
@@ -31,26 +32,20 @@ en:
31
32
  expectations:
32
33
  association_exists: "{{subject_name}} records {{macro}} {{association}}, got no association"
33
34
  macro_matches: "{{subject_name}} records {{macro}} {{association}}, got {{subject_name}} records {{actual_macro}} {{association}}"
34
- through_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, through association does not exist"
35
- join_table_exists: "join table {{actual_join_table}} to exist, but does not"
36
- foreign_key_exists: "foreign key {{actual_foreign_key}} to exist on {{foreign_key_table}}, but does not"
35
+ through_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, through association does not exist"
36
+ source_exists: "{{subject_name}} records {{macro}} {{association}} through {{through}}, source association does not exist"
37
+ join_table_exists: "join table {{join_table}} to exist, but does not"
38
+ foreign_key_exists: "foreign key {{foreign_key}} to exist on {{foreign_key_table}}, but does not"
37
39
  polymorphic_exists: "{{subject_table}} to have {{polymorphic_column}} as column, but does not"
38
- counter_cache_exists: "{{reflection_table}} to have {{counter_cache_column}} as column, but does not"
39
- through_matches: "{{association}} association through {{through}}, got {{actual_through}}"
40
- class_name_matches: "{{association}} association with class name {{class_name}}, got {{actual_class_name}}"
41
- foreign_key_matches: "{{association}} association with foreign key {{foreign_key}}, got {{actual_foreign_key}}"
42
- dependent_matches: "{{association}} association with dependent {{dependent}}, got {{actual_dependent}}"
43
- join_table_matches: "{{association}} association with join table {{join_table}}, got {{actual_join_table}}"
44
- uniq_matches: "{{association}} association with uniq equals to {{uniq}}, got {{actual_uniq}}"
45
- readonly_matches: "{{association}} association with readonly equals to {{readonly}}, got {{actual_readonly}}"
46
- validate_matches: "{{association}} association with validate equals to {{validate}}, got {{actual_validate}}"
47
- autosave_matches: "{{association}} association with autosave equals to {{autosave}}, got {{actual_autosave}}"
48
- polymorphic_matches: "{{association}} association with polymorphic equals to {{polymorphic}}, got {{actual_polymorphic}}"
49
- as_matches: "{{association}} association with polymorphic interface {{as}}, got {{actual_as}}"
50
- counter_cache_matches: "{{association}} association with counter cache {{counter_cache}}, got {{actual_counter_cache}}"
40
+ counter_cache_exists: "{{reflection_table}} to have {{counter_cache_column}} as column, but does not"
41
+ options_match: "{{subject_name}} records {{macro}} {{association}} with options {{options}}, got {{actual}}"
51
42
  optionals:
52
43
  through:
53
- positive: "through {{value}}"
44
+ positive: "through {{value}}"
45
+ source:
46
+ positive: "with source {{inspect}}"
47
+ source_type:
48
+ positive: "with source type {{inspect}}"
54
49
  class_name:
55
50
  positive: "with class name {{inspect}}"
56
51
  foreign_key:
@@ -75,7 +70,23 @@ en:
75
70
  positive: "through the polymorphic interface {{inspect}}"
76
71
  counter_cache:
77
72
  positive: "with counter cache {{inspect}}"
78
- negative: "without counter cache"
73
+ negative: "without counter cache"
74
+ select:
75
+ positive: "selecting {{inspect}}"
76
+ conditions:
77
+ positive: "with conditions {{inspect}}"
78
+ include:
79
+ positive: "including {{inspect}}"
80
+ group:
81
+ positive: "grouping by {{inspect}}"
82
+ having:
83
+ positive: "having {{inspect}}"
84
+ order:
85
+ positive: "with order {{inspect}}"
86
+ limit:
87
+ positive: "with limit {{inspect}}"
88
+ offset:
89
+ positive: "with offset {{inspect}}"
79
90
 
80
91
  have_column:
81
92
  description: "have column(s) named {{columns}}"
@@ -126,9 +137,6 @@ en:
126
137
  optionals:
127
138
  accept:
128
139
  positive: "with value {{inspect}}"
129
- allow_nil:
130
- positive: "allowing nil values"
131
- negative: "not allowing nil values"
132
140
 
133
141
  validate_associated:
134
142
  description: "require associated {{associations}} to be valid"
@@ -146,26 +154,12 @@ en:
146
154
  expectations:
147
155
  is_valid: "{{subject_name}} to be valid when {{attribute}} is set to {{value}}"
148
156
  is_invalid: "{{subject_name}} to be invalid when {{attribute}} is set to {{value}}"
149
- optionals:
150
- allow_nil:
151
- positive: "allowing nil values"
152
- negative: "not allowing nil values"
153
- allow_blank:
154
- positive: "allowing blank values"
155
- negative: "not allowing blank values"
156
157
 
157
158
  validate_inclusion_of:
158
159
  description: "ensure inclusion of {{attributes}} in {{in}}"
159
160
  expectations:
160
161
  is_valid: "{{subject_name}} to be valid when {{attribute}} is set to {{value}}"
161
162
  is_invalid: "{{subject_name}} to be invalid when {{attribute}} is set to {{value}}"
162
- optionals:
163
- allow_nil:
164
- positive: "allowing nil values"
165
- negative: "not allowing nil values"
166
- allow_blank:
167
- positive: "allowing blank values"
168
- negative: "not allowing blank values"
169
163
 
170
164
  validate_length_of:
171
165
  description: "ensure length of {{attributes}}"
@@ -183,12 +177,6 @@ en:
183
177
  positive: "is minimum {{inspect}} characters"
184
178
  is:
185
179
  positive: "is equal to {{inspect}} characters"
186
- allow_nil:
187
- positive: "allowing nil values"
188
- negative: "not allowing nil values"
189
- allow_blank:
190
- positive: "allowing blank values"
191
- negative: "not allowing blank values"
192
180
 
193
181
  validate_numericality_of:
194
182
  description: "ensure numericality of {{attributes}}"
@@ -217,12 +205,6 @@ en:
217
205
  positive: "is less than or equal to {{inspect}}"
218
206
  greater_than_or_equal_to:
219
207
  positive: "is greater than or equal to {{inspect}}"
220
- allow_nil:
221
- positive: "allowing nil values"
222
- negative: "not allowing nil values"
223
- allow_blank:
224
- positive: "allowing blank values"
225
- negative: "not allowing blank values"
226
208
 
227
209
  validate_presence_of:
228
210
  description: "require {{attributes}} to be set"
@@ -242,10 +224,4 @@ en:
242
224
  case_sensitive:
243
225
  positive: "case sensitive"
244
226
  negative: "case insensitive"
245
- allow_nil:
246
- positive: "allowing nil values"
247
- negative: "not allowing nil values"
248
- allow_blank:
249
- positive: "allowing blank values"
250
- negative: "not allowing blank values"
251
-
227
+
@@ -75,36 +75,16 @@ describe 'association_matcher' do
75
75
  matcher.failure_message.should == 'Expected "companies" to have "projects_count" as column, but does not'
76
76
  end
77
77
 
78
- it 'should set validate_matches? message' do
79
- matcher = define_and_validate(:validate => false)
80
- matcher.validate.matches?(@model)
81
- matcher.failure_message.should == 'Expected company association with validate equals to true, got "false"'
82
- end
83
-
84
- it 'should set readonly_matches? message' do
85
- matcher = define_and_validate(:readonly => false)
86
- matcher.readonly.matches?(@model)
87
- matcher.failure_message.should == 'Expected company association with readonly equals to true, got "false"'
88
- end
89
-
90
- if RAILS_VERSION =~ /^2.3/
91
- it 'should set autosave_matches? message' do
92
- matcher = define_and_validate(:autosave => false)
93
- matcher.autosave.matches?(@model)
94
- matcher.failure_message.should == 'Expected company association with autosave equals to true, got "false"'
95
- end
96
- end
97
-
98
- it 'should set polymorphic_matches? message' do
78
+ it 'should set options_matches? message when polymorphic is given' do
99
79
  matcher = define_and_validate(:polymorphic => false)
100
80
  matcher.polymorphic.matches?(@model)
101
- matcher.failure_message.should == 'Expected company association with polymorphic equals to true, got "false"'
81
+ matcher.failure_message.should == 'Expected Project records belong to company with options {:polymorphic=>"true"}, got {:polymorphic=>"false"}'
102
82
  end
103
83
 
104
- it 'should set counter_cache_matches? message' do
84
+ it 'should set options_matches? message when counter_cache is given' do
105
85
  matcher = define_and_validate(:counter_cache => true)
106
86
  matcher.counter_cache(false).matches?(@model)
107
- matcher.failure_message.should == 'Expected company association with counter cache false, got "true"'
87
+ matcher.failure_message.should == 'Expected Project records belong to company with options {:counter_cache=>"false"}, got {:counter_cache=>"true"}'
108
88
  end
109
89
  end
110
90
 
@@ -244,31 +224,11 @@ describe 'association_matcher' do
244
224
  matcher.failure_message.should == 'Expected foreign key "project_id" to exist on "labels_projects", but does not'
245
225
  end
246
226
 
247
- it 'should set validate_matches? message' do
248
- matcher = define_and_validate(:validate => false)
249
- matcher.validate.matches?(@model)
250
- matcher.failure_message.should == 'Expected labels association with validate equals to true, got "false"'
251
- end
252
-
253
- it 'should set readonly_matches? message' do
254
- matcher = define_and_validate(:readonly => false)
255
- matcher.readonly.matches?(@model)
256
- matcher.failure_message.should == 'Expected labels association with readonly equals to true, got "false"'
257
- end
258
-
259
- if RAILS_VERSION =~ /^2.3/
260
- it 'should set autosave_matches? message' do
261
- matcher = define_and_validate(:autosave => false)
262
- matcher.autosave.matches?(@model)
263
- matcher.failure_message.should == 'Expected labels association with autosave equals to true, got "false"'
264
- end
265
- end
266
-
267
- it 'should set uniq_matches? message' do
227
+ it 'should set options_matches? message' do
268
228
  matcher = define_and_validate(:uniq => false)
269
229
  matcher.uniq.matches?(@model)
270
- matcher.failure_message.should == 'Expected labels association with uniq equals to true, got "false"'
271
- end
230
+ matcher.failure_message.should == 'Expected Project records have and belong to many labels with options {:uniq=>"true"}, got {:uniq=>"false"}'
231
+ end
272
232
  end
273
233
 
274
234
  describe 'matchers' do
@@ -348,17 +308,19 @@ describe 'association_matcher' do
348
308
 
349
309
  # Defines a model, create a validation and returns a raw matcher
350
310
  def define_and_validate(options={})
351
- columns = options.delete(:association_columns) || { :task_id => :integer, :project_id => :integer }
352
- define_model :task, columns
311
+ columns = options.delete(:association_columns) || { :task_id => :integer, :project_id => :integer, :todo_id => :integer }
312
+ define_model :task, columns
313
+ define_model :todo, columns
353
314
 
354
315
  define_model :project_task, columns do
355
316
  belongs_to :task
356
- belongs_to :project
357
- end unless options.delete(:skip_through)
317
+ belongs_to :project
318
+ belongs_to :todo
319
+ end unless options.delete(:skip_source)
358
320
 
359
- @model = define_model :project, options.delete(:model_columns) || {} do
321
+ @model = define_model :project, options.delete(:model_columns) || {} do
322
+ has_many :project_tasks unless options.delete(:skip_through)
360
323
  has_many :tasks, options
361
- has_many :project_tasks
362
324
  end
363
325
 
364
326
  have_many :tasks
@@ -403,15 +365,28 @@ describe 'association_matcher' do
403
365
  end
404
366
 
405
367
  it 'should set through_exists? message' do
406
- matcher = define_and_validate(:through => 'project_tasks')
407
- matcher.through(:another).matches?(@model)
408
- matcher.failure_message.should == 'Expected Project records have many tasks through :another, through association does not exist'
409
- end
410
-
411
- it 'should set join_table_exists? message' do
412
- matcher = define_and_validate(:through => 'project_tasks', :skip_through => true)
368
+ matcher = define_and_validate(:through => :project_tasks, :skip_through => true)
369
+ matcher.through(:project_tasks).matches?(@model)
370
+ matcher.failure_message.should == 'Expected Project records have many tasks through :project_tasks, through association does not exist'
371
+ end
372
+
373
+ it 'should set source_exists? message' do
374
+ matcher = define_and_validate(:through => :project_tasks, :skip_source => true)
413
375
  matcher.through(:project_tasks).matches?(@model)
414
- matcher.failure_message.should == 'Expected join table "project_tasks" to exist, but does not'
376
+ matcher.failure_message.should == 'Expected Project records have many tasks through :project_tasks, source association does not exist'
377
+ end
378
+
379
+ it 'should set options_matches? message when dependent is given' do
380
+ matcher = define_and_validate(:dependent => :destroy)
381
+ matcher.dependent(:nullify).matches?(@model)
382
+ matcher.failure_message.should == 'Expected Project records have many tasks with options {:dependent=>"nullify"}, got {:dependent=>"destroy"}'
383
+ end
384
+
385
+ it 'should set options_matches? message when source is given' do
386
+ matcher = define_and_validate(:through => :project_tasks, :source => :todo)
387
+ matcher.through(:project_tasks).source(:task).matches?(@model)
388
+ matcher.failure_message.should match(/:source=>"task"/)
389
+ matcher.failure_message.should match(/:source=>"todo"/)
415
390
  end
416
391
  end
417
392
 
@@ -456,11 +431,16 @@ describe 'association_matcher' do
456
431
  end
457
432
 
458
433
  describe 'with through option' do
459
- it { should define_and_validate(:through => 'project_tasks') }
460
- it { should define_and_validate(:through => 'project_tasks').through(:project_tasks) }
434
+ it { should define_and_validate(:through => :project_tasks) }
435
+ it { should define_and_validate(:through => :project_tasks).through(:project_tasks) }
461
436
 
462
- it { should_not define_and_validate(:through => 'project_tasks').through(:something) }
463
- it { should_not define_and_validate(:through => 'project_tasks', :skip_through => true).through(:project_tasks) }
437
+ it { should_not define_and_validate(:through => :project_tasks).through(:something) }
438
+ it { should_not define_and_validate(:through => :project_tasks, :skip_through => true).through(:project_tasks) }
439
+ end
440
+
441
+ describe 'with source option' do
442
+ it { should define_and_validate(:through => :project_tasks, :source => :todo).source(:todo) }
443
+ it { should_not define_and_validate(:through => :project_tasks, :source => :todo).source(:task) }
464
444
  end
465
445
 
466
446
  create_optional_boolean_specs(:uniq, self)
@@ -470,7 +450,7 @@ describe 'association_matcher' do
470
450
  end
471
451
 
472
452
  describe 'macros' do
473
- before(:each){ define_and_validate(:through => 'project_tasks', :readonly => true, :validate => true) }
453
+ before(:each){ define_and_validate(:through => :project_tasks, :readonly => true, :validate => true) }
474
454
 
475
455
  should_have_many :tasks
476
456
  should_have_many :tasks, :readonly => true
@@ -487,17 +467,19 @@ describe 'association_matcher' do
487
467
 
488
468
  # Defines a model, create a validation and returns a raw matcher
489
469
  def define_and_validate(options={})
490
- columns = options.delete(:association_columns) || { :manager_id => :integer, :project_id => :integer }
491
- define_model :manager, columns
470
+ columns = options.delete(:association_columns) || { :manager_id => :integer, :project_id => :integer, :boss_id => :integer }
471
+ define_model :manager, columns
472
+ define_model :boss, columns
492
473
 
493
474
  define_model :project_manager, columns do
494
475
  belongs_to :manager
495
- belongs_to :project
496
- end unless options.delete(:skip_through)
476
+ belongs_to :project
477
+ belongs_to :boss
478
+ end unless options.delete(:skip_source)
497
479
 
498
- @model = define_model :project, options.delete(:model_columns) || {} do
480
+ @model = define_model :project, options.delete(:model_columns) || {} do
481
+ has_many :project_managers unless options.delete(:skip_through)
499
482
  has_one :manager, options
500
- has_many :project_managers
501
483
  end
502
484
 
503
485
  have_one :manager
@@ -536,15 +518,28 @@ describe 'association_matcher' do
536
518
  end
537
519
 
538
520
  it 'should set through_exists? message' do
539
- matcher = define_and_validate(:through => 'project_managers')
540
- matcher.through(:another).matches?(@model)
541
- matcher.failure_message.should == 'Expected Project records have one manager through :another, through association does not exist'
542
- end
543
-
544
- it 'should set join_table_exists? message' do
545
- matcher = define_and_validate(:through => 'project_managers', :skip_through => true)
521
+ matcher = define_and_validate(:through => :project_managers, :skip_through => true)
522
+ matcher.through(:project_managers).matches?(@model)
523
+ matcher.failure_message.should == 'Expected Project records have one manager through :project_managers, through association does not exist'
524
+ end
525
+
526
+ it 'should set source_exists? message' do
527
+ matcher = define_and_validate(:through => :project_managers, :skip_source => true)
546
528
  matcher.through(:project_managers).matches?(@model)
547
- matcher.failure_message.should == 'Expected join table "project_managers" to exist, but does not'
529
+ matcher.failure_message.should == 'Expected Project records have one manager through :project_managers, source association does not exist'
530
+ end
531
+
532
+ it 'should set options_matches? message when dependent is given' do
533
+ matcher = define_and_validate(:dependent => :destroy)
534
+ matcher.dependent(:nullify).matches?(@model)
535
+ matcher.failure_message.should == 'Expected Project records have one manager with options {:dependent=>"nullify"}, got {:dependent=>"destroy"}'
536
+ end
537
+
538
+ it 'should set options_matches? message when source is given' do
539
+ matcher = define_and_validate(:through => :project_managers, :source => :boss)
540
+ matcher.through(:project_managers).source(:manager).matches?(@model)
541
+ matcher.failure_message.should match(/:source=>"manager"/)
542
+ matcher.failure_message.should match(/:source=>"boss"/)
548
543
  end
549
544
  end
550
545
 
@@ -589,11 +584,16 @@ describe 'association_matcher' do
589
584
  end
590
585
 
591
586
  describe 'with through option' do
592
- it { should define_and_validate(:through => 'project_managers') }
593
- it { should define_and_validate(:through => 'project_managers').through(:project_managers) }
587
+ it { should define_and_validate(:through => :project_managers) }
588
+ it { should define_and_validate(:through => :project_managers).through(:project_managers) }
594
589
 
595
- it { should_not define_and_validate(:through => 'project_managers').through(:something) }
596
- it { should_not define_and_validate(:through => 'project_managers', :skip_through => true).through(:project_managers) }
590
+ it { should_not define_and_validate(:through => :project_managers).through(:something) }
591
+ it { should_not define_and_validate(:through => :project_managers, :skip_through => true).through(:project_managers) }
592
+ end
593
+
594
+ describe 'with source option' do
595
+ it { should define_and_validate(:through => :project_managers, :source => :boss).source(:boss) }
596
+ it { should_not define_and_validate(:through => :project_managers, :source => :boss).source(:manager) }
597
597
  end
598
598
 
599
599
  create_optional_boolean_specs(:validate, self)
@@ -601,7 +601,7 @@ describe 'association_matcher' do
601
601
  end
602
602
 
603
603
  describe 'macros' do
604
- before(:each){ define_and_validate(:through => 'project_managers', :validate => true) }
604
+ before(:each){ define_and_validate(:through => :project_managers, :validate => true) }
605
605
 
606
606
  should_have_one :manager
607
607
  should_have_one :manager, :validate => true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remarkable_activerecord
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.4
4
+ version: 3.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carlos Brando
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2009-04-18 00:00:00 +02:00
14
+ date: 2009-04-20 00:00:00 +02:00
15
15
  default_executable:
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
@@ -22,7 +22,7 @@ dependencies:
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 3.0.4
25
+ version: 3.0.5
26
26
  version:
27
27
  description: "Remarkable ActiveRecord: collection of matchers and macros with I18n for ActiveRecord"
28
28
  email: