joinfix 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/README +1 -1
  2. data/lib/joinfix/fixtures.rb +130 -155
  3. data/lib/joinfix/fixtures_class.rb +95 -30
  4. data/lib/joinfix.rb +108 -45
  5. data/rails/log/development.log +71 -0
  6. data/rails/log/test.log +85 -0
  7. data/rails/test/test_helper.rb +1 -0
  8. data/test/belongs_to_polymorphic_test.rb +78 -0
  9. data/test/belongs_to_test.rb +135 -44
  10. data/test/belongs_to_with_options_test.rb +57 -0
  11. data/test/has_and_belongs_to_many_test.rb +36 -36
  12. data/test/has_and_belongs_to_many_with_options_test.rb +84 -0
  13. data/test/has_many_as_test.rb +66 -0
  14. data/test/has_many_test.rb +33 -69
  15. data/test/has_many_through_test.rb +79 -0
  16. data/test/has_many_through_with_options_test.rb +85 -0
  17. data/test/has_many_with_options_test.rb +63 -0
  18. data/test/has_one_test.rb +26 -27
  19. data/test/has_one_with_options_test.rb +57 -0
  20. data/test/joinfix_test.rb +5 -5
  21. data/test/joinfix_test_helper.rb +76 -16
  22. data/test/missing_fixture_test.rb +54 -0
  23. data/test/nested_test.rb +13 -6
  24. data/test/todo +15 -0
  25. metadata +48 -51
  26. data/test/fixtures/as_children.yml +0 -0
  27. data/test/fixtures/bt_children.yml +0 -0
  28. data/test/fixtures/bt_parents.yml +0 -30
  29. data/test/fixtures/habtm_children.yml +0 -0
  30. data/test/fixtures/habtm_children_habtm_parents.yml +0 -0
  31. data/test/fixtures/habtm_joins.yml +0 -0
  32. data/test/fixtures/habtm_parents.yml +0 -18
  33. data/test/fixtures/hm_children.yml +0 -0
  34. data/test/fixtures/hm_joins.yml +0 -0
  35. data/test/fixtures/hm_parents.yml +0 -34
  36. data/test/fixtures/ho_children.yml +0 -0
  37. data/test/fixtures/ho_parents.yml +0 -14
  38. data/test/fixtures/no_join_fixes.yml +0 -4
  39. data/test/fixtures/omap_no_join_fixes.yml +0 -7
  40. data/test/fixtures/polymorphic_children.yml +0 -0
data/README CHANGED
@@ -37,7 +37,7 @@
37
37
  # groups: admin_group # => reference to the 'admin_group' entry
38
38
  #
39
39
  # jane:
40
- # id: 3 # => you can specify ids if you want
40
+ # id: 3 # => you can specify ids if you want
41
41
  # login: jane
42
42
  # groups: # => an array of joins
43
43
  # - admin_group
@@ -1,32 +1,32 @@
1
1
  class Fixtures
2
- attr_reader :join_configs, :templates
2
+ attr_reader :klass, :attributes, :templates, :fixture_path
3
3
 
4
+ alias join_fix_original_initialize initialize
5
+ def initialize(*args)
6
+ join_fix_original_initialize(*args)
7
+ @klass = Object.const_get(@class_name)
8
+
9
+ # default attributes, constructed from reflecting on the active record table
10
+ @attributes = {}
11
+ @klass.columns.each do |column|
12
+ @attributes[column.name] = column.default
13
+ end
14
+
15
+ @join_configs = {}
16
+ end
17
+
4
18
  alias join_fix_original_insert_fixtures insert_fixtures
5
19
  def insert_fixtures
6
20
  Fixtures.template_all_loaded_fixtures if templates.nil?
7
21
  join_fix_original_insert_fixtures
8
22
  end
9
-
10
- @@entry_stack = []
11
-
23
+
12
24
  def template_fixtures
13
25
  return unless templates.nil?
14
26
 
15
- begin
16
- configure
17
- rescue
18
- raise "\nError configuring fixtures for: #{@class_name}\n#{$!.message}"
19
- end
20
-
21
27
  extract_templates
22
-
23
- begin
24
- templates.each_pair do |entry_name, entry|
25
- make_entry(entry_name, entry, true)
26
- end
27
- rescue
28
- entry_str = "Entry:\n" + @@entry_stack.last.to_yaml
29
- raise "Error making entry for: '#{@class_name}'\n#{entry_str}#{$!.message}"
28
+ templates.each_pair do |entry_name, entry|
29
+ make_entry(entry_name, entry, true)
30
30
  end
