myronmarston-factory_data_preloader 0.3.1 → 0.3.2
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 +1 -1
- data/lib/factory_data_preloader/factory_data.rb +16 -18
- data/lib/factory_data_preloader/preloader.rb +35 -13
- data/test/lib/models.rb +14 -0
- data/test/lib/schema.rb +21 -0
- data/test/preloader_test.rb +42 -20
- data/test/test_helper.rb +6 -6
- metadata +2 -2
data/VERSION.yml
CHANGED
@@ -8,21 +8,20 @@ module FactoryDataPreloader
|
|
8
8
|
@@preloaded_cache = nil
|
9
9
|
@@preloaded_data_deleted = nil
|
10
10
|
@@single_test_cache = {}
|
11
|
-
|
12
|
-
|
11
|
+
|
13
12
|
class << self
|
14
13
|
# An Array of strings specifying locations that should be searched for
|
15
14
|
# factory_data definitions. By default, factory_data_preloader will attempt to require
|
16
15
|
# "factory_data," "test/factory_data," and "spec/factory_data." Only the first
|
17
16
|
# existing file will be loaded.
|
18
17
|
attr_accessor :definition_file_paths
|
19
|
-
|
18
|
+
|
20
19
|
def preload(model_type, options = {}, &proc)
|
21
|
-
raise PreloaderAlreadyDefinedError.new, "You have already defined the preloader for #{model_type.to_s}" if
|
22
|
-
|
20
|
+
raise PreloaderAlreadyDefinedError.new, "You have already defined the preloader for #{model_type.to_s}" if PreloaderCollection.instance.map(&:model_type).include?(model_type)
|
21
|
+
|
23
22
|
model_class = options[:model_class] || model_type.to_s.singularize.classify.constantize
|
24
23
|
depends_on = [options[:depends_on]].compact.flatten
|
25
|
-
|
24
|
+
FactoryDataPreloader::Preloader.new(model_type, model_class, proc, depends_on)
|
26
25
|
|
27
26
|
class << self; self; end.class_eval do
|
28
27
|
define_method model_type do |key|
|
@@ -34,21 +33,20 @@ module FactoryDataPreloader
|
|
34
33
|
def delete_preload_data!
|
35
34
|
# make sure this only runs once...
|
36
35
|
return unless @@preloaded_data_deleted.nil?
|
37
|
-
|
38
|
-
# the
|
39
|
-
|
40
|
-
@@preloaders.sort.reverse.each do |preloader|
|
36
|
+
|
37
|
+
# Delete them in the reverse order of the dependencies, to handle foreign keys
|
38
|
+
PreloaderCollection.instance.dependency_order.reverse.each do |preloader|
|
41
39
|
preloader.model_class.delete_all
|
42
40
|
end
|
43
|
-
|
41
|
+
|
44
42
|
@@preloaded_data_deleted = true
|
45
43
|
end
|
46
44
|
|
47
45
|
def preload_data!
|
48
46
|
return unless @@preloaded_cache.nil? # make sure the data is only preloaded once.
|
49
47
|
@@preloaded_cache = {}
|
50
|
-
|
51
|
-
|
48
|
+
|
49
|
+
PreloaderCollection.instance.dependency_order.each do |preloader|
|
52
50
|
cache = @@preloaded_cache[preloader.model_type] ||= {}
|
53
51
|
preloader.data.each do |key, record|
|
54
52
|
if record.new_record? && !record.save
|
@@ -57,16 +55,16 @@ module FactoryDataPreloader
|
|
57
55
|
puts "\n\n"
|
58
56
|
next
|
59
57
|
end
|
60
|
-
|
58
|
+
|
61
59
|
cache[key] = record.id
|
62
60
|
end
|
63
61
|
end
|
64
62
|
end
|
65
|
-
|
63
|
+
|
66
64
|
def reset_cache!
|
67
65
|
@@single_test_cache = {}
|
68
66
|
end
|
69
|
-
|
67
|
+
|
70
68
|
def find_definitions
|
71
69
|
definition_file_paths.each do |path|
|
72
70
|
require("#{path}.rb") if File.exists?("#{path}.rb")
|
@@ -89,7 +87,7 @@ module FactoryDataPreloader
|
|
89
87
|
record
|
90
88
|
end
|
91
89
|
end
|
92
|
-
|
90
|
+
|
93
91
|
# Borrowed from shoulda: http://github.com/thoughtbot/shoulda/blob/e02228d45a879ff92cb72b84f5fccc6a5f856a65/lib/shoulda/active_record/helpers.rb#L4-9
|
94
92
|
def pretty_error_messages(obj)
|
95
93
|
obj.errors.map do |a, m|
|
@@ -98,7 +96,7 @@ module FactoryDataPreloader
|
|
98
96
|
end
|
99
97
|
end
|
100
98
|
end
|
101
|
-
|
99
|
+
|
102
100
|
self.definition_file_paths = %w(factory_data test/factory_data spec/factory_data)
|
103
101
|
end
|
104
102
|
end
|
@@ -1,11 +1,14 @@
|
|
1
1
|
module FactoryDataPreloader
|
2
|
+
class PreloaderNotDefinedError < StandardError; end
|
3
|
+
|
2
4
|
class Preloader
|
3
|
-
attr_accessor :model_type, :model_class, :proc, :
|
4
|
-
|
5
|
-
def initialize(model_type, model_class, proc,
|
6
|
-
@model_type, @model_class, @proc, @
|
5
|
+
attr_accessor :model_type, :model_class, :proc, :depends_on
|
6
|
+
|
7
|
+
def initialize(model_type, model_class, proc, depends_on)
|
8
|
+
@model_type, @model_class, @proc, @depends_on = model_type, model_class, proc, depends_on || []
|
9
|
+
PreloaderCollection.instance << self
|
7
10
|
end
|
8
|
-
|
11
|
+
|
9
12
|
def data
|
10
13
|
@data ||= begin
|
11
14
|
data = {}
|
@@ -13,15 +16,34 @@ module FactoryDataPreloader
|
|
13
16
|
data
|
14
17
|
end
|
15
18
|
end
|
16
|
-
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
|
20
|
+
def dependencies
|
21
|
+
@dependencies ||= begin
|
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
|
24
27
|
end
|
25
28
|
end
|
26
29
|
end
|
30
|
+
|
31
|
+
class PreloaderCollection < Array
|
32
|
+
include Singleton
|
33
|
+
|
34
|
+
def dependency_order
|
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
|
45
|
+
|
46
|
+
ordered_preloaders
|
47
|
+
end
|
48
|
+
end
|
27
49
|
end
|
data/test/lib/models.rb
CHANGED
@@ -6,9 +6,23 @@ end
|
|
6
6
|
|
7
7
|
class Post < ActiveRecord::Base
|
8
8
|
belongs_to :user
|
9
|
+
has_many :comments
|
10
|
+
has_many :post_images
|
9
11
|
end
|
10
12
|
|
11
13
|
class Comment < ActiveRecord::Base
|
12
14
|
belongs_to :post
|
13
15
|
belongs_to :user
|
16
|
+
end
|
17
|
+
|
18
|
+
class PostImage < ActiveRecord::Base
|
19
|
+
belongs_to :post
|
20
|
+
has_many :post_image_ratings
|
21
|
+
end
|
22
|
+
|
23
|
+
class PostImageRating < ActiveRecord::Base
|
24
|
+
belongs_to :post_image
|
25
|
+
end
|
26
|
+
|
27
|
+
class IpAddress < ActiveRecord::Base
|
14
28
|
end
|
data/test/lib/schema.rb
CHANGED
@@ -24,4 +24,25 @@ OutputCapturer.capture do
|
|
24
24
|
t.timestamps
|
25
25
|
end
|
26
26
|
end
|
27
|
+
|
28
|
+
ActiveRecord::Schema.define do
|
29
|
+
create_table :post_images, :force => true do |t|
|
30
|
+
t.references :post
|
31
|
+
t.timestamps
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
ActiveRecord::Schema.define do
|
36
|
+
create_table :post_image_ratings, :force => true do |t|
|
37
|
+
t.references :post_image
|
38
|
+
t.timestamps
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
ActiveRecord::Schema.define do
|
43
|
+
create_table :ip_addresses, :force => true do |t|
|
44
|
+
t.string :ip_address
|
45
|
+
t.timestamps
|
46
|
+
end
|
47
|
+
end
|
27
48
|
end
|
data/test/preloader_test.rb
CHANGED
@@ -1,43 +1,65 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class PreloaderTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
FactoryDataPreloader::PreloaderCollection.instance.clear
|
6
|
+
end
|
7
|
+
|
4
8
|
context 'A new preloader' do
|
5
9
|
setup do
|
6
|
-
proc = lambda { |data|
|
10
|
+
proc = lambda { |data|
|
7
11
|
data[:thom] = User.create(:first_name => 'Thom', :last_name => 'York')
|
8
12
|
data[:john] = User.create(:first_name => 'John', :last_name => 'Doe')
|
9
13
|
}
|
10
|
-
@preloader = FactoryDataPreloader::Preloader.new(:users, User, proc,
|
14
|
+
@preloader = FactoryDataPreloader::Preloader.new(:users, User, proc, [])
|
11
15
|
end
|
12
|
-
|
16
|
+
|
13
17
|
should 'return the preloaded data for #data' do
|
14
18
|
data = @preloader.data
|
15
19
|
assert_equal 'York', data[:thom].last_name
|
16
20
|
assert_equal 'Doe', data[:john].last_name
|
17
21
|
end
|
22
|
+
|
23
|
+
should 'be automatically added to the PreloaderCollection' do
|
24
|
+
assert_equal [@preloader], FactoryDataPreloader::PreloaderCollection.instance
|
25
|
+
end
|
18
26
|
end
|
19
|
-
|
20
|
-
context '
|
27
|
+
|
28
|
+
context 'A preloader with dependencies' do
|
21
29
|
setup do
|
22
|
-
@
|
23
|
-
@users = FactoryDataPreloader::Preloader.new(:users, User, nil, 1, [])
|
30
|
+
@comments = FactoryDataPreloader::Preloader.new(:comments, Comment, nil, [:users, :posts])
|
24
31
|
end
|
25
|
-
|
26
|
-
should '
|
27
|
-
|
28
|
-
|
32
|
+
|
33
|
+
should 'raise PreloaderNotDefinedError for #dependencies if the preloader it depends on are not defined' do
|
34
|
+
assert_raise FactoryDataPreloader::PreloaderNotDefinedError do
|
35
|
+
@comments.dependencies
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context 'when the dependency preloaders have also been defined' do
|
40
|
+
setup do
|
41
|
+
@posts = FactoryDataPreloader::Preloader.new(:posts, Post, nil, [:users])
|
42
|
+
@users = FactoryDataPreloader::Preloader.new(:users, User, nil, [])
|
43
|
+
end
|
44
|
+
|
45
|
+
should 'return the preloader objects for #dependencies' do
|
46
|
+
assert_equal [@users, @posts], @comments.dependencies
|
47
|
+
end
|
29
48
|
end
|
30
49
|
end
|
31
|
-
|
32
|
-
context '
|
50
|
+
|
51
|
+
context 'A series of preloaders, with dependencies,' do
|
33
52
|
setup do
|
34
|
-
@
|
35
|
-
@
|
53
|
+
@post_image_ratings = FactoryDataPreloader::Preloader.new(:post_image_ratings, PostImageRating, nil, [:post_images])
|
54
|
+
@post_images = FactoryDataPreloader::Preloader.new(:post_images, PostImage, nil, [:posts])
|
55
|
+
@ip_addresses = FactoryDataPreloader::Preloader.new(:ip_addresses, IpAddress, nil, [])
|
56
|
+
@posts = FactoryDataPreloader::Preloader.new(:posts, Post, nil, [:users])
|
57
|
+
@users = FactoryDataPreloader::Preloader.new(:users, User, nil, [])
|
36
58
|
end
|
37
|
-
|
38
|
-
should '
|
39
|
-
|
40
|
-
assert_equal
|
59
|
+
|
60
|
+
should 'sort correctly for PreloaderCollection.instance.dependency_order' do
|
61
|
+
expected = [@ip_addresses, @users, @posts, @post_images, @post_image_ratings]
|
62
|
+
assert_equal expected.map(&:model_type), FactoryDataPreloader::PreloaderCollection.instance.dependency_order.map(&:model_type)
|
41
63
|
end
|
42
64
|
end
|
43
65
|
end
|
data/test/test_helper.rb
CHANGED
@@ -41,20 +41,20 @@ end
|
|
41
41
|
class FactoryDataPreloader::FactoryData
|
42
42
|
# helper method to reset the factory data between test runs.
|
43
43
|
def self.reset!
|
44
|
-
|
45
|
-
class << self; self; end.class_eval do
|
46
|
-
remove_method(preloader.model_type)
|
44
|
+
FactoryDataPreloader::PreloaderCollection.instance.dependency_order.reverse.each do |preloader|
|
45
|
+
class << self; self; end.class_eval do
|
46
|
+
remove_method(preloader.model_type)
|
47
47
|
end
|
48
|
-
|
48
|
+
|
49
49
|
unless @@preloaded_cache.nil?
|
50
50
|
preloader.model_class.delete_all(:id => (@@preloaded_cache[preloader.model_type] || {}).values)
|
51
51
|
end
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
@@preloaded_cache = nil
|
55
55
|
@@preloaded_data_deleted = nil
|
56
56
|
@@single_test_cache = {}
|
57
|
-
|
57
|
+
FactoryDataPreloader::PreloaderCollection.instance.clear
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
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.3.
|
4
|
+
version: 0.3.2
|
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-04-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|