myronmarston-factory_data_preloader 0.3.2 → 0.4.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.
- data/VERSION.yml +2 -2
- data/lib/factory_data_preloader/factory_data.rb +3 -3
- data/lib/factory_data_preloader/preloader.rb +38 -26
- data/lib/factory_data_preloader/preloader_collection.rb +30 -0
- data/lib/factory_data_preloader/rails_core_ext.rb +6 -0
- data/lib/factory_data_preloader.rb +1 -0
- data/test/factory_data_test.rb +1 -1
- data/test/preloader_test.rb +40 -3
- data/test/test_helper.rb +22 -13
- metadata +3 -2
data/VERSION.yml
CHANGED
@@ -17,7 +17,7 @@ module FactoryDataPreloader
|
|
17
17
|
attr_accessor :definition_file_paths
|
18
18
|
|
19
19
|
def preload(model_type, options = {}, &proc)
|
20
|
-
raise PreloaderAlreadyDefinedError.new, "You have already defined the preloader for #{model_type.to_s}" if
|
20
|
+
raise PreloaderAlreadyDefinedError.new, "You have already defined the preloader for #{model_type.to_s}" if AllPreloaders.instance.map(&:model_type).include?(model_type)
|
21
21
|
|
22
22
|
model_class = options[:model_class] || model_type.to_s.singularize.classify.constantize
|
23
23
|
depends_on = [options[:depends_on]].compact.flatten
|
@@ -35,7 +35,7 @@ module FactoryDataPreloader
|
|
35
35
|
return unless @@preloaded_data_deleted.nil?
|
36
36
|
|
37
37
|
# Delete them in the reverse order of the dependencies, to handle foreign keys
|
38
|
-
|
38
|
+
FactoryDataPreloader.requested_preloaders.reverse.each do |preloader|
|
39
39
|
preloader.model_class.delete_all
|
40
40
|
end
|
41
41
|
|
@@ -46,7 +46,7 @@ module FactoryDataPreloader
|
|
46
46
|
return unless @@preloaded_cache.nil? # make sure the data is only preloaded once.
|
47
47
|
@@preloaded_cache = {}
|
48
48
|
|
49
|
-
|
49
|
+
FactoryDataPreloader.requested_preloaders.dependency_order.each do |preloader|
|
50
50
|
cache = @@preloaded_cache[preloader.model_type] ||= {}
|
51
51
|
preloader.data.each do |key, record|
|
52
52
|
if record.new_record? && !record.save
|
@@ -1,49 +1,61 @@
|
|
1
1
|
module FactoryDataPreloader
|
2
2
|
class PreloaderNotDefinedError < StandardError; end
|
3
3
|
|
4
|
+
mattr_accessor :preload_all
|
5
|
+
self.preload_all = true
|
6
|
+
|
7
|
+
mattr_accessor :preload_types
|
8
|
+
self.preload_types = []
|
9
|
+
|
10
|
+
class << self
|
11
|
+
alias :preload_all? :preload_all
|
12
|
+
|
13
|
+
def requested_preloaders
|
14
|
+
@requested_preloaders ||= begin
|
15
|
+
if preload_all?
|
16
|
+
AllPreloaders.instance
|
17
|
+
else
|
18
|
+
preloaders = self.preload_types.collect { |type| AllPreloaders.instance.from_symbol(type) }
|
19
|
+
preloaders += (preloaders.collect { |p| p.all_dependencies }).flatten
|
20
|
+
preloaders.uniq!
|
21
|
+
PreloaderCollection.new(preloaders)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
4
27
|
class Preloader
|
5
28
|
attr_accessor :model_type, :model_class, :proc, :depends_on
|
6
29
|
|
7
30
|
def initialize(model_type, model_class, proc, depends_on)
|
8
31
|
@model_type, @model_class, @proc, @depends_on = model_type, model_class, proc, depends_on || []
|
9
|
-
|
32
|
+
AllPreloaders.instance << self
|
10
33
|
end
|
11
34
|
|
12
35
|
def data
|
13
36
|
@data ||= begin
|
14
|
-
data =
|
15
|
-
|
37
|
+
data = PreloaderDataHash.new
|
38
|
+
print "Preloading #{model_type}:"
|
39
|
+
benchmark_measurement = Benchmark.measure { self.proc.try(:call, data) }
|
40
|
+
print "(#{format('%.3f', benchmark_measurement.real)} secs)\n"
|
16
41
|
data
|
17
42
|
end
|
18
43
|
end
|
19
44
|
|
20
45
|
def dependencies
|
21
|
-
@dependencies ||=
|
22
|
-
self.depends_on.collect do |dependency|
|
23
|
-
preloader = PreloaderCollection.instance.detect { |p| p.model_type == dependency }
|
24
|
-
raise PreloaderNotDefinedError, "The preloader for :#{dependency} has not been defined." unless preloader
|
25
|
-
preloader
|
26
|
-
end
|
27
|
-
end
|
46
|
+
@dependencies ||= self.depends_on.collect { |dependency| AllPreloaders.instance.from_symbol(dependency) }
|
28
47
|
end
|
29
|
-
end
|
30
48
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
unordered_preloaders = Array.new(self) # rather than using self.dup since singleton doesn't allow duping.
|
36
|
-
ordered_preloaders = []
|
37
|
-
|
38
|
-
until unordered_preloaders.empty?
|
39
|
-
unordered_preloaders.each do |preloader|
|
40
|
-
if preloader.dependencies.all? { |dependency| ordered_preloaders.include?(dependency) }
|
41
|
-
ordered_preloaders << unordered_preloaders.delete(preloader)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
49
|
+
def all_dependencies
|
50
|
+
@all_dependencies ||= (self.dependencies + (self.dependencies.collect { |d| d.all_dependencies }).flatten).uniq
|
51
|
+
end
|
52
|
+
end
|
45
53
|
|
46
|
-
|
54
|
+
class PreloaderDataHash < Hash
|
55
|
+
def []=(key, value)
|
56
|
+
print "."
|
57
|
+
super
|
47
58
|
end
|
48
59
|
end
|
60
|
+
|
49
61
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module FactoryDataPreloader
|
2
|
+
class PreloaderCollection < Array
|
3
|
+
def dependency_order
|
4
|
+
unordered_preloaders = Array.new(self) # rather than using self.dup since singleton doesn't allow duping.
|
5
|
+
ordered_preloaders = []
|
6
|
+
|
7
|
+
until unordered_preloaders.empty?
|
8
|
+
unordered_preloaders.each do |preloader|
|
9
|
+
if preloader.dependencies.all? { |dependency| ordered_preloaders.include?(dependency) }
|
10
|
+
ordered_preloaders << unordered_preloaders.delete(preloader)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
ordered_preloaders
|
16
|
+
end
|
17
|
+
|
18
|
+
def from_symbol(symbol)
|
19
|
+
unless preloader = self.detect { |p| p.model_type == symbol }
|
20
|
+
raise PreloaderNotDefinedError, "The preloader for :#{symbol} has not been defined."
|
21
|
+
end
|
22
|
+
preloader
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class AllPreloaders < PreloaderCollection
|
27
|
+
include Singleton
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -30,4 +30,10 @@ class Fixtures
|
|
30
30
|
end
|
31
31
|
|
32
32
|
alias_method_chain :delete_existing_fixtures, :preloaded_factory_data
|
33
|
+
end
|
34
|
+
|
35
|
+
class ActiveSupport::TestCase
|
36
|
+
def self.preload_factory_data(*types)
|
37
|
+
types.each { |t| FactoryDataPreloader.preload_types << t }
|
38
|
+
end
|
33
39
|
end
|
@@ -13,6 +13,7 @@ require 'active_record/fixtures'
|
|
13
13
|
|
14
14
|
require 'factory_data_preloader/core_ext'
|
15
15
|
require 'factory_data_preloader/preloader'
|
16
|
+
require 'factory_data_preloader/preloader_collection'
|
16
17
|
require 'factory_data_preloader/factory_data'
|
17
18
|
require 'factory_data_preloader/rails_core_ext'
|
18
19
|
|
data/test/factory_data_test.rb
CHANGED
data/test/preloader_test.rb
CHANGED
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/test_helper'
|
|
2
2
|
|
3
3
|
class PreloaderTest < Test::Unit::TestCase
|
4
4
|
def setup
|
5
|
-
FactoryDataPreloader
|
5
|
+
FactoryDataPreloader.reset!
|
6
6
|
end
|
7
7
|
|
8
8
|
context 'A new preloader' do
|
@@ -21,7 +21,7 @@ class PreloaderTest < Test::Unit::TestCase
|
|
21
21
|
end
|
22
22
|
|
23
23
|
should 'be automatically added to the PreloaderCollection' do
|
24
|
-
assert_equal [@preloader], FactoryDataPreloader::
|
24
|
+
assert_equal [@preloader], FactoryDataPreloader::AllPreloaders.instance
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
@@ -59,7 +59,44 @@ class PreloaderTest < Test::Unit::TestCase
|
|
59
59
|
|
60
60
|
should 'sort correctly for PreloaderCollection.instance.dependency_order' do
|
61
61
|
expected = [@ip_addresses, @users, @posts, @post_images, @post_image_ratings]
|
62
|
-
assert_equal expected.map(&:model_type), FactoryDataPreloader::
|
62
|
+
assert_equal expected.map(&:model_type), FactoryDataPreloader::AllPreloaders.instance.dependency_order.map(&:model_type)
|
63
|
+
end
|
64
|
+
|
65
|
+
should 'return the correct preloader objects for #all_dependencies' do
|
66
|
+
assert_same_elements [@post_images, @posts, @users], @post_image_ratings.all_dependencies
|
67
|
+
assert_same_elements [@posts, @users], @post_images.all_dependencies
|
68
|
+
assert_same_elements [], @ip_addresses.all_dependencies
|
69
|
+
assert_same_elements [@users], @posts.all_dependencies
|
70
|
+
assert_same_elements [], @users.all_dependencies
|
71
|
+
end
|
72
|
+
|
73
|
+
context 'when FactoryDataPreloader.preload_all = true' do
|
74
|
+
setup do
|
75
|
+
FactoryDataPreloader.preload_all = true
|
76
|
+
end
|
77
|
+
|
78
|
+
should 'return all preloaders for FactoryDataPreloader.requested_preloaders' do
|
79
|
+
expected = [@ip_addresses, @users, @posts, @post_images, @post_image_ratings]
|
80
|
+
assert_equal expected.map(&:model_type), FactoryDataPreloader.requested_preloaders.dependency_order.map(&:model_type)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'when FactoryDataPreloader.preload_all = false' do
|
85
|
+
setup do
|
86
|
+
FactoryDataPreloader.preload_all = false
|
87
|
+
end
|
88
|
+
|
89
|
+
should 'return no preloaders when for FactoryDataPreloader.requested_preloaders when preload_types is empty' do
|
90
|
+
assert_equal [], FactoryDataPreloader.preload_types
|
91
|
+
assert_equal [], FactoryDataPreloader.requested_preloaders
|
92
|
+
end
|
93
|
+
|
94
|
+
should 'return just the requested preloaders for FactoryDataPreloader.requested_preloaders' do
|
95
|
+
FactoryDataPreloader.preload_types << :post_images
|
96
|
+
FactoryDataPreloader.preload_types << :ip_addresses
|
97
|
+
expected = [@ip_addresses, @users, @posts, @post_images]
|
98
|
+
assert_equal expected.map(&:model_type), FactoryDataPreloader.requested_preloaders.dependency_order.map(&:model_type)
|
99
|
+
end
|
63
100
|
end
|
64
101
|
end
|
65
102
|
end
|
data/test/test_helper.rb
CHANGED
@@ -38,23 +38,32 @@ module OutputCapturer
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
|
42
|
-
# helper method to reset the factory data between test runs.
|
41
|
+
module FactoryDataPreloader
|
43
42
|
def self.reset!
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
43
|
+
self.preload_all = true
|
44
|
+
self.preload_types = []
|
45
|
+
@requested_preloaders = nil
|
46
|
+
FactoryData.reset!
|
47
|
+
end
|
48
|
+
|
49
|
+
class FactoryData
|
50
|
+
# helper method to reset the factory data between test runs.
|
51
|
+
def self.reset!
|
52
|
+
FactoryDataPreloader::AllPreloaders.instance.each do |preloader|
|
53
|
+
class << self; self; end.class_eval do
|
54
|
+
remove_method(preloader.model_type) if method_defined?(preloader.model_type)
|
55
|
+
end
|
48
56
|
|
49
|
-
|
50
|
-
|
57
|
+
unless @@preloaded_cache.nil?
|
58
|
+
preloader.model_class.delete_all(:id => (@@preloaded_cache[preloader.model_type] || {}).values)
|
59
|
+
end
|
51
60
|
end
|
52
|
-
end
|
53
61
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
62
|
+
@@preloaded_cache = nil
|
63
|
+
@@preloaded_data_deleted = nil
|
64
|
+
@@single_test_cache = {}
|
65
|
+
FactoryDataPreloader::AllPreloaders.instance.clear
|
66
|
+
end
|
58
67
|
end
|
59
68
|
end
|
60
69
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: myronmarston-factory_data_preloader
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Myron Marston
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-06-01 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -29,6 +29,7 @@ files:
|
|
29
29
|
- lib/factory_data_preloader/core_ext.rb
|
30
30
|
- lib/factory_data_preloader/factory_data.rb
|
31
31
|
- lib/factory_data_preloader/preloader.rb
|
32
|
+
- lib/factory_data_preloader/preloader_collection.rb
|
32
33
|
- lib/factory_data_preloader/rails_core_ext.rb
|
33
34
|
- lib/factory_data_preloader.rb
|
34
35
|
- test/factory_data_test.rb
|