31
31
  end
32
32
 
@@ -37,158 +37,62 @@ class Fixtures
37
37
  # @connection. QUERY FOR NEXT ID
38
38
  end
39
39
 
40
+ def join_config(assoc_name)
41
+ @join_configs[assoc_name] ||= JoinFix.send("configure", klass, assoc_name)
42
+ end
43
+
40
44
  def each_pair(&block)
41
45
  map { |entry_name, fixture| yield(entry_name, fixture) }
42
46
  end
43
47
 
44
- def config
45
- configure unless @config
46
- @config
48
+ def to_hash
49
+ hash = {}
50
+ each_pair do |name, fixture|
51
+ hash[name] = fixture.to_hash
52
+ end
53
+ hash
47
54
  end
48
55
 
49
56
  protected
50
57
 
51
- def configure
52
- klass = @class_name.constantize
53
- file_base = @class_name.underscore.singularize
54
-
55
- # default attributes, constructed from reflecting on the active record table
56
- attributes = {}
57
- klass.columns.each do |column|
58
- next if JoinFix.preserves?(column.name)
59
- attributes[column.name] = column.default
60
- end
61
-
62
- # default associations, constructed from reflecting on the active record class
63
- associations = {}
64
- klass.reflect_on_all_associations.each do |association|
65
- begin
66
- config = {:macro => association.macro}.merge(association.options)
67
-
68
- # get the child table name either by reflecting on the association class
69
- config[:class_name] ||= association.class_name
70
- config[:table_name] = config[:class_name].constantize.table_name unless config[:polymorphic]
71
-
72
- associations[association.name] = config
73
- rescue
74
- # known failure retrieving class name for has_many :through if the join model doesn't
75
- # have a 'belongs_to' pointing to the source model
76
- raise "Could not reflect on association: #{association.name}\n" +
77
- "Check that your join models are properly configured.\n" +
78
- $!.message
79
- end
80
- end
81
-
82
- # merge the defaults with the file configurations
83
- @config = {
84
- 'class_name' => klass.class_name,
85
- 'table_name' => klass.table_name,
86
- 'attributes' => attributes,
87
- 'associations' => associations
88
- # FUTURE! bring back if you start running methods
89
- #'modules' => [JoinFix, "#{@class_name}Template"]
90
- }.with_indifferent_access
91
-
92
- @join_configs = {}.with_indifferent_access
93
- parent_config = @config
94
- associations.each_pair do |association, child_config|
95
- # define shared parameters
96
- join_config = {
97
- :parent_table => parent_config[:table_name],
98
- :child_table => child_config[:table_name],
99
- :macro => child_config[:macro]
100
- }.with_indifferent_access
101
-
102
- case join_config[:macro].to_sym
103
- when :belongs_to
104
- if child_config[:polymorphic]
105
- join_config[:polymorphic] = true
106
- join_config[:associable] = association.to_s
107
- join_config[:foreign_key] = child_config[:foreign_key] || "#{association}_id"
108
- join_config.delete(:child_table) # not necessary, but reflects the fact that the polymorphic entry must specify this directly
109
- else
110
- join_config[:foreign_key] = child_config[:foreign_key] || "#{join_config[:child_table].singularize}_id"
111
- end
112
- when :has_one
113
- join_config[:foreign_key] = child_config[:foreign_key] || "#{join_config[:parent_table].singularize}_id"
114
- when :has_many
115
- if child_config[:as]
116
- join_config[:as] = child_config[:as]
117
- join_config[:foreign_key] = child_config[:foreign_key] || "#{child_config[:as]}_id"
118
- join_config[:parent_class] = parent_config[:class_name]
119
- elsif child_config[:through]
120
- join_config[:through] = child_config[:through]
121
- join_config[:join_table] = associations[child_config[:through]][:table_name]
122
- join_config[:foreign_key] = "#{join_config[:parent_table].singularize}_id"
123
- join_config[:association_foreign_key] = "#{join_config[:child_table].singularize}_id"
124
- else
125
- join_config[:foreign_key] = child_config[:foreign_key] || "#{join_config[:parent_table].singularize}_id"
126
- end
127
- when :has_and_belongs_to_many
128
- join_config[:join_table] = child_config[:join_table] || (join_config[:parent_table] < join_config[:child_table] ? "#{join_config[:parent_table]}_#{join_config[:child_table]}" : "#{join_config[:child_table]}_#{join_config[:parent_table]}") # echos the way join tables are guessed by ActiveRecord
129
- join_config[:foreign_key] = child_config[:foreign_key] || "#{join_config[:parent_table].singularize}_id"
130
- join_config[:association_foreign_key] = child_config[:association_foreign_key] || "#{join_config[:child_table].singularize}_id"
131
- else
132
- raise ArgumentError, "Unknown join type '#{join_config[:macro]}'."
133
- end
134
-
135
- join_config[:attributes] = Fixtures.fixture(join_config[:join_table]).config[:attributes] if join_config.has_key?(:join_table)
136
- @join_configs[association] = join_config
137
- end
138
- end
139
-
140
58
  def extract_templates
