jeremyevans-fixture_dependencies 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2007 Jeremy Evans
1
+ Copyright (c) 2007-2008 Jeremy Evans
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README CHANGED
@@ -1,31 +1,74 @@
1
- fixture_dependencies is a plugin that changes the way Rails uses fixtures in
2
- the following ways:
3
-
4
- - Fixtures can specify associations instead of foreign keys
5
- - Supports belongs_to, has_many, has_one, and habtm associations
6
- - Loads a fixture's dependencies (associations with other fixtures) before the
7
- fixture itself so that foreign key constraints aren't violated
8
- - Can specify individual fixtures to load per test or test suite
9
- - Loads fixtures on every test inside a transaction, so fixture information
10
- is never left in your database
1
+ = fixture_dependencies
2
+
3
+ fixture_dependencies is an advanced fixture loader, allowing the loading of
4
+ models from YAML fixtures, along with their entire dependency graph. It has
5
+ the following features:
6
+
7
+ - Fixtures specify association names instead of foreign keys
8
+ - Support both Sequel and ActiveRecord
9
+ - Supports many_to_one/belongs_to, one_to_many/has_many,
10
+ many_to_many/has_and_belongs_to_many, and has_one associations
11
+ - Loads a fixture's dependency graph in such a manner that foreign key
12
+ constraints aren't violated
13
+ - Has a very simple API (FixtureDependencies.load(:model__fixture))
11
14
  - Handles almost all cyclic dependencies
15
+ - Includes Rails and Sequel test helpers for Test::Unit that load fixtures for
16
+ every test inside a transaction, so fixture data is never left in your
17
+ database
12
18
 
13
- To use, first install the plugin, then add the following to
14
- test/test_helper.rb after "require 'test_help'":
19
+ == Installation
15
20
 
16
- require 'fixture_dependencies_test_help'
21
+ sudo gem install jeremyevans-fixture_dependencies \
22
+ --source http://gems.github.com
23
+
24
+ == Source
25
+
26
+ Source is available via github:
27
+
28
+ http://github.com/jeremyevans/fixture_dependencies
29
+
30
+ You can check it out with git:
31
+
32
+ git clone git://github.com/jeremyevans/fixture_dependencies.git
33
+
34
+ == Usage
35
+
36
+ === With Rails/ActiveRecord/Test::Unit:
37
+
38
+ Add the following to test/test_helper.rb after "require 'test_help'":
39
+
40
+ require 'fixture_dependencies/test_unit/rails'
17
41
 
18
42
  This overrides the default test helper to load the fixtures inside transactions
19
43
  and to use FixtureDependencies to load the fixtures.
20
44
 
21
- fixture_dependencies is available via github:
45
+ === With Sequel/Test::Unit:
46
+
47
+ Somewhere before the test code is loaded:
48
+
49
+ require 'fixture_dependencies/test_unit/sequel'
50
+
51
+ Make sure the test case classes use FixtureDependencies::SequelTestCase:
52
+
53
+ class ModelTest < FixtureDependencies::SequelTestCase
22
54
 
23
- http://github.com/jeremyevans/fixture_dependencies/tree/master
55
+ This runs the test cases inside a Sequel transaction.
24
56
 
25
- Changes to Fixtures:
57
+ === With other testing libraries:
58
+
59
+ You can just use FixtureDependencies.load to handle the loading of fixtures.
60
+ The use of transactions is up to you. It's fairly easy to add support for
61
+ running RSpec examples inside transactions. One thing you must do if you are
62
+ not using the rails test helper is to set the fixture path for
63
+ FixtureDependencies:
64
+
65
+ FixtureDependencies.fixture_path = '/path/to/fixtures'
66
+
67
+ == Changes to Rails default fixtures:
26
68
 
27
69
  fixture_dependencies is designed to require the least possible changes to
28
- fixtures. For example, see the following changes:
70
+ the default YAML fixtures used by Rails (well, at least Rails 1.2 and earlier).
71
+ For example, see the following changes:
29
72
 
30
73
  OLD NEW
31
74
  asset1: asset1:
