factory_girl 2.3.2 → 2.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/.travis.yml +5 -3
- data/Appraisals +4 -0
- data/CONTRIBUTION_GUIDELINES.md +1 -1
- data/Changelog +13 -0
- data/GETTING_STARTED.md +362 -286
- data/Gemfile.lock +1 -1
- data/README.md +8 -8
- data/features/factory_girl_steps.feature +4 -0
- data/features/support/factories.rb +19 -0
- data/gemfiles/2.1.gemfile.lock +1 -1
- data/gemfiles/2.3.gemfile.lock +1 -1
- data/gemfiles/3.0.gemfile.lock +1 -1
- data/gemfiles/3.1.gemfile.lock +1 -1
- data/gemfiles/3.2.gemfile +7 -0
- data/gemfiles/3.2.gemfile.lock +90 -0
- data/lib/factory_girl.rb +4 -0
- data/lib/factory_girl/attribute.rb +1 -9
- data/lib/factory_girl/attribute/association.rb +2 -2
- data/lib/factory_girl/attribute/dynamic.rb +2 -2
- data/lib/factory_girl/attribute/sequence.rb +1 -1
- data/lib/factory_girl/attribute/static.rb +1 -1
- data/lib/factory_girl/attribute_assigner.rb +73 -0
- data/lib/factory_girl/attribute_list.rb +6 -15
- data/lib/factory_girl/callback.rb +2 -2
- data/lib/factory_girl/evaluator.rb +57 -0
- data/lib/factory_girl/evaluator_class_definer.rb +34 -0
- data/lib/factory_girl/factory.rb +31 -80
- data/lib/factory_girl/null_factory.rb +2 -1
- data/lib/factory_girl/null_object.rb +19 -0
- data/lib/factory_girl/proxy.rb +6 -87
- data/lib/factory_girl/proxy/attributes_for.rb +2 -7
- data/lib/factory_girl/proxy/build.rb +4 -3
- data/lib/factory_girl/proxy/create.rb +6 -7
- data/lib/factory_girl/proxy/stub.rb +19 -18
- data/lib/factory_girl/step_definitions.rb +4 -3
- data/lib/factory_girl/version.rb +1 -1
- data/spec/acceptance/aliases_spec.rb +19 -0
- data/spec/acceptance/attributes_for_spec.rb +10 -1
- data/spec/acceptance/attributes_from_instance_spec.rb +53 -0
- data/spec/acceptance/build_spec.rb +8 -0
- data/spec/acceptance/build_stubbed_spec.rb +9 -0
- data/spec/acceptance/create_spec.rb +8 -0
- data/spec/factory_girl/attribute/association_spec.rb +5 -4
- data/spec/factory_girl/attribute/dynamic_spec.rb +9 -10
- data/spec/factory_girl/attribute/sequence_spec.rb +1 -2
- data/spec/factory_girl/attribute/static_spec.rb +1 -2
- data/spec/factory_girl/attribute_list_spec.rb +14 -4
- data/spec/factory_girl/evaluator_class_definer_spec.rb +54 -0
- data/spec/factory_girl/factory_spec.rb +23 -16
- data/spec/factory_girl/null_factory_spec.rb +2 -1
- data/spec/factory_girl/null_object_spec.rb +8 -0
- data/spec/factory_girl/proxy/attributes_for_spec.rb +8 -24
- data/spec/factory_girl/proxy/build_spec.rb +1 -7
- data/spec/factory_girl/proxy/create_spec.rb +2 -27
- data/spec/factory_girl/proxy/stub_spec.rb +14 -13
- data/spec/factory_girl/proxy_spec.rb +1 -33
- data/spec/support/shared_examples/proxy.rb +22 -45
- metadata +133 -177
@@ -0,0 +1,34 @@
|
|
1
|
+
module FactoryGirl
|
2
|
+
class EvaluatorClassDefiner
|
3
|
+
def initialize(attributes, callbacks, parent_class)
|
4
|
+
@parent_class = parent_class
|
5
|
+
@callbacks = callbacks
|
6
|
+
@attributes = attributes
|
7
|
+
|
8
|
+
attributes.each do |attribute|
|
9
|
+
define_attribute(attribute.name, attribute.to_proc)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def evaluator_class
|
14
|
+
@evaluator_class ||= Class.new(@parent_class).tap do |klass|
|
15
|
+
klass.callbacks ||= []
|
16
|
+
klass.callbacks += @callbacks
|
17
|
+
klass.attribute_lists ||= []
|
18
|
+
klass.attribute_lists += [@attributes]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def define_attribute(attribute_name, attribute_proc)
|
25
|
+
evaluator_class.send(:define_method, attribute_name) do
|
26
|
+
if @cached_attributes.key?(attribute_name)
|
27
|
+
@cached_attributes[attribute_name]
|
28
|
+
else
|
29
|
+
@cached_attributes[attribute_name] = instance_exec(&attribute_proc)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/factory_girl/factory.rb
CHANGED
@@ -13,6 +13,7 @@ module FactoryGirl
|
|
13
13
|
@class_name = options[:class]
|
14
14
|
@default_strategy = options[:default_strategy]
|
15
15
|
@definition = Definition.new(@name)
|
16
|
+
@compiled = false
|
16
17
|
|
17
18
|
inherit_traits(options[:traits] || [])
|
18
19
|
end
|
@@ -26,25 +27,27 @@ module FactoryGirl
|
|
26
27
|
end
|
27
28
|
|
28
29
|
def build_class #:nodoc:
|
29
|
-
class_name.
|
30
|
+
@build_class ||= if class_name.is_a? Class
|
31
|
+
class_name
|
32
|
+
else
|
33
|
+
class_name.to_s.camelize.constantize
|
34
|
+
end
|
30
35
|
end
|
31
36
|
|
32
37
|
def default_strategy #:nodoc:
|
33
|
-
@default_strategy || parent.default_strategy
|
38
|
+
@default_strategy || parent.default_strategy
|
34
39
|
end
|
35
40
|
|
36
41
|
def run(proxy_class, overrides, &block) #:nodoc:
|
37
42
|
block ||= lambda {|result| result }
|
43
|
+
compile
|
38
44
|
|
39
|
-
|
40
|
-
:attributes => attributes,
|
41
|
-
:callbacks => callbacks,
|
42
|
-
:to_create => to_create,
|
43
|
-
:build_class => build_class,
|
44
|
-
:proxy_class => proxy_class
|
45
|
-
}
|
45
|
+
proxy = proxy_class.new
|
46
46
|
|
47
|
-
|
47
|
+
evaluator = evaluator_class.new(proxy, overrides.symbolize_keys)
|
48
|
+
attribute_assigner = AttributeAssigner.new(build_class, evaluator)
|
49
|
+
|
50
|
+
proxy.result(attribute_assigner, to_create).tap(&block)
|
48
51
|
end
|
49
52
|
|
50
53
|
def human_names
|
@@ -52,7 +55,7 @@ module FactoryGirl
|
|
52
55
|
end
|
53
56
|
|
54
57
|
def associations
|
55
|
-
attributes.
|
58
|
+
attributes.associations
|
56
59
|
end
|
57
60
|
|
58
61
|
# Names for this factory, including aliases.
|
@@ -85,9 +88,12 @@ module FactoryGirl
|
|
85
88
|
end
|
86
89
|
|
87
90
|
def compile
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
+
unless @compiled
|
92
|
+
parent.defined_traits.each {|trait| define_trait(trait) }
|
93
|
+
parent.compile
|
94
|
+
@definition.compile
|
95
|
+
@compiled = true
|
96
|
+
end
|
91
97
|
end
|
92
98
|
|
93
99
|
def with_traits(traits)
|
@@ -102,24 +108,29 @@ module FactoryGirl
|
|
102
108
|
@class_name || parent.class_name || name
|
103
109
|
end
|
104
110
|
|
111
|
+
def evaluator_class
|
112
|
+
@evaluator_class ||= EvaluatorClassDefiner.new(attributes, callbacks, parent.evaluator_class).evaluator_class
|
113
|
+
end
|
114
|
+
|
105
115
|
def attributes
|
106
116
|
compile
|
107
117
|
AttributeList.new(@name).tap do |list|
|
108
|
-
|
109
|
-
list.apply_attributes
|
118
|
+
processing_order.each do |factory|
|
119
|
+
list.apply_attributes factory.attributes
|
110
120
|
end
|
111
|
-
|
112
|
-
list.apply_attributes(@definition.attributes)
|
113
|
-
list.apply_attributes(parent.attributes)
|
114
121
|
end
|
115
122
|
end
|
116
123
|
|
117
124
|
def callbacks
|
118
|
-
|
125
|
+
processing_order.map {|factory| factory.callbacks }.flatten
|
119
126
|
end
|
120
127
|
|
121
128
|
private
|
122
129
|
|
130
|
+
def processing_order
|
131
|
+
[traits.reverse, @definition].flatten
|
132
|
+
end
|
133
|
+
|
123
134
|
def assert_valid_options(options)
|
124
135
|
options.assert_valid_keys(:class, :parent, :default_strategy, :aliases, :traits)
|
125
136
|
|
@@ -142,65 +153,5 @@ module FactoryGirl
|
|
142
153
|
super
|
143
154
|
@definition = @definition.clone
|
144
155
|
end
|
145
|
-
|
146
|
-
class Runner
|
147
|
-
def initialize(options = {})
|
148
|
-
@attributes = options[:attributes]
|
149
|
-
@callbacks = options[:callbacks]
|
150
|
-
@to_create = options[:to_create]
|
151
|
-
@build_class = options[:build_class]
|
152
|
-
@proxy_class = options[:proxy_class]
|
153
|
-
|
154
|
-
@overrides = {}
|
155
|
-
end
|
156
|
-
|
157
|
-
def run(overrides = {})
|
158
|
-
@overrides = overrides.symbolize_keys
|
159
|
-
|
160
|
-
apply_attributes
|
161
|
-
apply_remaining_overrides
|
162
|
-
|
163
|
-
proxy.result(@to_create)
|
164
|
-
end
|
165
|
-
|
166
|
-
private
|
167
|
-
|
168
|
-
def apply_attributes
|
169
|
-
@attributes.each do |attribute|
|
170
|
-
if overrides_for_attribute(attribute).any?
|
171
|
-
handle_attribute_with_overrides(attribute)
|
172
|
-
else
|
173
|
-
handle_attribute_without_overrides(attribute)
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
def apply_remaining_overrides
|
179
|
-
@overrides.each { |attr, val| add_static_attribute(attr, val) }
|
180
|
-
end
|
181
|
-
|
182
|
-
def overrides_for_attribute(attribute)
|
183
|
-
@overrides.select { |attr, val| attribute.alias_for?(attr) }
|
184
|
-
end
|
185
|
-
|
186
|
-
def handle_attribute_with_overrides(attribute)
|
187
|
-
overrides_for_attribute(attribute).each do |attr, val|
|
188
|
-
add_static_attribute(attr, val, attribute.ignored)
|
189
|
-
@overrides.delete(attr)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
def add_static_attribute(attr, val, ignored = false)
|
194
|
-
Attribute::Static.new(attr, val, ignored).add_to(proxy)
|
195
|
-
end
|
196
|
-
|
197
|
-
def handle_attribute_without_overrides(attribute)
|
198
|
-
attribute.add_to(proxy)
|
199
|
-
end
|
200
|
-
|
201
|
-
def proxy
|
202
|
-
@proxy ||= @proxy_class.new(@build_class, @callbacks)
|
203
|
-
end
|
204
|
-
end
|
205
156
|
end
|
206
157
|
end
|
@@ -9,7 +9,8 @@ module FactoryGirl
|
|
9
9
|
delegate :defined_traits, :callbacks, :attributes, :to => :definition
|
10
10
|
|
11
11
|
def compile; end
|
12
|
-
def default_strategy; end
|
13
12
|
def class_name; end
|
13
|
+
def default_strategy; :create; end
|
14
|
+
def evaluator_class; FactoryGirl::Evaluator; end
|
14
15
|
end
|
15
16
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module FactoryGirl
|
2
|
+
if defined?(::BasicObject)
|
3
|
+
class NullObject < ::BasicObject
|
4
|
+
def method_missing(*args)
|
5
|
+
nil
|
6
|
+
end
|
7
|
+
end
|
8
|
+
else
|
9
|
+
class NullObject
|
10
|
+
instance_methods.each do |m|
|
11
|
+
undef_method(m) if m.to_s !~ /(?:^__|^nil\?$|^send$|^object_id$)/
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing(*args)
|
15
|
+
nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/factory_girl/proxy.rb
CHANGED
@@ -3,23 +3,11 @@ require "factory_girl/proxy/build"
|
|
3
3
|
require "factory_girl/proxy/create"
|
4
4
|
require "factory_girl/proxy/attributes_for"
|
5
5
|
require "factory_girl/proxy/stub"
|
6
|
+
require "observer"
|
6
7
|
|
7
8
|
module FactoryGirl
|
8
9
|
class Proxy #:nodoc:
|
9
|
-
|
10
|
-
@callbacks = process_callbacks(callbacks)
|
11
|
-
@proxy = ObjectWrapper.new(klass)
|
12
|
-
end
|
13
|
-
|
14
|
-
delegate :get, :set, :set_ignored, :to => :@proxy
|
15
|
-
|
16
|
-
def run_callbacks(name)
|
17
|
-
if @callbacks[name]
|
18
|
-
@callbacks[name].each do |callback|
|
19
|
-
callback.run(result_instance, self)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
10
|
+
include Observable
|
23
11
|
|
24
12
|
# Generates an association using the current build strategy.
|
25
13
|
#
|
@@ -56,7 +44,7 @@ module FactoryGirl
|
|
56
44
|
def association(name, overrides = {})
|
57
45
|
end
|
58
46
|
|
59
|
-
def result(to_create)
|
47
|
+
def result(attribute_assigner, to_create)
|
60
48
|
raise NotImplementedError, "Strategies must return a result"
|
61
49
|
end
|
62
50
|
|
@@ -68,78 +56,9 @@ module FactoryGirl
|
|
68
56
|
|
69
57
|
private
|
70
58
|
|
71
|
-
def
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
def process_callbacks(callbacks)
|
76
|
-
callbacks.inject({}) do |result, callback|
|
77
|
-
result[callback.name] ||= []
|
78
|
-
result[callback.name] << callback
|
79
|
-
result
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def result_instance
|
84
|
-
@proxy.object
|
85
|
-
end
|
86
|
-
|
87
|
-
def result_hash
|
88
|
-
@proxy.to_hash
|
89
|
-
end
|
90
|
-
|
91
|
-
class ObjectWrapper
|
92
|
-
def initialize(klass)
|
93
|
-
@klass = klass
|
94
|
-
@attributes = []
|
95
|
-
@cached_attribute_values = {}
|
96
|
-
end
|
97
|
-
|
98
|
-
def to_hash
|
99
|
-
@attributes.inject({}) do |result, attribute|
|
100
|
-
result[attribute] = get(attribute)
|
101
|
-
result
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def object
|
106
|
-
@object ||= @klass.new
|
107
|
-
assign_object_attributes
|
108
|
-
@object
|
109
|
-
end
|
110
|
-
|
111
|
-
def set(attribute, value)
|
112
|
-
define_attribute(attribute, value)
|
113
|
-
@attributes << attribute.name
|
114
|
-
end
|
115
|
-
|
116
|
-
def set_ignored(attribute, value)
|
117
|
-
define_attribute(attribute, value)
|
118
|
-
end
|
119
|
-
|
120
|
-
def get(attribute)
|
121
|
-
@cached_attribute_values[attribute] ||= anonymous_instance.send(attribute)
|
122
|
-
end
|
123
|
-
|
124
|
-
private
|
125
|
-
|
126
|
-
def define_attribute(attribute, value)
|
127
|
-
anonymous_class.send(:define_method, attribute.name, value)
|
128
|
-
end
|
129
|
-
|
130
|
-
def assign_object_attributes
|
131
|
-
(@attributes - @cached_attribute_values.keys).each do |attribute|
|
132
|
-
@object.send("#{attribute}=", get(attribute))
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
def anonymous_class
|
137
|
-
@anonymous_class ||= Class.new
|
138
|
-
end
|
139
|
-
|
140
|
-
def anonymous_instance
|
141
|
-
@anonymous_instance ||= anonymous_class.new
|
142
|
-
end
|
59
|
+
def run_callbacks(name, result_instance)
|
60
|
+
changed
|
61
|
+
notify_observers(name, result_instance)
|
143
62
|
end
|
144
63
|
end
|
145
64
|
end
|
@@ -1,13 +1,8 @@
|
|
1
1
|
module FactoryGirl
|
2
2
|
class Proxy #:nodoc:
|
3
3
|
class AttributesFor < Proxy #:nodoc:
|
4
|
-
def
|
5
|
-
|
6
|
-
super
|
7
|
-
end
|
8
|
-
|
9
|
-
def result(to_create)
|
10
|
-
result_hash
|
4
|
+
def result(attribute_assigner, to_create)
|
5
|
+
attribute_assigner.hash
|
11
6
|
end
|
12
7
|
end
|
13
8
|
end
|
@@ -6,9 +6,10 @@ module FactoryGirl
|
|
6
6
|
factory.run(get_method(overrides[:method]), overrides.except(:method))
|
7
7
|
end
|
8
8
|
|
9
|
-
def result(to_create)
|
10
|
-
|
11
|
-
|
9
|
+
def result(attribute_assigner, to_create)
|
10
|
+
attribute_assigner.object.tap do |result_instance|
|
11
|
+
run_callbacks(:after_build, result_instance)
|
12
|
+
end
|
12
13
|
end
|
13
14
|
|
14
15
|
private
|
@@ -1,13 +1,12 @@
|
|
1
1
|
module FactoryGirl
|
2
2
|
class Proxy #:nodoc:
|
3
3
|
class Create < Build #:nodoc:
|
4
|
-
def result(to_create)
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
result_instance
|
4
|
+
def result(attribute_assigner, to_create)
|
5
|
+
attribute_assigner.object.tap do |result_instance|
|
6
|
+
run_callbacks(:after_build, result_instance)
|
7
|
+
to_create[result_instance]
|
8
|
+
run_callbacks(:after_create, result_instance)
|
9
|
+
end
|
11
10
|
end
|
12
11
|
end
|
13
12
|
end
|
@@ -3,8 +3,25 @@ module FactoryGirl
|
|
3
3
|
class Stub < Proxy #:nodoc:
|
4
4
|
@@next_id = 1000
|
5
5
|
|
6
|
-
def
|
7
|
-
|
6
|
+
def association(factory_name, overrides = {})
|
7
|
+
factory = FactoryGirl.factory_by_name(factory_name)
|
8
|
+
factory.run(Proxy::Stub, overrides.except(:method))
|
9
|
+
end
|
10
|
+
|
11
|
+
def result(attribute_assigner, to_create)
|
12
|
+
attribute_assigner.object.tap do |result_instance|
|
13
|
+
stub_database_interaction_on_result(result_instance)
|
14
|
+
run_callbacks(:after_stub, result_instance)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def next_id
|
21
|
+
@@next_id += 1
|
22
|
+
end
|
23
|
+
|
24
|
+
def stub_database_interaction_on_result(result_instance)
|
8
25
|
result_instance.id = next_id
|
9
26
|
result_instance.instance_eval do
|
10
27
|
def persisted?
|
@@ -40,22 +57,6 @@ module FactoryGirl
|
|
40
57
|
end
|
41
58
|
end
|
42
59
|
end
|
43
|
-
|
44
|
-
def association(factory_name, overrides = {})
|
45
|
-
factory = FactoryGirl.factory_by_name(factory_name)
|
46
|
-
factory.run(Proxy::Stub, overrides.except(:method))
|
47
|
-
end
|
48
|
-
|
49
|
-
def result(to_create)
|
50
|
-
run_callbacks(:after_stub)
|
51
|
-
result_instance
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def next_id
|
57
|
-
@@next_id += 1
|
58
|
-
end
|
59
60
|
end
|
60
61
|
end
|
61
62
|
end
|