141
59
  # fixture is a template if it contains an association
142
60
  @templates = {}
143
- associations = config[:associations].keys
61
+ assoc_names = klass.reflect_on_all_associations.collect {|assoc| assoc.name.to_s}
144
62
  each do |entry_name, fixture|
145
- #next if key.to_s !~ /[=|!]$/ # FUTURE! bring back if you start running methods
146
63
  entry = fixture.to_hash
147
- next if (entry.keys & associations).empty?
64
+ next if (entry.keys & assoc_names).empty?
148
65
  @templates[entry_name] = entry
149
66
  end
150
67
  delete_if do |entry_name, fixture|
151
68
  @templates.has_key?(entry_name)
152
69
  end
153
70
  end
154
-
155
- def make_entry(entry_name, entry, add_entry_on_complete)
156
- @@entry_stack << entry.dup
71
+
72
+ def make_entry(entry_name, entry_template, add_entry_on_complete)
73
+ raise NoEntryNameError.new(self, entry_name, entry_template) unless entry_template.kind_of?(Hash)
157
74
 
158
- attributes = config[:attributes]
159
- #modules = config[:modules] # FUTURE! bring back if you start running methods
160
-
161
- entry = attributes.merge(entry)
75
+ entry = attributes.merge(entry_template)
162
76
  entry.extend JoinFix
163
77
  entry.entry_name = entry_name
164
78
 
165
- # FUTURE! bring back if you start running methods
166
- #modules.each do |module_name|
167
- # mod = get_module(module_name, module_options)
168
- # template.extend(mod) if mod
169
- #end
170
-
171
79
  # extract templates for entries that will be joined to the current entry
172
80
  # Associated entries are indicated by any key undeclared in attributes, that also does not
173
81
  # match one of the reseved key patterns... ie 'id' or keys ending in '_id'. Additionally includes
174
82
  # join references, which will all be arrays.
175
- associated_entries = entry.extract_unless(attributes.keys) do |key, value|
176
- JoinFix.preserves?(key) || key.kind_of?(Array)
83
+ assoc_entries = entry.extract_unless(attributes.keys) do |key, value|
84
+ key == "id" || key.kind_of?(Array)
177
85
  end
178
86
 
179
87
  # also extract templates for entries that have an array value. These entries indicate a set of
180
88
  # associated entries that should each be joined to the current entry
181
- associated_entries.merge( entry.extract_if { |key, value| value.kind_of?(Array) } )
182
- associated_entries.each_pair do |association, association_templates|
183
- # ensure that association_templates is an array of template
184
- association_templates = [association_templates] unless association_templates.kind_of?(Array)
89
+ assoc_entries.merge( entry.extract_if { |key, value| value.kind_of?(Array) } )
90
+ assoc_entries.each_pair do |assoc_name, assoc_array|
91
+ # ensure that assoc_array is an array of template
92
+ assoc_array = [assoc_array] unless assoc_array.kind_of?(Array)
185
93
 
186
94
  # translate the association configuration into a join configuration
187
- join_config = join_configs[association]
188
- unless join_config
189
- raise ArgumentError, "Unknown association '#{association}' for '#{table_name}'."
190
- end
191
-
95
+ join_config = join_config(assoc_name)
192
96
  join_table = join_config[:join_table]
193
97
  macro = join_config[:macro]
194
98
 
@@ -197,22 +101,25 @@ class Fixtures
197
101
  if join_config[:polymorphic] == true
198
102
  join_config = join_config.dup
199
103
 
200
- associable_type = "#{join_config[:associable]}_type"
201
- unless entry.has_key?(associable_type)
202
- raise ArgumentError, "Polymorphic type '#{associable_type}' missing in entry '#{entry_name}' for '#{table_name}'."
203
- end
204
-
104
+ associable_type = join_config[:associable_type]
205
105
  associable_class = entry[associable_type]