@@ -42,7 +85,7 @@ nx7010, and a vendors fixture with the name lxg_computers.
42
85
 
43
86
  Fixture files still use the table_name of the model.
44
87
 
45
- Changes to the fixtures Class Method:
88
+ == Changes to the fixtures Class Method:
46
89
 
47
90
  fixture_dependencies can still use the fixtures class method in your test:
48
91
 
@@ -54,12 +97,11 @@ In Rails default testing practices, the arguments to fixtures are table names.
54
97
  fixture_dependencies changes this to underscored model names. If you are using
55
98
  Rails' recommended table practices, this shouldn't make a difference.
56
99
 
57
- Another change is that Rails defaults allow you to specify habtm join tables in
58
- fixtures. That doesn't work with fixture dependencies, as there is no
59
- associated model. Instead, you use a has_and_belongs_to_many association name
60
- in the the appropriate model fixtures (see below).
100
+ It is recommended that you do not use the fixtures method, and instead load
101
+ individual fixtures as needed (see below). This makes your tests much more
102
+ robust, in case you want to add or remove individual fixtures at a later date.
61
103
 
62
- Loading Individual Fixtures with fixtures class method:
104
+ == Loading individual fixtures with fixtures class method
63
105
 
64
106
  There is support for loading individual fixtures (and just their dependencies),
65
107
  using the following syntax:
@@ -69,9 +111,11 @@ using the following syntax:
69
111
  end
70
112
 
71
113
  This would load just the jeremy fixture and its dependencies. I find this is
72
- much better than loading all fixtures in most of my test suites.
114
+ much better than loading all fixtures in most of my test suites. Even better
115
+ is loading just the fixtures you want instead every test method (see below).
116
+ This leads to the most robust testing.
73
117
 
74
- Loading Fixtures Inside Test Methods:
118
+ == Loading fixtures inside test methods
75
119
 
76
120
  I find that it is often better to skip the use of the fixtures method entirely,
77
121
  and load the fixtures I want manually in each test method. This provides for
@@ -86,7 +130,7 @@ the loosest coupling possible. Here's an example:
86
130
 
87
131
  def test_award_statistics
88
132
  # Load all fixtures in both tables
89
- load(:employee_awards, :awards)
133
+ load(:employee_award__jeremy_first, :award__first)
90
134
  # Test the award_statistics method
91
135
  # (which pulls data from the tables loaded above)
92
136
  end
@@ -95,7 +139,7 @@ the loosest coupling possible. Here's an example:
95
139
  Don't worry about loading the same fixture twice, if a fixture is already
96
140
  loaded, it won't attempt to load it again.
97
141
 
98
- has_* Assocations in Fixtures:
142
+ == one_to_many/many_to_many/has_many/has_and_belongs_to_many assocations
99
143
 
100
144
  Here's an example of using has_one (logon_information), has_many (assets), and
101
145
  has_and_belongs_to_many (groups) associations.
@@ -120,7 +164,14 @@ groups in the order specified (and their dependencies...). Note that there
120
164
  is only a load order inside a specific association, associations are stored
121
165
  in the same hash as attributes and are loaded in an arbitrary order.
122
166
 
123
- Cyclic Dependencies:
167
+ == many_to_many/has_and_belongs_to_many join table fixtures
168
+
169
+ Another change is that Rails defaults allow you to specify habtm join tables in
170
+ fixtures. That doesn't work with fixture dependencies, as there is no
171
+ associated model. Instead, you use a has_and_belongs_to_many association name
172
+ in the the appropriate model fixtures (see above).
173
+
174
+ == Cyclic dependencies
124
175
 
125
176
  fixture_dependencies handles almost all cyclic dependencies. It handles all
126
177
  has_many, has_one, and habtm cyclic dependencies. It handles all
@@ -145,9 +196,9 @@ division belongs_to head_of_division when the employee is a member of the
145
196
  division and also the head of the division), even that approach is not
146
197
  possible.
147
198
 
148
- Known Issues:
199
+ == Known issues
149
200
 
