fixation 1.3.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -0
- data/lib/fixation.rb +13 -251
- data/lib/fixation/fixture_table.rb +163 -0
- data/lib/fixation/fixtures.rb +103 -0
- data/lib/fixation/version.rb +1 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c574bc684d8f4b914fc2ecb3189c06eb603d0b47
|
4
|
+
data.tar.gz: 4c5ddf419b00ccb17f45d825c7c5681a3ffb328c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 89541e134b63e0f395304f60aa5191d444a7e65becfcc6d6a296afa0905ef6ef8cd0362a5798258855ddd4d5ce9aabbb5d8ae2669f53ec1fde34111316afbcf2
|
7
|
+
data.tar.gz: 9e8f2cc7f32d14b7151024cb22f570a32bc7661863114bbb341c9e29646f899531d76d3cb0ef63334695f346ba81abcfa0af9077a6d2b527002df0839e1d3847
|
data/README.md
CHANGED
@@ -76,6 +76,16 @@ if Rails.env.test? && Fixation.running_under_spring?
|
|
76
76
|
end
|
77
77
|
```
|
78
78
|
|
79
|
+
## Auto-clearing other tables
|
80
|
+
|
81
|
+
By default Fixation will only reset those tables that have a fixture file, like Rails. Optionally, you can tell it to clear all other tables so that you don't need to make empty fixture files.
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
if Rails.env.test?
|
85
|
+
Fixation.clear_other_tables = true
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
79
89
|
|
80
90
|
## Contributing
|
81
91
|
|
data/lib/fixation.rb
CHANGED
@@ -3,263 +3,25 @@ require 'yaml'
|
|
3
3
|
require 'set'
|
4
4
|
require 'active_support/dependencies'
|
5
5
|
require 'active_record/errors'
|
6
|
-
|
6
|
+
require_relative "fixation/version"
|
7
|
+
require_relative "fixation/fixture_table"
|
8
|
+
require_relative "fixation/fixtures"
|
7
9
|
|
8
10
|
module Fixation
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(filename, basename, connection, now)
|
13
|
-
@filename = filename
|
14
|
-
@connection = connection
|
15
|
-
@now = now
|
16
|
-
|
17
|
-
@class_name = basename.classify
|
18
|
-
begin
|
19
|
-
@klass = @class_name.constantize
|
20
|
-
@klass = nil unless @klass < ActiveRecord::Base
|
21
|
-
rescue NameError
|
22
|
-
ActiveRecord::Base.logger.warn "couldn't load #{class_name} for fixture table #{table_name}: #{$!}"
|
23
|
-
end
|
24
|
-
|
25
|
-
if @klass
|
26
|
-
@table_name = @klass.table_name
|
27
|
-
@primary_key = @klass.primary_key
|
28
|
-
@record_timestamps = @klass.record_timestamps
|
29
|
-
@inheritance_column = @klass.inheritance_column
|
30
|
-
else
|
31
|
-
@table_name = basename.gsub('/', '_')
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def columns_hash
|
36
|
-
@columns_hash ||= connection.columns(table_name).index_by(&:name)
|
37
|
-
end
|
38
|
-
|
39
|
-
def content
|
40
|
-
template = File.read(filename)
|
41
|
-
render_context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new.get_binding
|
42
|
-
ERB.new(template).result(render_context)
|
43
|
-
end
|
44
|
-
|
45
|
-
def parsed_rows
|
46
|
-
result = YAML.load(content)
|
47
|
-
result ||= {} # for completely empty files
|
48
|
-
|
49
|
-
unless (result.is_a?(Hash) || result.is_a?(YAML::Omap)) && result.all? { |name, attributes| name.is_a?(String) && attributes.is_a?(Hash) }
|
50
|
-
raise ActiveRecord::Fixture::FormatError, "#{filename} needs to contain a hash of fixtures"
|
51
|
-
end
|
52
|
-
|
53
|
-
result.delete('DEFAULTS')
|
54
|
-
result
|
55
|
-
rescue ArgumentError, Psych::SyntaxError => error
|
56
|
-
# we use exactly the same error class and message as ActiveRecord::FixtureSet in case anyone was depending on it
|
57
|
-
raise ActiveRecord::Fixture::FormatError, "a YAML error occurred parsing #{filename}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
|
58
|
-
end
|
59
|
-
|
60
|
-
def embellished_rows
|
61
|
-
@embellished_rows ||= parsed_rows.each do |name, attributes|
|
62
|
-
embellish_fixture(name, attributes, columns_hash)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def embellish_fixture(name, attributes, columns_hash)
|
67
|
-
# populate the primary key column, if not already set
|
68
|
-
if @primary_key && columns_hash[@primary_key] && !attributes.has_key?(@primary_key)
|
69
|
-
attributes[@primary_key] = Fixation.identify(name, columns_hash[@primary_key].type)
|
70
|
-
end
|
71
|
-
|
72
|
-
# substitute $LABEL into all string values
|
73
|
-
attributes.each do |column_name, value|
|
74
|
-
attributes[column_name] = value.gsub("$LABEL", name) if value.is_a?(String)
|
75
|
-
end
|
76
|
-
|
77
|
-
# populate any timestamp columns, if not already set
|
78
|
-
if @record_timestamps
|
79
|
-
%w(created_at updated_at).each do |column_name|
|
80
|
-
attributes[column_name] = now if columns_hash[column_name] && !attributes.has_key?(column_name)
|
81
|
-
end
|
82
|
-
%w(created_at updated_at).each do |column_name|
|
83
|
-
attributes[column_name] = now.to_date if columns_hash[column_name] && !attributes.has_key?(column_name)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# convert enum names to values
|
88
|
-
@klass.defined_enums.each do |name, values|
|
89
|
-
attributes[name] = values.fetch(attributes[name], attributes[name]) if attributes.has_key?(name)
|
90
|
-
end if @klass.respond_to?(:defined_enums)
|
91
|
-
|
92
|
-
# convert any association names into the identity column equivalent - following code from activerecord's fixtures.rb
|
93
|
-
nonexistant_columns = attributes.keys - columns_hash.keys
|
94
|
-
|
95
|
-
if @klass && nonexistant_columns.present?
|
96
|
-
# If STI is used, find the correct subclass for association reflection
|
97
|
-
reflection_class =
|
98
|
-
if attributes.include?(@inheritance_column)
|
99
|
-
attributes[@inheritance_column].constantize rescue @klass
|
100
|
-
else
|
101
|
-
@klass
|
102
|
-
end
|
103
|
-
|
104
|
-
nonexistant_columns.each do |column_name|
|
105
|
-
association = reflection_class.reflect_on_association(column_name)
|
106
|
-
|
107
|
-
if association.nil?
|
108
|
-
raise ActiveRecord::Fixture::FormatError, "No column named #{column_name} found in table #{table_name}"
|
109
|
-
elsif association.macro != :belongs_to
|
110
|
-
raise ActiveRecord::Fixture::FormatError, "Association #{column_name} in table #{table_name} has type #{association.macro}, which is not currently supported"
|
111
|
-
else
|
112
|
-
value = attributes.delete(column_name)
|
113
|
-
|
114
|
-
if association.options[:polymorphic] && value.is_a?(String) && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
|
115
|
-
# support polymorphic belongs_to as "label (Type)"
|
116
|
-
attributes[association.foreign_type] = $1
|
117
|
-
end
|
118
|
-
|
119
|
-
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
|
120
|
-
attributes[fk_name] = value ? ActiveRecord::FixtureSet.identify(value) : value
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def fixture_ids
|
127
|
-
embellished_rows.each_with_object({}) do |(name, attributes), ids|
|
128
|
-
ids[name] = attributes['id'] || attributes['uuid']
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def statements
|
133
|
-
statements = ["DELETE FROM #{connection.quote_table_name table_name}"]
|
134
|
-
|
135
|
-
unless embellished_rows.empty?
|
136
|
-
# first figure out what columns we have to insert into; we're going to need to use the same names for
|
137
|
-
# all rows so we can use the multi-line INSERT syntax
|
138
|
-
columns_to_include = Set.new
|
139
|
-
embellished_rows.each do |name, attributes|
|
140
|
-
attributes.each do |column_name, value|
|
141
|
-
raise ActiveRecord::Fixture::FormatError, "No column named #{column_name.inspect} found in table #{table_name.inspect} (attribute on fixture #{name.inspect})" unless columns_hash[column_name]
|
142
|
-
columns_to_include.add(columns_hash[column_name])
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
# now build the INSERT statement
|
147
|
-
quoted_column_names = columns_to_include.collect { |column| connection.quote_column_name(column.name) }.join(', ')
|
148
|
-
statements <<
|
149
|
-
"INSERT INTO #{connection.quote_table_name table_name} (#{quoted_column_names}) VALUES " +
|
150
|
-
embellished_rows.collect do |name, attributes|
|
151
|
-
'(' + columns_to_include.collect do |column|
|
152
|
-
if attributes.has_key?(column.name)
|
153
|
-
quote_value(column, attributes[column.name])
|
154
|
-
else
|
155
|
-
column.default_function || quote_value(column, column.default)
|
156
|
-
end
|
157
|
-
end.join(', ') + ')'
|
158
|
-
end.join(', ')
|
159
|
-
end
|
160
|
-
|
161
|
-
statements
|
162
|
-
end
|
163
|
-
|
164
|
-
def quote_value(column, value)
|
165
|
-
connection.quote(value)
|
166
|
-
rescue TypeError
|
167
|
-
connection.quote(YAML.dump(value))
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
class Fixtures
|
172
|
-
def initialize
|
173
|
-
@class_names = {}
|
174
|
-
@fixture_ids = {}
|
175
|
-
@statements = {}
|
176
|
-
|
177
|
-
compile_fixture_files
|
178
|
-
end
|
179
|
-
|
180
|
-
def compile_fixture_files(connection = ActiveRecord::Base.connection)
|
181
|
-
puts "#{Time.now} building fixtures" if Fixation.trace
|
182
|
-
|
183
|
-
now = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
|
184
|
-
Fixation.paths.each do |path|
|
185
|
-
Dir["#{path}/{**,*}/*.yml"].each do |pathname|
|
186
|
-
basename = pathname[path.size + 1..-5]
|
187
|
-
compile_fixture_file(pathname, basename, connection, now) if ::File.file?(pathname)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
puts "#{Time.now} built fixtures for #{@fixture_ids.size} tables" if Fixation.trace
|
192
|
-
end
|
193
|
-
|
194
|
-
def compile_fixture_file(filename, basename, connection, now)
|
195
|
-
fixture_table = FixtureTable.new(filename, basename, connection, now)
|
196
|
-
fixture_name = basename.gsub('/', '_')
|
197
|
-
@fixture_ids[fixture_name] = fixture_table.fixture_ids
|
198
|
-
@statements[fixture_name] = fixture_table.statements
|
199
|
-
@class_names[fixture_name] = fixture_table.class_name
|
200
|
-
end
|
201
|
-
|
202
|
-
def apply_fixtures(connection = ActiveRecord::Base.connection)
|
203
|
-
connection.transaction do
|
204
|
-
@statements.each do |table_name, table_statements|
|
205
|
-
table_statements.each do |statement|
|
206
|
-
connection.execute(statement)
|
207
|
-
end
|
208
|
-
end
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
def fixture_methods
|
213
|
-
fixture_ids = @fixture_ids
|
214
|
-
class_names = @class_names
|
215
|
-
|
216
|
-
methods = Module.new do
|
217
|
-
def setup_fixtures(config = ActiveRecord::Base)
|
218
|
-
if run_in_transaction?
|
219
|
-
@@fixated_fixtures_applied ||= false
|
220
|
-
unless @@fixated_fixtures_applied
|
221
|
-
puts "#{Time.now} applying fixtures" if Fixation.trace
|
222
|
-
Fixation.apply_fixtures
|
223
|
-
@@fixated_fixtures_applied = true
|
224
|
-
puts "#{Time.now} applied fixtures" if Fixation.trace
|
225
|
-
end
|
226
|
-
else
|
227
|
-
@@fixated_fixtures_applied = false
|
228
|
-
end
|
229
|
-
super
|
230
|
-
end
|
231
|
-
|
232
|
-
fixture_ids.each do |fixture_name, fixtures|
|
233
|
-
begin
|
234
|
-
klass = class_names[fixture_name].constantize
|
235
|
-
rescue NameError
|
236
|
-
next
|
237
|
-
end
|
238
|
-
|
239
|
-
define_method(fixture_name) do |*fixture_names|
|
240
|
-
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
241
|
-
|
242
|
-
@fixture_cache[fixture_name] ||= {}
|
11
|
+
# The list of paths to look in to find .yml fixture files.
|
12
|
+
cattr_accessor :paths
|
13
|
+
self.paths = %w(test/fixtures spec/fixtures)
|
243
14
|
|
244
|
-
|
245
|
-
|
246
|
-
raise StandardError, "No fixture named '#{name}' found for fixture set '#{fixture_name}'" if id.nil?
|
15
|
+
# Set to true to clear any tables found in the database that do *not* have a fixture file.
|
16
|
+
cattr_accessor :clear_other_tables
|
247
17
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
instances.size == 1 ? instances.first : instances
|
253
|
-
end
|
254
|
-
private fixture_name
|
255
|
-
end
|
256
|
-
end
|
257
|
-
end
|
258
|
-
end
|
18
|
+
# Set to the list of tables you don't want to clear (if clear_other_tables is turned on).
|
19
|
+
# Defaults to just schema_migrations.
|
20
|
+
cattr_accessor :tables_not_to_clear
|
21
|
+
self.tables_not_to_clear = %w(schema_migrations)
|
259
22
|
|
23
|
+
# Set to true to log some debugging information to stdout.
|
260
24
|
cattr_accessor :trace
|
261
|
-
cattr_accessor :paths
|
262
|
-
self.paths = %w(test/fixtures spec/fixtures)
|
263
25
|
|
264
26
|
def self.build_fixtures
|
265
27
|
@fixtures = Fixtures.new
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module Fixation
|
2
|
+
class FixtureTable
|
3
|
+
attr_reader :filename, :class_name, :table_name, :connection, :now
|
4
|
+
|
5
|
+
def initialize(filename, basename, connection, now)
|
6
|
+
@filename = filename
|
7
|
+
@connection = connection
|
8
|
+
@now = now
|
9
|
+
|
10
|
+
@class_name = basename.classify
|
11
|
+
begin
|
12
|
+
@klass = @class_name.constantize
|
13
|
+
@klass = nil unless @klass < ActiveRecord::Base
|
14
|
+
rescue NameError
|
15
|
+
ActiveRecord::Base.logger.warn "couldn't load #{class_name} for fixture table #{table_name}: #{$!}"
|
16
|
+
end
|
17
|
+
|
18
|
+
if @klass
|
19
|
+
@table_name = @klass.table_name
|
20
|
+
@primary_key = @klass.primary_key
|
21
|
+
@record_timestamps = @klass.record_timestamps
|
22
|
+
@inheritance_column = @klass.inheritance_column
|
23
|
+
else
|
24
|
+
@table_name = basename.gsub('/', '_')
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def columns_hash
|
29
|
+
@columns_hash ||= connection.columns(table_name).index_by(&:name)
|
30
|
+
end
|
31
|
+
|
32
|
+
def content
|
33
|
+
template = File.read(filename)
|
34
|
+
render_context = ActiveRecord::FixtureSet::RenderContext.create_subclass.new.get_binding
|
35
|
+
ERB.new(template).result(render_context)
|
36
|
+
end
|
37
|
+
|
38
|
+
def parsed_rows
|
39
|
+
result = YAML.load(content)
|
40
|
+
result ||= {} # for completely empty files
|
41
|
+
|
42
|
+
unless (result.is_a?(Hash) || result.is_a?(YAML::Omap)) && result.all? { |name, attributes| name.is_a?(String) && attributes.is_a?(Hash) }
|
43
|
+
raise ActiveRecord::Fixture::FormatError, "#{filename} needs to contain a hash of fixtures"
|
44
|
+
end
|
45
|
+
|
46
|
+
result.delete('DEFAULTS')
|
47
|
+
result
|
48
|
+
rescue ArgumentError, Psych::SyntaxError => error
|
49
|
+
# we use exactly the same error class and message as ActiveRecord::FixtureSet in case anyone was depending on it
|
50
|
+
raise ActiveRecord::Fixture::FormatError, "a YAML error occurred parsing #{filename}. Please note that YAML must be consistently indented using spaces. Tabs are not allowed. Please have a look at http://www.yaml.org/faq.html\nThe exact error was:\n #{error.class}: #{error}", error.backtrace
|
51
|
+
end
|
52
|
+
|
53
|
+
def embellished_rows
|
54
|
+
@embellished_rows ||= parsed_rows.each do |name, attributes|
|
55
|
+
embellish_fixture(name, attributes, columns_hash)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def embellish_fixture(name, attributes, columns_hash)
|
60
|
+
# populate the primary key column, if not already set
|
61
|
+
if @primary_key && columns_hash[@primary_key] && !attributes.has_key?(@primary_key)
|
62
|
+
attributes[@primary_key] = Fixation.identify(name, columns_hash[@primary_key].type)
|
63
|
+
end
|
64
|
+
|
65
|
+
# substitute $LABEL into all string values
|
66
|
+
attributes.each do |column_name, value|
|
67
|
+
attributes[column_name] = value.gsub("$LABEL", name) if value.is_a?(String)
|
68
|
+
end
|
69
|
+
|
70
|
+
# populate any timestamp columns, if not already set
|
71
|
+
if @record_timestamps
|
72
|
+
%w(created_at updated_at).each do |column_name|
|
73
|
+
attributes[column_name] = now if columns_hash[column_name] && !attributes.has_key?(column_name)
|
74
|
+
end
|
75
|
+
%w(created_at updated_at).each do |column_name|
|
76
|
+
attributes[column_name] = now.to_date if columns_hash[column_name] && !attributes.has_key?(column_name)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# convert enum names to values
|
81
|
+
@klass.defined_enums.each do |name, values|
|
82
|
+
attributes[name] = values.fetch(attributes[name], attributes[name]) if attributes.has_key?(name)
|
83
|
+
end if @klass.respond_to?(:defined_enums)
|
84
|
+
|
85
|
+
# convert any association names into the identity column equivalent - following code from activerecord's fixtures.rb
|
86
|
+
nonexistant_columns = attributes.keys - columns_hash.keys
|
87
|
+
|
88
|
+
if @klass && nonexistant_columns.present?
|
89
|
+
# If STI is used, find the correct subclass for association reflection
|
90
|
+
reflection_class =
|
91
|
+
if attributes.include?(@inheritance_column)
|
92
|
+
attributes[@inheritance_column].constantize rescue @klass
|
93
|
+
else
|
94
|
+
@klass
|
95
|
+
end
|
96
|
+
|
97
|
+
nonexistant_columns.each do |column_name|
|
98
|
+
association = reflection_class.reflect_on_association(column_name)
|
99
|
+
|
100
|
+
if association.nil?
|
101
|
+
raise ActiveRecord::Fixture::FormatError, "No column named #{column_name} found in table #{table_name}"
|
102
|
+
elsif association.macro != :belongs_to
|
103
|
+
raise ActiveRecord::Fixture::FormatError, "Association #{column_name} in table #{table_name} has type #{association.macro}, which is not currently supported"
|
104
|
+
else
|
105
|
+
value = attributes.delete(column_name)
|
106
|
+
|
107
|
+
if association.options[:polymorphic] && value.is_a?(String) && value.sub!(/\s*\(([^\)]*)\)\s*$/, "")
|
108
|
+
# support polymorphic belongs_to as "label (Type)"
|
109
|
+
attributes[association.foreign_type] = $1
|
110
|
+
end
|
111
|
+
|
112
|
+
fk_name = (association.options[:foreign_key] || "#{association.name}_id").to_s
|
113
|
+
attributes[fk_name] = value ? ActiveRecord::FixtureSet.identify(value) : value
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def fixture_ids
|
120
|
+
embellished_rows.each_with_object({}) do |(name, attributes), ids|
|
121
|
+
ids[name] = attributes['id'] || attributes['uuid']
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def statements
|
126
|
+
statements = ["DELETE FROM #{connection.quote_table_name table_name}"]
|
127
|
+
|
128
|
+
unless embellished_rows.empty?
|
129
|
+
# first figure out what columns we have to insert into; we're going to need to use the same names for
|
130
|
+
# all rows so we can use the multi-line INSERT syntax
|
131
|
+
columns_to_include = Set.new
|
132
|
+
embellished_rows.each do |name, attributes|
|
133
|
+
attributes.each do |column_name, value|
|
134
|
+
raise ActiveRecord::Fixture::FormatError, "No column named #{column_name.inspect} found in table #{table_name.inspect} (attribute on fixture #{name.inspect})" unless columns_hash[column_name]
|
135
|
+
columns_to_include.add(columns_hash[column_name])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# now build the INSERT statement
|
140
|
+
quoted_column_names = columns_to_include.collect { |column| connection.quote_column_name(column.name) }.join(', ')
|
141
|
+
statements <<
|
142
|
+
"INSERT INTO #{connection.quote_table_name table_name} (#{quoted_column_names}) VALUES " +
|
143
|
+
embellished_rows.collect do |name, attributes|
|
144
|
+
'(' + columns_to_include.collect do |column|
|
145
|
+
if attributes.has_key?(column.name)
|
146
|
+
quote_value(column, attributes[column.name])
|
147
|
+
else
|
148
|
+
column.default_function || quote_value(column, column.default)
|
149
|
+
end
|
150
|
+
end.join(', ') + ')'
|
151
|
+
end.join(', ')
|
152
|
+
end
|
153
|
+
|
154
|
+
statements
|
155
|
+
end
|
156
|
+
|
157
|
+
def quote_value(column, value)
|
158
|
+
connection.quote(value)
|
159
|
+
rescue TypeError
|
160
|
+
connection.quote(YAML.dump(value))
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Fixation
|
2
|
+
class Fixtures
|
3
|
+
def initialize
|
4
|
+
@class_names = {}
|
5
|
+
@fixture_ids = {}
|
6
|
+
@statements = {}
|
7
|
+
|
8
|
+
compile_fixture_files
|
9
|
+
end
|
10
|
+
|
11
|
+
def compile_fixture_files(connection = ActiveRecord::Base.connection)
|
12
|
+
puts "#{Time.now} building fixtures" if Fixation.trace
|
13
|
+
|
14
|
+
now = ActiveRecord::Base.default_timezone == :utc ? Time.now.utc : Time.now
|
15
|
+
Fixation.paths.each do |path|
|
16
|
+
Dir["#{path}/{**,*}/*.yml"].each do |pathname|
|
17
|
+
basename = pathname[path.size + 1..-5]
|
18
|
+
compile_fixture_file(pathname, basename, connection, now) if ::File.file?(pathname)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
puts "#{Time.now} built fixtures for #{@fixture_ids.size} tables" if Fixation.trace
|
23
|
+
end
|
24
|
+
|
25
|
+
def compile_fixture_file(filename, basename, connection, now)
|
26
|
+
fixture_table = FixtureTable.new(filename, basename, connection, now)
|
27
|
+
fixture_name = basename.gsub('/', '_')
|
28
|
+
@fixture_ids[fixture_name] = fixture_table.fixture_ids
|
29
|
+
@statements[fixture_name] = fixture_table.statements
|
30
|
+
@class_names[fixture_name] = fixture_table.class_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def apply_fixtures(connection = ActiveRecord::Base.connection)
|
34
|
+
connection.disable_referential_integrity do
|
35
|
+
connection.transaction do
|
36
|
+
apply_fixture_statements(connection)
|
37
|
+
clear_other_tables(connection) if Fixation.clear_other_tables
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def apply_fixture_statements(connection)
|
43
|
+
@statements.each do |table_name, table_statements|
|
44
|
+
table_statements.each do |statement|
|
45
|
+
connection.execute(statement)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def clear_other_tables(connection)
|
51
|
+
(connection.tables - Fixation.tables_not_to_clear - @statements.keys).each do |table_name|
|
52
|
+
connection.execute("DELETE FROM #{connection.quote_table_name table_name}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def fixture_methods
|
57
|
+
fixture_ids = @fixture_ids
|
58
|
+
class_names = @class_names
|
59
|
+
|
60
|
+
methods = Module.new do
|
61
|
+
def setup_fixtures(config = ActiveRecord::Base)
|
62
|
+
if run_in_transaction?
|
63
|
+
@@fixated_fixtures_applied ||= false
|
64
|
+
unless @@fixated_fixtures_applied
|
65
|
+
puts "#{Time.now} applying fixtures" if Fixation.trace
|
66
|
+
Fixation.apply_fixtures
|
67
|
+
@@fixated_fixtures_applied = true
|
68
|
+
puts "#{Time.now} applied fixtures" if Fixation.trace
|
69
|
+
end
|
70
|
+
else
|
71
|
+
@@fixated_fixtures_applied = false
|
72
|
+
end
|
73
|
+
super
|
74
|
+
end
|
75
|
+
|
76
|
+
fixture_ids.each do |fixture_name, fixtures|
|
77
|
+
begin
|
78
|
+
klass = class_names[fixture_name].constantize
|
79
|
+
rescue NameError
|
80
|
+
next
|
81
|
+
end
|
82
|
+
|
83
|
+
define_method(fixture_name) do |*fixture_names|
|
84
|
+
force_reload = fixture_names.pop if fixture_names.last == true || fixture_names.last == :reload
|
85
|
+
|
86
|
+
@fixture_cache[fixture_name] ||= {}
|
87
|
+
|
88
|
+
instances = fixture_names.map do |name|
|
89
|
+
id = fixtures[name.to_s]
|
90
|
+
raise StandardError, "No fixture named '#{name}' found for fixture set '#{fixture_name}'" if id.nil?
|
91
|
+
|
92
|
+
@fixture_cache[fixture_name].delete(name) if force_reload
|
93
|
+
@fixture_cache[fixture_name][name] ||= klass.find(id)
|
94
|
+
end
|
95
|
+
|
96
|
+
instances.size == 1 ? instances.first : instances
|
97
|
+
end
|
98
|
+
private fixture_name
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/fixation/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fixation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Will Bryant
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-08-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -57,6 +57,8 @@ files:
|
|
57
57
|
- bin/setup
|
58
58
|
- fixation.gemspec
|
59
59
|
- lib/fixation.rb
|
60
|
+
- lib/fixation/fixture_table.rb
|
61
|
+
- lib/fixation/fixtures.rb
|
60
62
|
- lib/fixation/version.rb
|
61
63
|
homepage: https://github.com/willbryant/fixation
|
62
64
|
licenses:
|
@@ -78,7 +80,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
80
|
version: '0'
|
79
81
|
requirements: []
|
80
82
|
rubyforge_project:
|
81
|
-
rubygems_version: 2.
|
83
|
+
rubygems_version: 2.5.1
|
82
84
|
signing_key:
|
83
85
|
specification_version: 4
|
84
86
|
summary: 10x faster fixture startup under spring.
|