106
+
107
+ unless associable_class
108
+ raise MissingPolymorphicTypeError.new(self, entry_name, entry_template,
109
+ "No <#{associable_type}> was specified.")
110
+ end
111
+
206
112
  join_config[:child_class] = associable_class
207
- join_config[:child_table] = associable_class.constantize.table_name
113
+ join_config[:child_table] = Object.const_get(associable_class).table_name
208
114
  end
209
115
 
210
116
  # raise an error if the macro doesn't allow for multiple joins, but multiple associated entries are specified
211
- unless association_templates.length == 1 || JoinFix.macro_allows_multiple(macro)
212
- raise ArgumentError, "Multiple associated entries specified for the single-association macro '#{macro}' in table '#{table_name}'."
117
+ unless assoc_array.length == 1 || JoinFix.macro_allows_multiple(macro)
118
+ raise MultipleChildrenError.new(self, entry_name, entry_template,
119
+ "Multiple joined entries specified for the single-join macro '#{macro}'.")
213
120
  end
214
121
 
215
- association_templates.each do |template|
122
+ assoc_array.each do |template|
216
123
  # template is a reference to another entry
217
124
  template = {template => JoinFix.new(template)} if template.kind_of?(String)
218
125
 
@@ -229,14 +136,13 @@ class Fixtures
229
136
  # Note: join is sent through the make_entry machinery before adding... this ensures that the
230
137
  # join entry will be processed according to the wizard modules specified for the join table.
231
138
  child_fixture.add_entry(child_name, child)
232
- Fixtures.fixture(join_table).make_entry(join_name(entry_name, child_name), join, true) if join
139
+ Fixtures.fixture(join_table).make_entry(join.entry_name, join, true) if join
233
140
  end
234
141
  end
235
142
  end
236
143
 
237
144
  # add the entry if flagged and return the entry
238
145
  add_entry(entry_name, entry) if add_entry_on_complete
239
- @@entry_stack.pop
240
146
  entry
241
147
  end
242
148
 
@@ -245,27 +151,96 @@ class Fixtures
245
151
  #return unless entry.addable?
246
152
 
247
153
  # remove any attributes that are equal to their default
248
- attributes = config[:attributes]
249
154
  entry.delete_if do |attribute, value|
250
155
  default = attributes[attribute]
251
156
  value == default
252
157
  end
253
158
 
254
159
  # create a new fixture if one by the entry_name doesn't exist
255
- existing = self[entry_name] ||= Fixture.new({}, config[:class_name])
160
+ existing = self[entry_name] ||= Fixture.new({}, klass.class_name)
256
161
 
257
162
  # merge new data, checking for data collissions
258
163
  entry.each_pair do |attribute, value|
259
164
  if existing.has_key?(attribute) && existing[attribute] != value
260
- raise ArgumentError,
261
- "Data collision: #{@table_name}(:#{entry_name}).#{attribute}\n" +
262
- "<#{existing[attribute]}> is not equal to\n<#{value}>"
165
+ raise EntryCollisionError.new(self, entry_name, entry,
166
+ "<#{value}> is not equal to the existing '#{attribute}'\n<#{existing[attribute]}>")
263
167
  end
264
168
  existing[attribute] = value
265
169
  end
266
170
  end
171
+ end
172
+
173
+ class MakeEntryError < RuntimeError # :nodoc:
174
+ attr_reader :fixtures, :entry_name, :entry, :msg
175
+ attr_accessor :advice
267
176
 