150
- Currently, the plugin only supports yaml fixtures, but other types of fixtures
201
+ Currently, the plugin only supports YAML fixtures, but other types of fixtures
151
202
  would be fairly easy to add (send me a patch if you add support for another
152
203
  fixture type).
153
204
 
@@ -161,32 +212,31 @@ was rolled back in r2730 due to speed issues. See ticket #2404 on Rails' trac.
161
212
  Instantiated fixtures are not available with this plugin. Instead, you should
162
213
  use load(:model__fixture_name).
163
214
 
164
- Troubleshooting:
215
+ == Troubleshooting
165
216
 
166
217
  If you run into problems with loading your fixtures, it can be difficult to see
167
218
  where the problems are. To aid in debugging an error, add the following to
168
219
  test/test_helper.rb:
169
220
 
170
- FixtureDependencies.verbose = 2
221
+ FixtureDependencies.verbose = 3
171
222
 
172
223
  This will give a verbose description of the loading and saving of fixtures for
173
- every test, including the recursive loading of all dependencies.
224
+ every test, including the recursive loading of the dependency graph.
225
+
226
+ == Similar Ideas
174
227
 
175
- Similar Ideas:
228
+ Rails now supports something similar by default. Honestly, I'm not sure what
229
+ the differences are.
176
230
 
177
231
  fixture_references is a similar plugin. It uses erb inside yaml, and uses the
178
232
  foreign key numbers inside of the association names, which leads me to believe
179
233
  it doesn't support has_* associations.
180
234
 
181
- Ticket #6424 on the Rails' trac also implements a similar idea, but it parses
182
- the associations and changes them to foreign keys, which leads me to believe it
183
- doesn't support has_* associations either.
184
-
185
- License:
235
+ == License
186
236
 
187
237
  fixture_dependencies is released under the MIT License. See the LICENSE file
188
238
  for details.
189
239
 
190
- Author:
240
+ == Author
191
241
 
192
242
  Jeremy Evans <code@jeremyevans.net>
@@ -2,156 +2,183 @@ class FixtureDependencies
2
2
  @fixtures = {}
3
3
  @loaded = {}
4
4
  @verbose = 0
5
- class << self
6
- attr_reader :fixtures, :loaded
7
- attr_accessor :verbose
8
- # Load all record arguments into the database. If a single argument is
9
- # given and it corresponds to a single fixture, return the the model
10
- # instance corresponding to that fixture. If a single argument if given
11
- # and it corresponds to a model, return all model instances corresponding
12
- # to that model. If multiple arguments are given, return a list of
13
- # model instances (for single fixture arguments) or list of model instances
14
- # (for model fixture arguments). If no arguments, return the empty list.
15
- #
16
- # This will load the data from the yaml files for each argument whose model
17
- # is not already in the fixture hash.
18
- def load(*records)
19
- ret = records.collect do |record|
20
- model_name, name = split_name(record)
21
- if name
22
- use(record.to_sym)
23
- else
24
- model_name = model_name.singularize
25
- unless loaded[model_name.to_sym]
26
- puts "loading #{model_name}.yml" if verbose > 0
27
- load_yaml(model_name)
28
- end
29
- fixtures[model_name.to_sym].keys.collect{|name| use("#{model_name}__#{name}".to_sym)}
5
+
6
+ # Load all record arguments into the database. If a single argument is
7
+ # given and it corresponds to a single fixture, return the the model
8
+ # instance corresponding to that fixture. If a single argument if given
9
+ # and it corresponds to a model, return all model instances corresponding
10
+ # to that model. If multiple arguments are given, return a list of
11
+ # model instances (for single fixture arguments) or list of model instances
12
+ # (for model fixture arguments). If no arguments, return the empty list.
13
+ #
14
+ # This will load the data from the yaml files for each argument whose model
15
+ # is not already in the fixture hash.
16
+ def self.load(*records)
17
+ ret = records.collect do |record|
18
+ model_name, name = split_name(record)
19
+ if name
20
+ use(record.to_sym)
21
+ else
22
+ model_name = model_name.singularize
23
+ unless loaded[model_name.to_sym]
24
+ puts "loading #{model_name}.yml" if verbose > 0
25
+ load_yaml(model_name)
30
26
  end
