factory_girl 2.0.4 → 2.0.5
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/CONTRIBUTION_GUIDELINES.md +1 -0
- data/GETTING_STARTED.md +28 -4
- data/Gemfile +2 -1
- data/Gemfile.lock +6 -2
- data/features/factory_girl_steps.feature +17 -0
- data/features/step_definitions/database_steps.rb +22 -0
- data/features/support/factories.rb +13 -0
- data/features/support/test.db +0 -0
- data/lib/factory_girl/aliases.rb +1 -3
- data/lib/factory_girl/attribute.rb +16 -8
- data/lib/factory_girl/attribute/association.rb +0 -3
- data/lib/factory_girl/attribute/callback.rb +0 -2
- data/lib/factory_girl/attribute/dynamic.rb +1 -3
- data/lib/factory_girl/attribute/static.rb +1 -1
- data/lib/factory_girl/attribute_list.rb +30 -9
- data/lib/factory_girl/factory.rb +1 -1
- data/lib/factory_girl/proxy.rb +7 -5
- data/lib/factory_girl/proxy/attributes_for.rb +8 -3
- data/lib/factory_girl/proxy/build.rb +12 -3
- data/lib/factory_girl/proxy/stub.rb +12 -3
- data/lib/factory_girl/sequence.rb +2 -2
- data/lib/factory_girl/step_definitions.rb +3 -2
- data/lib/factory_girl/version.rb +1 -1
- data/spec/acceptance/attribute_aliases_spec.rb +0 -1
- data/spec/acceptance/attributes_for_spec.rb +0 -1
- data/spec/acceptance/attributes_ordered_spec.rb +24 -6
- data/spec/acceptance/build_list_spec.rb +0 -1
- data/spec/acceptance/build_spec.rb +0 -1
- data/spec/acceptance/build_stubbed_spec.rb +0 -1
- data/spec/acceptance/callbacks_spec.rb +0 -1
- data/spec/acceptance/create_list_spec.rb +0 -1
- data/spec/acceptance/create_spec.rb +0 -1
- data/spec/acceptance/default_strategy_spec.rb +0 -1
- data/spec/acceptance/definition_spec.rb +0 -1
- data/spec/acceptance/definition_without_block_spec.rb +0 -1
- data/spec/acceptance/overrides_spec.rb +0 -1
- data/spec/acceptance/parent_spec.rb +18 -1
- data/spec/acceptance/sequence_spec.rb +0 -1
- data/spec/acceptance/syntax/blueprint_spec.rb +0 -1
- data/spec/acceptance/syntax/generate_spec.rb +0 -1
- data/spec/acceptance/syntax/make_spec.rb +0 -1
- data/spec/acceptance/syntax/sham_spec.rb +0 -1
- data/spec/acceptance/syntax/vintage_spec.rb +27 -29
- data/spec/acceptance/traits_spec.rb +0 -1
- data/spec/acceptance/transient_attributes_spec.rb +68 -0
- data/spec/factory_girl/aliases_spec.rb +19 -21
- data/spec/factory_girl/attribute/association_spec.rb +16 -24
- data/spec/factory_girl/attribute/callback_spec.rb +14 -15
- data/spec/factory_girl/attribute/dynamic_spec.rb +41 -45
- data/spec/factory_girl/attribute/implicit_spec.rb +18 -30
- data/spec/factory_girl/attribute/sequence_spec.rb +11 -13
- data/spec/factory_girl/attribute/static_spec.rb +13 -20
- data/spec/factory_girl/attribute_list_spec.rb +9 -1
- data/spec/factory_girl/attribute_spec.rb +17 -28
- data/spec/factory_girl/definition_proxy_spec.rb +131 -82
- data/spec/factory_girl/deprecated_spec.rb +15 -36
- data/spec/factory_girl/factory_spec.rb +106 -135
- data/spec/factory_girl/find_definitions_spec.rb +7 -6
- data/spec/factory_girl/proxy/attributes_for_spec.rb +23 -32
- data/spec/factory_girl/proxy/build_spec.rb +6 -80
- data/spec/factory_girl/proxy/create_spec.rb +24 -89
- data/spec/factory_girl/proxy/stub_spec.rb +14 -73
- data/spec/factory_girl/proxy_spec.rb +53 -53
- data/spec/factory_girl/registry_spec.rb +13 -29
- data/spec/factory_girl/sequence_spec.rb +24 -72
- data/spec/factory_girl_spec.rb +10 -5
- data/spec/spec_helper.rb +5 -79
- data/spec/support/macros/define_constant.rb +86 -0
- data/spec/support/shared_examples/proxy.rb +99 -0
- metadata +34 -20
- data/spec/acceptance/acceptance_helper.rb +0 -11
data/CONTRIBUTION_GUIDELINES.md
CHANGED
data/GETTING_STARTED.md
CHANGED
@@ -149,6 +149,30 @@ Attributes can be based on the values of other attributes using the proxy that i
|
|
149
149
|
FactoryGirl.create(:user, :last_name => 'Doe').email
|
150
150
|
# => "joe.doe@example.com"
|
151
151
|
|
152
|
+
Transient Attributes
|
153
|
+
--------------------
|
154
|
+
|
155
|
+
There may be times where your code can be DRYed up by passing in transient attributes to factories.
|
156
|
+
|
157
|
+
factory :user do
|
158
|
+
rockstar(true).ignore
|
159
|
+
upcased { false }.ignore
|
160
|
+
|
161
|
+
name { "John Doe#{" - Rockstar" if rockstar}" }
|
162
|
+
email { "#{name.downcase}@example.com" }
|
163
|
+
|
164
|
+
after_create do |user, proxy|
|
165
|
+
user.name.upcase! if proxy.upcased
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
FactoryGirl.create(:user, :upcased => true).name
|
170
|
+
# => "JOHN DOE - ROCKSTAR"
|
171
|
+
|
172
|
+
Static and dynamic attributes can be ignored. Ignored attributes will be ignored within attributes_for and won't be set on the model, even if the attribute exists or you attempt to override it.
|
173
|
+
|
174
|
+
Within Factory Girl's dynamic attributes, you can access ignored attributes as you would expect. If you need to access the proxy in a Factory Girl callback, you'll need to declare a second block argument (for the proxy) and access ignored attributes from there.
|
175
|
+
|
152
176
|
Associations
|
153
177
|
------------
|
154
178
|
|
@@ -213,7 +237,7 @@ Sequences
|
|
213
237
|
Unique values in a specific format (for example, e-mail addresses) can be
|
214
238
|
generated using sequences. Sequences are defined by calling sequence in a
|
215
239
|
definition block, and values in a sequence are generated by calling
|
216
|
-
|
240
|
+
FactoryGirl.generate:
|
217
241
|
|
218
242
|
# Defines a new sequence
|
219
243
|
FactoryGirl.define do
|
@@ -222,10 +246,10 @@ Factory.next:
|
|
222
246
|
end
|
223
247
|
end
|
224
248
|
|
225
|
-
|
249
|
+
FactoryGirl.generate :email
|
226
250
|
# => "person1@example.com"
|
227
251
|
|
228
|
-
|
252
|
+
FactoryGirl.generate :email
|
229
253
|
# => "person2@example.com"
|
230
254
|
|
231
255
|
Sequences can be used as attributes:
|
@@ -237,7 +261,7 @@ Sequences can be used as attributes:
|
|
237
261
|
Or in lazy attributes:
|
238
262
|
|
239
263
|
factory :invite do
|
240
|
-
invitee {
|
264
|
+
invitee { FactoryGirl.generate(:email) }
|
241
265
|
end
|
242
266
|
|
243
267
|
And it's also possible to define an in-line sequence that is only used in
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -22,6 +22,8 @@ GEM
|
|
22
22
|
cucumber (>= 0.10.5)
|
23
23
|
rspec (>= 2.6.0)
|
24
24
|
bluecloth (2.0.9)
|
25
|
+
bourne (1.0)
|
26
|
+
mocha (= 0.9.8)
|
25
27
|
builder (2.1.2)
|
26
28
|
childprocess (0.1.9)
|
27
29
|
ffi (~> 1.0.6)
|
@@ -37,9 +39,10 @@ GEM
|
|
37
39
|
json (>= 1.4.6)
|
38
40
|
i18n (0.4.2)
|
39
41
|
json (1.5.3)
|
42
|
+
mocha (0.9.8)
|
43
|
+
rake
|
40
44
|
rake (0.9.2)
|
41
45
|
rcov (0.9.9)
|
42
|
-
rr (1.0.2)
|
43
46
|
rspec (2.6.0)
|
44
47
|
rspec-core (~> 2.6.0)
|
45
48
|
rspec-expectations (~> 2.6.0)
|
@@ -61,10 +64,11 @@ DEPENDENCIES
|
|
61
64
|
activesupport
|
62
65
|
appraisal (~> 0.3.5)
|
63
66
|
bluecloth
|
67
|
+
bourne
|
64
68
|
cucumber (~> 1.0.0)
|
69
|
+
mocha
|
65
70
|
rake
|
66
71
|
rcov
|
67
|
-
rr
|
68
72
|
rspec (~> 2.0)
|
69
73
|
sqlite3-ruby
|
70
74
|
yard
|
@@ -198,3 +198,20 @@ Feature: Use step definitions generated by factories
|
|
198
198
|
Then I should find the following for the last user:
|
199
199
|
| id | name | admin |
|
200
200
|
| 123 | Joe | true |
|
201
|
+
|
202
|
+
Scenario: Transform parses string data into array before assigning to an association
|
203
|
+
Given the following tags exist:
|
204
|
+
| name |
|
205
|
+
| funky |
|
206
|
+
| cool |
|
207
|
+
| hip |
|
208
|
+
And the following post exists:
|
209
|
+
| title | tags |
|
210
|
+
| Tagged post | cool, hip |
|
211
|
+
Then the post "Tagged post" should have the following tags:
|
212
|
+
| name |
|
213
|
+
| cool |
|
214
|
+
| hip |
|
215
|
+
And the post "Tagged post" should not have the following tags:
|
216
|
+
| name |
|
217
|
+
| funky |
|
@@ -11,8 +11,30 @@ Then /^there should be (\d+) (.*)$/ do |count, model|
|
|
11
11
|
model_class.count.should == count.to_i
|
12
12
|
end
|
13
13
|
|
14
|
+
Then /^the post "([^"]*)" should (not )?have the following tags?:$/ do |post_title, negate, table|
|
15
|
+
post = Post.find_by_title!(post_title)
|
16
|
+
|
17
|
+
table.hashes.each do |row|
|
18
|
+
tag = Tag.find_by_name(row[:name])
|
19
|
+
|
20
|
+
if negate
|
21
|
+
post.tags.should_not include(tag)
|
22
|
+
else
|
23
|
+
post.tags.should include(tag)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Transform /^table:(?:.*,)?tags(?:,.*)?$/ do |table|
|
29
|
+
table.map_column!("tags") do |tags|
|
30
|
+
tags.split(',').map {|tag| Tag.find_by_name! tag.strip }
|
31
|
+
end
|
32
|
+
table
|
33
|
+
end
|
34
|
+
|
14
35
|
Before do
|
15
36
|
Post.delete_all
|
37
|
+
Tag.delete_all
|
16
38
|
User.delete_all
|
17
39
|
Category.delete_all
|
18
40
|
CategoryGroup.delete_all
|
@@ -21,6 +21,11 @@ class CreateSchema < ActiveRecord::Migration
|
|
21
21
|
t.string :name
|
22
22
|
end
|
23
23
|
|
24
|
+
create_table :tags, :force => true do |t|
|
25
|
+
t.integer :post_id
|
26
|
+
t.string :name
|
27
|
+
end
|
28
|
+
|
24
29
|
create_table :users, :force => true do |t|
|
25
30
|
t.string :name
|
26
31
|
t.boolean :admin, :default => false, :null => false
|
@@ -43,6 +48,11 @@ end
|
|
43
48
|
class Post < ActiveRecord::Base
|
44
49
|
belongs_to :author, :class_name => 'User'
|
45
50
|
belongs_to :category
|
51
|
+
has_many :tags
|
52
|
+
end
|
53
|
+
|
54
|
+
class Tag < ActiveRecord::Base
|
55
|
+
belongs_to :post
|
46
56
|
end
|
47
57
|
|
48
58
|
class NonActiveRecord
|
@@ -74,6 +84,9 @@ FactoryGirl.define do
|
|
74
84
|
category
|
75
85
|
end
|
76
86
|
|
87
|
+
factory :tag do
|
88
|
+
post
|
89
|
+
end
|
77
90
|
# This is here to ensure that factory step definitions don't raise for a non-AR factory
|
78
91
|
factory :non_active_record do
|
79
92
|
end
|
data/features/support/test.db
CHANGED
Binary file
|
data/lib/factory_girl/aliases.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module FactoryGirl
|
2
|
-
|
3
2
|
class << self
|
4
3
|
attr_accessor :aliases #:nodoc:
|
5
4
|
end
|
5
|
+
|
6
6
|
self.aliases = [
|
7
7
|
[/(.+)_id/, '\1'],
|
8
8
|
[/(.*)/, '\1_id']
|
@@ -13,8 +13,6 @@ module FactoryGirl
|
|
13
13
|
pattern, replace = *params
|
14
14
|
if pattern.match(attribute.to_s)
|
15
15
|
attribute.to_s.sub(pattern, replace).to_sym
|
16
|
-
else
|
17
|
-
nil
|
18
16
|
end
|
19
17
|
end.compact << attribute
|
20
18
|
end
|
@@ -10,17 +10,16 @@ module FactoryGirl
|
|
10
10
|
class Attribute #:nodoc:
|
11
11
|
include Comparable
|
12
12
|
|
13
|
-
attr_reader :name
|
13
|
+
attr_reader :name, :ignored
|
14
14
|
|
15
15
|
def initialize(name)
|
16
16
|
@name = name.to_sym
|
17
|
+
@ignored = false
|
18
|
+
ensure_non_attribute_writer!
|
19
|
+
end
|
17
20
|
|
18
|
-
|
19
|
-
|
20
|
-
raise AttributeDefinitionError,
|
21
|
-
"factory_girl uses 'f.#{attribute_name} value' syntax " +
|
22
|
-
"rather than 'f.#{attribute_name} = value'"
|
23
|
-
end
|
21
|
+
def ignore
|
22
|
+
@ignored = true
|
24
23
|
end
|
25
24
|
|
26
25
|
def add_to(proxy)
|
@@ -43,6 +42,15 @@ module FactoryGirl
|
|
43
42
|
self.priority <=> another.priority
|
44
43
|
end
|
45
44
|
|
46
|
-
|
45
|
+
private
|
47
46
|
|
47
|
+
def ensure_non_attribute_writer!
|
48
|
+
if @name.to_s =~ /=$/
|
49
|
+
attribute_name = $`
|
50
|
+
raise AttributeDefinitionError,
|
51
|
+
"factory_girl uses 'f.#{attribute_name} value' syntax " +
|
52
|
+
"rather than 'f.#{attribute_name} = value'"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
48
56
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module FactoryGirl
|
2
2
|
class Attribute #:nodoc:
|
3
|
-
|
4
3
|
class Dynamic < Attribute #:nodoc:
|
5
4
|
def initialize(name, block)
|
6
5
|
super(name)
|
@@ -12,9 +11,8 @@ module FactoryGirl
|
|
12
11
|
if FactoryGirl::Sequence === value
|
13
12
|
raise SequenceAbuseError
|
14
13
|
end
|
15
|
-
proxy.set(name, value)
|
14
|
+
proxy.set(name, value, @ignored)
|
16
15
|
end
|
17
16
|
end
|
18
|
-
|
19
17
|
end
|
20
18
|
end
|
@@ -3,7 +3,7 @@ module FactoryGirl
|
|
3
3
|
include Enumerable
|
4
4
|
|
5
5
|
def initialize
|
6
|
-
@attributes =
|
6
|
+
@attributes = {}
|
7
7
|
end
|
8
8
|
|
9
9
|
def define_attribute(attribute)
|
@@ -11,7 +11,7 @@ module FactoryGirl
|
|
11
11
|
raise AttributeDefinitionError, "Attribute already defined: #{attribute.name}"
|
12
12
|
end
|
13
13
|
|
14
|
-
|
14
|
+
add_attribute attribute
|
15
15
|
end
|
16
16
|
|
17
17
|
def add_callback(name, &block)
|
@@ -19,15 +19,15 @@ module FactoryGirl
|
|
19
19
|
raise InvalidCallbackNameError, "#{name} is not a valid callback name. Valid callback names are #{valid_callback_names.inspect}"
|
20
20
|
end
|
21
21
|
|
22
|
-
|
22
|
+
add_attribute Attribute::Callback.new(name.to_sym, block)
|
23
23
|
end
|
24
24
|
|
25
25
|
def each(&block)
|
26
|
-
|
26
|
+
flattened_attributes.each(&block)
|
27
27
|
end
|
28
28
|
|
29
29
|
def attribute_defined?(attribute_name)
|
30
|
-
!@attributes.detect do |attribute|
|
30
|
+
!@attributes.values.flatten.detect do |attribute|
|
31
31
|
attribute.name == attribute_name &&
|
32
32
|
!attribute.is_a?(FactoryGirl::Attribute::Callback)
|
33
33
|
end.nil?
|
@@ -38,16 +38,17 @@ module FactoryGirl
|
|
38
38
|
|
39
39
|
attributes_to_apply.each do |attribute|
|
40
40
|
if attribute_defined?(attribute.name)
|
41
|
-
@attributes.
|
42
|
-
|
41
|
+
@attributes.each_value do |attributes|
|
42
|
+
attributes.delete_if do |attrib|
|
43
|
+
new_attributes << attrib.clone if attrib.name == attribute.name
|
44
|
+
end
|
43
45
|
end
|
44
46
|
else
|
45
47
|
new_attributes << attribute.clone
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
49
|
-
|
50
|
-
@attributes = @attributes.partition {|attr| attr.priority.zero? }.flatten
|
51
|
+
prepend_attributes new_attributes
|
51
52
|
end
|
52
53
|
|
53
54
|
private
|
@@ -55,5 +56,25 @@ module FactoryGirl
|
|
55
56
|
def valid_callback_names
|
56
57
|
[:after_build, :after_create, :after_stub]
|
57
58
|
end
|
59
|
+
|
60
|
+
def add_attribute(attribute)
|
61
|
+
@attributes[attribute.priority] ||= []
|
62
|
+
@attributes[attribute.priority] << attribute
|
63
|
+
attribute
|
64
|
+
end
|
65
|
+
|
66
|
+
def prepend_attributes(new_attributes)
|
67
|
+
new_attributes.group_by {|attr| attr.priority }.each do |priority, attributes|
|
68
|
+
@attributes[priority] ||= []
|
69
|
+
@attributes[priority].unshift *attributes
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def flattened_attributes
|
74
|
+
@attributes.keys.sort.inject([]) do |result, key|
|
75
|
+
result << @attributes[key]
|
76
|
+
result
|
77
|
+
end.flatten
|
78
|
+
end
|
58
79
|
end
|
59
80
|
end
|
data/lib/factory_girl/factory.rb
CHANGED
@@ -86,7 +86,7 @@ module FactoryGirl
|
|
86
86
|
if factory_overrides.empty?
|
87
87
|
attribute.add_to(proxy)
|
88
88
|
else
|
89
|
-
factory_overrides.each { |attr, val| proxy.set(attr, val) }
|
89
|
+
factory_overrides.each { |attr, val| proxy.set(attr, val, attribute.ignored); overrides.delete(attr) }
|
90
90
|
end
|
91
91
|
end
|
92
92
|
overrides.each { |attr, val| proxy.set(attr, val) }
|
data/lib/factory_girl/proxy.rb
CHANGED
@@ -7,10 +7,9 @@ module FactoryGirl
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def get(attribute)
|
10
|
-
nil
|
11
10
|
end
|
12
11
|
|
13
|
-
def set(attribute, value)
|
12
|
+
def set(attribute, value, ignored = false)
|
14
13
|
end
|
15
14
|
|
16
15
|
def associate(name, factory, attributes)
|
@@ -25,7 +24,11 @@ module FactoryGirl
|
|
25
24
|
def run_callbacks(name)
|
26
25
|
if @callbacks && @callbacks[name]
|
27
26
|
@callbacks[name].each do |block|
|
28
|
-
block.arity
|
27
|
+
case block.arity
|
28
|
+
when 0 then block.call
|
29
|
+
when 2 then block.call(@instance, self)
|
30
|
+
else block.call(@instance)
|
31
|
+
end
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
@@ -59,11 +62,10 @@ module FactoryGirl
|
|
59
62
|
# FactoryGirl.build(:post)
|
60
63
|
#
|
61
64
|
# # Builds and saves a User, builds a Post, assigns the User to the
|
62
|
-
# # author association, and saves the
|
65
|
+
# # author association, and saves the Post.
|
63
66
|
# FactoryGirl.create(:post)
|
64
67
|
#
|
65
68
|
def association(name, overrides = {})
|
66
|
-
nil
|
67
69
|
end
|
68
70
|
|
69
71
|
def method_missing(method, *args, &block)
|