forked from kylejginavan/factory_data_preloader
/
preloader.rb
94 lines (73 loc) · 2.96 KB
/
preloader.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
require 'active_support/deprecation'
module FactoryDataPreloader
class PreloaderNotDefinedError < StandardError; end
mattr_accessor :preload_all
self.preload_all = true
mattr_accessor :preload_types
self.preload_types = []
class << self
alias :preload_all? :preload_all
def requested_preloaders
if preload_all?
AllPreloaders.instance
else
preloaders = self.preload_types.collect { |type| AllPreloaders.instance.from_symbol(type) }
preloaders += (preloaders.collect { |p| p.all_dependencies }).flatten
preloaders.uniq!
PreloaderCollection.new(preloaders)
end
end
end
class Preloader
attr_accessor :model_type, :model_class, :proc, :depends_on
attr_reader :data
def initialize(model_type, model_class, proc, depends_on)
model_class ||= model_type.to_s.pluralize.classify.constantize
@model_type, @model_class, @proc, @depends_on = model_type, model_class, proc, [depends_on].compact.flatten
AllPreloaders.instance << self
DataMethods.class_eval do
define_method model_type do |key|
FactoryData.send(:get_record, model_type, key)
end
end
end
def preload!
@data = PreloadedDataHash.new(self)
print "Preloading #{model_type}:"
benchmark_measurement = Benchmark.measure { self.proc.try(:call, @data) }
print "(#{format('%.3f', benchmark_measurement.real)} secs)\n"
end
def preloaded?
!@data.nil?
end
def dependencies
self.depends_on.collect { |dependency| AllPreloaders.instance.from_symbol(dependency) }
end
def all_dependencies
(self.dependencies + (self.dependencies.collect { |d| d.all_dependencies }).flatten).uniq
end
def get_record(key)
unless self.preloaded?
raise DefinedPreloaderNotRunError.new, "The :#{self.model_type} preloader has never been run. Did you forget to add the 'preload_factory_data :#{self.model_type}' declaration to your test case? You'll need this at the top of your test case class if you want to use the factory data defined by this preloader."
end
unless record_id_or_error = self.data[key]
raise PreloadedRecordNotFound.new, "Could not find a preloaded record #{self.model_type} recore for :#{key}. Did you mispell :#{key}?"
end
if record_id_or_error.is_a?(Exception)
raise ErrorWhilePreloadingRecord.new, "An error occurred while preloading #{self.model_type}(:#{key}): #{record_id_or_error.class.to_s}: #{record_id_or_error.message}\n\nBacktrace:\n\n#{record_id_or_error.backtrace}"
end
self.model_class.find_by_id(record_id_or_error)
end
def remove!
preloader = self
DataMethods.class_eval do
remove_method(preloader.model_type) if method_defined?(preloader.model_type)
end
if @data
self.model_class.delete_all(:id => @data.record_ids)
@data = nil
end
AllPreloaders.instance.delete(self)
end
end
end