27
+ fixtures[model_name.to_sym].keys.collect{|name| use("#{model_name}__#{name}".to_sym)}
31
28
  end
32
- records.length == 1 ? ret[0] : ret
33
29
  end
30
+ records.length == 1 ? ret[0] : ret
31
+ end
32
+ end
33
+
34
+ require 'fixture_dependencies/active_record' if defined?(ActiveRecord::Base)
35
+ require 'fixture_dependencies/sequel' if defined?(Sequel::Model)
36
+
37
+
38
+ class << FixtureDependencies
39
+ attr_reader :fixtures, :loaded
40
+ attr_accessor :verbose, :fixture_path
41
+
42
+ private
34
43
 
35
- private
36
- # Add a fixture to the fixture hash (does not add to the database,
37
- # just makes it available to be add to the database via use).
38
- def add(model_name, name, attributes)
39
- (fixtures[model_name.to_sym]||={})[name.to_sym] = attributes
40
- end
41
-
42
- # Get the model instance that already exists in the database using
43
- # the fixture name.
44
- def get(record)
45
- model_name, name = split_name(record)
46
- model = model_name.camelize.constantize
47
- model.find(fixtures[model_name.to_sym][name.to_sym][model.primary_key.to_sym])
48
- end
49
-
50
- # Adds all fixtures in the yaml fixture file for the model to the fixtures
51
- # hash (does not add them to the database, see add).
52
- def load_yaml(model_name)
53
- YAML.load(File.read(File.join(Test::Unit::TestCase.fixture_path, "#{model_name.camelize.constantize.table_name}.yml"))).each do |name, attributes|
54
- symbol_attrs = {}
55
- attributes.each{|k,v| symbol_attrs[k.to_sym] = v}
56
- add(model_name.to_sym, name, symbol_attrs)
57
- end
58
- loaded[model_name.to_sym] = true
59
- end
60
-
61
- # Split the fixture name into the name of the model and the name of
62
- # the individual fixture.
63
- def split_name(name)
64
- name.to_s.split('__', 2)
65
- end
66
-
67
- # Load the individual fixture into the database, by loading all necessary
68
- # belongs_to dependencies before saving the model, and all has_*
69
- # dependencies after saving the model. If the model already exists in
70
- # the database, return it. Will check the yaml file for fixtures if no
71
- # fixtures yet exist for the model. If the fixture isn't in the fixture
72
- # hash, raise an error.
73
- def use(record, loading = [], procs = {})
74
- spaces = " " * loading.length
75
- puts "#{spaces}using #{record}" if verbose > 0
76
- puts "#{spaces}load stack:#{loading.inspect}" if verbose > 1
77
- loading.push(record)
78
- model_name, name = split_name(record)
79
- model = model_name.camelize.constantize
80
- unless loaded[model_name.to_sym]
81
- puts "#{spaces}loading #{model.table_name}.yml" if verbose > 0
82
- load_yaml(model_name)
83
- end
84
- raise ActiveRecord::RecordNotFound, "Couldn't use fixture #{record.inspect}" unless attributes = fixtures[model_name.to_sym][name.to_sym]
85
- # return if object has already been loaded into the database
86
- if existing_obj = model.send("find_by_#{model.primary_key}", attributes[model.primary_key.to_sym])
87
- return existing_obj
88
- end
89
- obj = model.new
90
- many_associations = []
91
- attributes.each do |attr, value|
92
- if reflection = model.reflect_on_association(attr.to_sym)
93
- if reflection.macro == :belongs_to
94
- dep_name = "#{reflection.klass.name.underscore}__#{value}".to_sym
95
- if dep_name == record
96
- # Self referential record, use primary key
97
- puts "#{spaces}#{record}.#{attr}: belongs_to self-referential" if verbose > 1
98
- attr = reflection.options[:foreign_key] || reflection.klass.table_name.classify.foreign_key
99
- value = attributes[model.primary_key.to_sym]
100
- elsif loading.include?(dep_name)
101
- # Association cycle detected, set foreign key for this model afterward using procs
102
- # This is will fail if the column is set to not null or validates_presence_of
103
- puts "#{spaces}#{record}.#{attr}: belongs-to cycle detected:#{dep_name}" if verbose > 1
104
- (procs[dep_name] ||= []) << Proc.new do |assoc|
105
- m = model.find(attributes[model.primary_key.to_sym])
106
- m.send("#{attr}=", assoc)
107
- m.save!
108
- end
109
- value = nil
110
- else
111
- # Regular assocation, load it
112
- puts "#{spaces}#{record}.#{attr}: belongs_to:#{dep_name}" if verbose > 1
113
- use(dep_name, loading, procs)
114
- value = get(dep_name)
115
- end
116
- elsif
117
- many_associations << [attr, reflection, reflection.macro == :has_one ? [value] : value]
118
- next
44
+ # Add a fixture to the fixture hash (does not add to the database,
45
+ # just makes it available to be add to the database via use).
46
+ def add(model_name, name, attributes)
47
+ (fixtures[model_name.to_sym]||={})[name.to_sym] = attributes
48
+ end
49
+
50
+ # Get the model instance that already exists in the database using
51
+ # the fixture name.
52
+ def get(record)
53
+ model_name, name = split_name(record)
54
+ model = model_name.camelize.constantize
55
+ model_method(:model_find, model_type(model), model, fixtures[model_name.to_sym][name.to_sym][model.primary_key.to_sym])
56
+ end
57
+
58
+ # Adds all fixtures in the yaml fixture file for the model to the fixtures
59
+ # hash (does not add them to the database, see add).
60
+ def load_yaml(model_name)
61
+ raise(ArgumentError, "No fixture_path set. Use FixtureDependencies.fixture_path = ...") unless fixture_path
62
+ YAML.load(File.read(File.join(fixture_path, "#{model_name.camelize.constantize.table_name}.yml"))).each do |name, attributes|
63
+ symbol_attrs = {}
64
+ attributes.each{|k,v| symbol_attrs[k.to_sym] = v}
65
+ add(model_name.to_sym, name, symbol_attrs)
66
+ end
67
+ loaded[model_name.to_sym] = true
68
+ end
69
+
70
+ # Delegate to the correct method based on mtype
71
+ def model_method(meth, mtype, *args, &block)
72
+ send("#{meth}_#{mtype}", *args, &block)
73
+ end
74
+
75
+ # A symbol representing the base class of the model, currently
76
+ # ActiveRecord::Base and Sequel::Model are supported.
77
+ def model_type(model)
78
+ if model.ancestors.map{|x| x.to_s}.include?('ActiveRecord::Base')
79
+ :AR
80
+ elsif model.ancestors.map{|x| x.to_s}.include?('Sequel::Model')
81
+ :S
82
+ else
83
+ raise TypeError, 'not ActiveRecord or Sequel model'
84
+ end
85
+ end
86
+
87
+ # Split the fixture name into the name of the model and the name of
88
+ # the individual fixture.
89
+ def split_name(name)
90
+ name.to_s.split('__', 2)
91
+ end
92
+
93
+ # Load the individual fixture into the database, by loading all necessary
94
+ # belongs_to dependencies before saving the model, and all has_*
95
+ # dependencies after saving the model. If the model already exists in
96
+ # the database, return it. Will check the yaml file for fixtures if no
97
+ # fixtures yet exist for the model. If the fixture isn't in the fixture
98
+ # hash, raise an error.
99
+ def use(record, loading = [], procs = {})
100
+ spaces = " " * loading.length
101
+ puts "#{spaces}using #{record}" if verbose > 0
102
+ puts "#{spaces}load stack:#{loading.inspect}" if verbose > 1
103
+ loading.push(record)
104
+ model_name, name = split_name(record)
105
+ model = model_name.camelize.constantize
106
+ unless loaded[model_name.to_sym]
107
+ puts "#{spaces}loading #{model.table_name}.yml" if verbose > 0
108
+ load_yaml(model_name)
109
+ end
110
+ mtype = model_type(model)
111
+ model_method(:raise_model_error, mtype, "Couldn't use fixture #{record.inspect}") unless attributes = fixtures[model_name.to_sym][name.to_sym]
112
+ # return if object has already been loaded into the database
113
+ if existing_obj = model_method(:model_find_by_pk, mtype, model, attributes[model.primary_key.to_sym])
114
+ puts "#{spaces}using #{record}: already in database" if verbose > 2
115
+ return existing_obj
116
+ end
117
+ obj = model.new
118
+ many_associations = []
119
+ attributes.each do |attr, value|
120
+ if reflection = model_method(:reflection, mtype, model, attr.to_sym)
121
+ if [:belongs_to, :many_to_one].include?(model_method(:reflection_type, mtype, reflection))
122
+ dep_name = "#{model_method(:reflection_class, mtype, reflection).name.underscore}__#{value}".to_sym
123
+ if dep_name == record
124
+ # Self referential record, use primary key
125
+ puts "#{spaces}#{record}.#{attr}: belongs_to self-referential" if verbose > 1
126
+ attr = model_method(:reflection_key, mtype, reflection)
127
+ value = attributes[model.primary_key.to_sym]
128
+ elsif loading.include?(dep_name)
129
+ # Association cycle detected, set foreign key for this model afterward using procs
130
+ # This is will fail if the column is set to not null or validates_presence_of
131
+ puts "#{spaces}#{record}.#{attr}: belongs-to cycle detected:#{dep_name}" if verbose > 1
132
+ (procs[dep_name] ||= []) << Proc.new do |assoc|
133
+ m = model_method(:model_find, mtype, model, attributes[model.primary_key.to_sym])
134
+ m.send("#{attr}=", assoc)
135
+ model_method(:model_save, mtype, m)
119
136
  end