268
- def join_name(entry_name, child_name)
269
- entry_name < child_name ? "#{entry_name}_#{child_name}" : "#{child_name}_#{entry_name}"
177
+ def initialize(fixtures, entry_name, entry, msg=nil)
178
+ @fixtures = fixtures
179
+ @entry_name = entry_name
180
+ @entry = entry
181
+ @msg =msg
182
+ end
183
+
184
+ def message
185
+ "Error making <#{fixtures.klass.table_name}(:#{entry_name})> in <#{fixtures.fixture_path}>.\n" +
186
+ {entry_name => entry}.to_yaml +
187
+ (msg.nil? ? '' : "\n#{msg}\n") +
188
+ (advice.nil? ? '' : "#{advice}\n")
189
+ end
190
+ end
191
+
192
+ class EntryCollisionError < MakeEntryError # :nodoc:
193
+ end
194
+
195
+ class NoEntryNameError < MakeEntryError # :nodoc:
196
+ def advice
197
+ %Q{
198
+ This error occurs when an entry is not named as in:
199
+ ---
200
+ dog:
201
+ title: Dog
202
+ author:
203
+ # <an entry name like 'ferlinghetti' is missing here>
204
+ full_name: Lawrence Ferlinghetti
205
+ ...}
206
+ end
207
+ end
208
+
209
+ class MultipleChildrenError < MakeEntryError # :nodoc:
210
+ def advice
211
+ %Q{
212
+ Single entry joins should specify a single entry, not an array of entries.
213
+ Use a different association if you need multiple joined entries.
214
+ ---
215
+ poem:
216
+ title: Slave's Dream
217
+ author:
218
+ longfellow:
219
+ full_name: Henry Wadsworth Longfellow}
220
+ end
221
+ end
222
+
223
+ class MissingPolymorphicTypeError < MakeEntryError # :nodoc:
224
+ def advice
225
+ %Q{
226
+ When specifying a belongs_to :polymorphic join, the type
227
+ of the joined entry must be specified because it cannot be
228
+ inferred from association itself. Use something like:
229
+ --
230
+ book_I_read:
231
+ opinion: Great!
232
+ readable_type: Book
233
+ readable:
234
+ the_jungle_books:
235
+ author: Rudyard Kipling
236
+ title: The Jungle Books
237
+
238
+ poem_I_read:
239
+ opinion: Essential!
240
+ readable_type: Poem
241
+ readable:
242
+ sea_fever:
243
+ poet: John Masefield
244
+ title: Sea-Fever}
270
245
  end
271
246
  end
@@ -23,25 +23,29 @@ class Fixtures
23
23
  # not yet been loaded.
24
24
  def fixture(table_name)
25
25
  fixture = all_loaded_fixtures[table_name.to_s]
26
- raise ArgumentError, "No fixture loaded for: #{table_name}" unless fixture
26
+ raise MissingFixtureError.new(table_name) unless fixture
27
27
  fixture
28
28
  end
29
29
 
30
30
  protected
31
31
 
32
+ # Sets the primary key in each of the input fixtures, beginning one-past fixtures.offset
33
+ # (generally this is 1). If a fixture already has an id assigned, it will be skipped.
32
34
  def index_fixtures(fixtures)
35
+ id = fixtures.klass.primary_key
36
+
33
37
  # first find entries with an id and record the ids so that they will be skipped
34
38
  skip_indicies = []
35
39
  fixtures.each_pair do |name, fixture|
36
- skip_indicies << fixture["id"].to_i if fixture.has_key?("id")
40
+ skip_indicies << fixture[id].to_i if fixture.has_key?(id)
37
41
  end
38
42
 
39
43
  # next find and index entries that do not have an id defined
40
44
  index = fixtures.offset
41
45
  fixtures.each_pair do |name, fixture|
42
46
  # skip entries that already have an id defined
43
- next if fixture.has_key?("id")
44
-
47
+ next if fixture.has_key?(id)
48
+
45
49
  # find the next available index
46
50
  # note this must happen before the id assignment,
47
51
  # in case index 1 is marked for skipping
@@ -50,12 +54,13 @@ class Fixtures
50
54
  break unless skip_indicies.include?(index)
51
55
  end
52
56
 
53
- fixture["id"] = index
57
+ fixture[id] = index
54
58
  end
55
59
  end
56
60
 
61
+ # Resolves each join reference in the input fixtures
57
62
  def resolve_references(fixtures)
58
- fixtures.each_pair do |name, fixture|
63
+ fixtures.each_pair do |entry_name, fixture|
59
64
  # search the fixture for join references
60
65
  fixture.each_pair do |join_ref, join_name|
61
66
  # next if the key isn't a join reference
@@ -63,35 +68,38 @@ class Fixtures
63
68
 
64
69
  foreign_key = join_ref.first
65
70
  join_table_name = join_ref.last
66
-
67
- # next if the foreign key is already defined
68
- next if fixture.has_key?(foreign_key)
69
-
70
- begin
71
- # raise an error if the join table isn't loaded; the reference cannot be resolved
72
- unless Fixtures.all_loaded_fixtures.has_key?(join_table_name)
73
- raise ArgumentError, "The join table '#{join_table_name}' has not been loaded."
74
- end
75
-
76
- join_fixtures = Fixtures.all_loaded_fixtures[join_table_name]
71
+
72
+ # raise an error if the join table isn't loaded; the reference cannot be resolved
73
+ unless Fixtures.all_loaded_fixtures.has_key?(join_table_name)
74
+ raise ResolveJoinReferenceError.new(fixtures, entry_name, join_table_name, join_name,
75
+ "The join table '#{join_table_name}' has not been loaded.")
76
+ end
77
77
 
