fixation 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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.
|