137
+ value = nil
138
+ else
139
+ # Regular assocation, load it
140
+ puts "#{spaces}#{record}.#{attr}: belongs_to:#{dep_name}" if verbose > 1
141
+ use(dep_name, loading, procs)
142
+ value = get(dep_name)
120
143
  end
121
- obj.send("#{attr}=", value)
122
- end
123
- puts "#{spaces}saving #{record}" if verbose > 1
124
- obj.save!
125
- loading.pop
126
- # Update the circular references
127
- if procs[record]
128
- procs[record].each{|p| p.call(obj)}
129
- procs.delete(record)
144
+ elsif
145
+ many_associations << [attr, reflection, model_method(:reflection_type, mtype, reflection) == :has_one ? [value] : value]
146
+ next
130
147
  end
131
- # Update the has_many and habtm associations
132
- many_associations.each do |attr, reflection, values|
133
- proxy = obj.send(attr)
134
- values.each do |value|
135
- dep_name = "#{reflection.klass.name.underscore}__#{value}".to_sym
136
- if dep_name == record
137
- # Self referential, add association
138
- puts "#{spaces}#{record}.#{attr}: #{reflection.macro} self-referential" if verbose > 1
139
- reflection.macro == :has_one ? (proxy = obj) : (proxy << obj)
140
- elsif loading.include?(dep_name)
141
- # Cycle Detected, add association to this object after saving other object
142
- puts "#{spaces}#{record}.#{attr}: #{reflection.macro} cycle detected:#{dep_name}" if verbose > 1
143
- (procs[dep_name] ||= []) << Proc.new do |assoc|
144
- reflection.macro == :has_one ? (proxy = assoc) : (proxy << assoc unless proxy.include?(assoc))
145
- end
146
- else
147
- # Regular association, add it
148
- puts "#{spaces}#{record}.#{attr}: #{reflection.macro}:#{dep_name}" if verbose > 1
149
- assoc = use(dep_name, loading, procs)
150
- reflection.macro == :has_one ? (proxy = assoc) : (proxy << assoc unless proxy.include?(assoc))
151
- end
148
+ end
149
+ puts "#{spaces}#{record}.#{attr} = #{value.inspect}" if verbose > 2
150
+ obj.send("#{attr}=", value)
151
+ end
152
+ puts "#{spaces}saving #{record}" if verbose > 1
153
+ model_method(:model_save, mtype, obj)
154
+ loading.pop
155
+ # Update the circular references
156
+ if procs[record]
157
+ procs[record].each{|p| p.call(obj)}
158
+ procs.delete(record)
159
+ end
160
+ # Update the has_many and habtm associations
161
+ many_associations.each do |attr, reflection, values|
162
+ values.each do |value|
163
+ dep_name = "#{model_method(:reflection_class, mtype, reflection).name.underscore}__#{value}".to_sym
164
+ rtype = model_method(:reflection_type, mtype, reflection) if verbose > 1
165
+ if dep_name == record
166
+ # Self referential, add association
167
+ puts "#{spaces}#{record}.#{attr}: #{rtype} self-referential" if verbose > 1
168
+ model_method(:add_associated_object, mtype, reflection, attr, obj, obj)
169
+ elsif loading.include?(dep_name)
170
+ # Cycle Detected, add association to this object after saving other object
171
+ puts "#{spaces}#{record}.#{attr}: #{rtype} cycle detected:#{dep_name}" if verbose > 1
172
+ (procs[dep_name] ||= []) << Proc.new do |assoc|
173
+ model_method(:add_associated_object, mtype, reflection, attr, obj, assoc)
152
174
  end