78
- # raise an error if the join entry isn't in the join table; the reference cannot be resolved
79
- unless join_fixtures.has_key?(join_name)
80
- raise ArgumentError, "The join entry '#{join_name}' doesn't exist in '#{join_table_name}'."
81
- end
78
+ join_fixtures = Fixtures.all_loaded_fixtures[join_table_name]
79
+ id = join_fixtures.klass.primary_key
80
+
81
+ # raise an error if the join entry isn't in the join table; the reference cannot be resolved
82
+ unless join_fixtures.has_key?(join_name)
83
+ raise ResolveJoinReferenceError.new(fixtures, entry_name, join_table_name, join_name,
84
+ "The join entry '#{join_name}' doesn't exist in '#{join_table_name}'.")
85
+ end
82
86
 
83
- join_entry = join_fixtures[join_name]
87
+ join_entry = join_fixtures[join_name]
84
88
 
85
- # raise an exception if a join_id was not found
86
- unless join_entry.has_key?("id")
87
- raise ArgumentError, "No id present in join entry '#{join_name}'."
88
- end
89
- rescue
90
- raise ArgumentError, "Cannot resolve reference '#{join_reference} => #{join_name}' in '#{@table_name}.#{name}'. #{$!}"
89
+ # raise an exception if a join_id was not found
90
+ unless join_entry.has_key?(id)
91
+ raise ResolveJoinReferenceError.new(fixtures, entry_name, join_table_name, join_name,
92
+ "No #{id} present in join entry '#{join_name}'.")
93
+ end
94
+
95
+ # raise an exception if the foreign key is already set
96
+ unless fixture[foreign_key].nil?
97
+ raise ForeignKeySetError.new(fixtures, entry_name, join_table_name, join_name,
98
+ "Foreign key <#{foreign_key}> is already set!")
91
99
  end
92
-
100
+
93
101
  # set the join id
94
- fixture[foreign_key] = join_entry["id"]
102
+ fixture[foreign_key] = join_entry[id]
95
103
  end
96
104
 
97
105
  # delete the join references
@@ -100,3 +108,60 @@ class Fixtures
100
108
  end
101
109
  end
102
110
  end
111
+
112
+ class MissingFixtureError < RuntimeError # :nodoc:
113
+ attr_reader :table_name
114
+ def initialize(table_name)
115
+ @table_name = table_name
116
+ end
117
+
118
+ def message
119
+ "No fixture loaded for <#{table_name}>\n" +
120
+ (advice.nil? ? '' : "#{advice}\n")
121
+ end
122
+
123
+ def advice
124
+ %Q{}
125
+ end
126
+ end
127
+
128
+ class ResolveJoinReferenceError < RuntimeError # :nodoc:
129
+ attr_reader :fixtures, :entry_name, :join_table_name, :join_name, :msg
130
+ attr_accessor :advice
131
+
132
+ def initialize(fixtures, entry_name, join_table_name, join_name, msg=nil)
133
+ @fixtures = fixtures
134
+ @entry_name = entry_name
135
+ @join_table_name = join_table_name
136
+ @join_name = join_name
137
+ @msg =msg
138
+ end
139
+
140
+ def message
141
+ "Cannot resolve reference to <#{join_table_name}(:#{join_name})> " +
142
+ "for <#{fixtures.klass.table_name}(:#{entry_name})> " +
143
+ "in <#{fixtures.fixture_path}>.\n" +
144
+ (msg.nil? ? '' : "\n#{msg}\n") +
145
+ (advice.nil? ? '' : "#{advice}\n")
146
+ end
147
+ end
148
+
149
+ class ForeignKeySetError < ResolveJoinReferenceError # :nodoc:
150
+ def advice
151
+ %Q{
152
+ This error occurs when you specifiy the foreign key, as well as a join entry.
153
+ ---
154
+ poem:
155
+ title: Poetry of Departures
156
+ author_id: 8
157
+ author: larkin
158
+
159
+ If you need to specify the foreign key, do so within the entry.
160
+ ---
161
+ poem:
162
+ title: Poetry of Departures
163
+ author:
164
+ larkin:
165
+ id: 8}
166
+ end
167
+ end