175
+ else
176
+ # Regular association, add it
177
+ puts "#{spaces}#{record}.#{attr}: #{rtype}:#{dep_name}" if verbose > 1
178
+ model_method(:add_associated_object, mtype, reflection, attr, obj, use(dep_name, loading, procs))
153
179
  end
154
- obj
155
180
  end
181
+ end
182
+ obj
156
183
  end
157
184
  end
@@ -0,0 +1,43 @@
1
+ class << FixtureDependencies
2
+ private
3
+
4
+ def add_associated_object_AR(reflection, attr, object, assoc)
5
+ if reflection.macro == :has_one
6
+ object.send("#{attr}=", assoc)
7
+ elsif !object.send(attr).include?(assoc)
8
+ object.send(attr) << assoc
9
+ end
10
+ end
11
+
12
+ def model_find_AR(model, pk)
13
+ model.find(pk)
14
+ end
15
+
16
+ def model_find_by_pk_AR(model, pk)
17
+ model.send("find_by_#{model.primary_key}", pk)
18
+ end
19
+
20
+ def model_save_AR(object)
21
+ object.save || raise(ActiveRecord::ActiveRecordError)
22
+ end
23
+
24
+ def raise_model_error_AR(message)
25
+ ActiveRecord::RecordNotFound
26
+ end
27
+
28
+ def reflection_AR(model, attr)
29
+ model.reflect_on_association(attr)
30
+ end
31
+
32
+ def reflection_class_AR(reflection)
33
+ reflection.klass
34
+ end
35
+
36
+ def reflection_key_AR(reflection)
37
+ reflection.options[:foreign_key] || reflection.klass.table_name.classify.foreign_key
38
+ end
39
+
40
+ def reflection_type_AR(reflection)
41
+ reflection.macro
42
+ end
43
+ end
@@ -0,0 +1,40 @@
1
+ class << FixtureDependencies
2
+ private
3
+
4
+ def add_associated_object_S(reflection, attr, object, assoc)
5
+ object.send("add_#{attr.singularize}", assoc) unless object.send(attr).include?(assoc)
6
+ end
7
+
8
+ def model_find_S(model, pk)
9
+ model[pk] || raise(Sequel::Error)
10
+ end
11
+
12
+ def model_find_by_pk_S(model, pk)
13
+ model[pk]
14
+ end
15
+
16
+ def model_save_S(object)
17
+ object.raise_on_save_failure = true
18
+ object.save
19
+ end
20
+
21
+ def raise_model_error_S(message)
22
+ Sequel::Error
23
+ end
24
+
25
+ def reflection_S(model, attr)
26
+ model.association_reflection(attr)
27
+ end
28
+
29
+ def reflection_class_S(reflection)
30
+ reflection.associated_class
31
+ end
32
+
33
+ def reflection_key_S(reflection)
34
+ reflection[:key]
35
+ end
36
+
37
+ def reflection_type_S(reflection)
38
+ reflection[:type]
39
+ end
40
+ end
@@ -0,0 +1,14 @@
1
+ require 'fixture_dependencies'
2
+
3
+ module Test
4
+ module Unit
5
+ class TestCase
6
+ private
7
+
8
+ # Load given fixtures using FixtureDependencies
9
+ def load(*fixture)
10
+ FixtureDependencies.load(*fixture)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,33 @@
1
+ require 'fixture_dependencies/test_unit'
2
+ FixtureDependencies.fixture_path = Test::Unit::TestCase.fixture_path
3
+
4
+ module Test
5
+ module Unit
6
+ class TestCase
7
+ class << self
8
+ alias_method :stupid_method_added, :method_added
9
+ end
10
+ def self.method_added(x)
11
+ end
12
+
13
+ # Load fixtures using FixtureDependencies inside a transaction
14
+ def setup_with_fixtures
15
+ ActiveRecord::Base.send :increment_open_transactions
16
+ ActiveRecord::Base.connection.begin_db_transaction
17
+ load_fixtures
18
+ end
19
+ alias_method :setup, :setup_with_fixtures
20
+
21
+ class << self
22
+ alias_method :method_added, :stupid_method_added
23
+ end
24
+
25
+ private
26
+
27
+ # Load fixtures named with the fixtures class method
28
+ def load_fixtures
29
+ load(*fixture_table_names)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,13 @@
1
+ require 'fixture_dependencies/test_unit'
2
+
3
+ class FixtureDependencies::SequelTestCase < Test::Unit::TestCase
4
+ # Work around for Rails stupidity
5
+ undef_method :default_test if method_defined?(:default_test)
6
+
7
+ def run(*args, &block)
8
+ Sequel::Model.db.transaction do
9
+ super
10
+ raise Sequel::Error::Rollback
11
+ end
12
+ end
13
+ end
@@ -1,34 +1 @@
1
- module Test
2
- module Unit
3
- class TestCase
4
- class << self
5
- alias_method :stupid_method_added, :method_added
6
- end
7
- def self.method_added(x)
8
- end
9
-
10
- # Load fixtures using FixtureDependencies inside a transaction
11
- def setup_with_fixtures
12
- ActiveRecord::Base.send :increment_open_transactions
13
- ActiveRecord::Base.connection.begin_db_transaction
14
- load_fixtures
15
- end
16
- alias_method :setup, :setup_with_fixtures
17
-
18
- class << self
19
- alias_method :method_added, :stupid_method_added
20
- end
21
-
22
- private
23
- # Load fixtures named with the fixtures class method
24
- def load_fixtures
25
- load(*fixture_table_names)
26
- end
27
-
28
- # Load given fixtures using FixtureDependencies
29
- def load(*fixture)
30
- FixtureDependencies.load(*fixture)
31
- end
32
- end
33
- end
34
- end
1
+ require 'fixture_dependencies/test_unit/rails'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeremyevans-fixture_dependencies
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jeremy Evans
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-07-06 00:00:00 -07:00
12
+ date: 2008-08-13 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -26,6 +26,11 @@ files:
26
26
  - LICENSE
27
27
  - lib/fixture_dependencies.rb
28
28
  - lib/fixture_dependencies_test_help.rb
29
+ - lib/fixture_dependencies/sequel.rb
30
+ - lib/fixture_dependencies/active_record.rb
31
+ - lib/fixture_dependencies/test_unit.rb
32
+ - lib/fixture_dependencies/test_unit/rails.rb
33
+ - lib/fixture_dependencies/test_unit/sequel.rb
29
34
  has_rdoc: true
30
35
  homepage:
31
36
  post_install_message:
@@ -54,6 +59,6 @@ rubyforge_project:
54
59
  rubygems_version: 1.2.0
55
60
  signing_key:
56
61
  specification_version: 2
57
- summary: Rails fixture loading that works with foreign keys
62
+ summary: Sequel/ActiveRecord fixture loader that handles dependency graphs
58
63
  test_files: []
59
64