factory_girl 2.1.0 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/.travis.yml +3 -0
  2. data/Changelog +9 -0
  3. data/GETTING_STARTED.md +47 -16
  4. data/Gemfile.lock +10 -9
  5. data/gemfiles/2.1.gemfile.lock +2 -1
  6. data/gemfiles/2.3.gemfile.lock +2 -1
  7. data/gemfiles/3.0.gemfile.lock +2 -1
  8. data/gemfiles/3.1.gemfile.lock +2 -1
  9. data/lib/factory_girl.rb +6 -3
  10. data/lib/factory_girl/attribute/static.rb +8 -0
  11. data/lib/factory_girl/attribute_list.rb +20 -12
  12. data/lib/factory_girl/callback.rb +30 -0
  13. data/lib/factory_girl/declaration.rb +19 -0
  14. data/lib/factory_girl/declaration/association.rb +17 -0
  15. data/lib/factory_girl/declaration/dynamic.rb +16 -0
  16. data/lib/factory_girl/declaration/implicit.rb +23 -0
  17. data/lib/factory_girl/declaration/static.rb +16 -0
  18. data/lib/factory_girl/definition_proxy.rb +6 -6
  19. data/lib/factory_girl/factory.rb +63 -79
  20. data/lib/factory_girl/proxy.rb +7 -11
  21. data/lib/factory_girl/proxy/attributes_for.rb +1 -0
  22. data/lib/factory_girl/proxy/build.rb +1 -0
  23. data/lib/factory_girl/proxy/stub.rb +1 -0
  24. data/lib/factory_girl/syntax/default.rb +4 -2
  25. data/lib/factory_girl/syntax/vintage.rb +1 -1
  26. data/lib/factory_girl/trait.rb +12 -4
  27. data/lib/factory_girl/version.rb +1 -1
  28. data/spec/acceptance/callbacks_spec.rb +7 -1
  29. data/spec/acceptance/modify_inherited_spec.rb +52 -0
  30. data/spec/acceptance/syntax/vintage_spec.rb +19 -7
  31. data/spec/factory_girl/attribute_list_spec.rb +18 -45
  32. data/spec/factory_girl/callback_spec.rb +41 -0
  33. data/spec/factory_girl/{attribute → declaration}/implicit_spec.rb +16 -11
  34. data/spec/factory_girl/definition_proxy_spec.rb +16 -12
  35. data/spec/factory_girl/factory_spec.rb +43 -34
  36. data/spec/factory_girl/proxy/create_spec.rb +7 -9
  37. data/spec/factory_girl/proxy_spec.rb +26 -39
  38. data/spec/support/shared_examples/proxy.rb +1 -1
  39. metadata +137 -114
  40. data/lib/factory_girl/attribute/callback.rb +0 -14
  41. data/lib/factory_girl/attribute/implicit.rb +0 -39
  42. data/lib/factory_girl/attribute/trait.rb +0 -22
  43. data/spec/factory_girl/attribute/callback_spec.rb +0 -22
data/.travis.yml CHANGED
@@ -8,3 +8,6 @@ gemfile:
8
8
  - gemfiles/2.3.gemfile
9
9
  - gemfiles/3.0.gemfile
10
10
  - gemfiles/3.1.gemfile
11
+ branches:
12
+ only:
13
+ - master
data/Changelog CHANGED
@@ -1,3 +1,12 @@
1
+ 2.1.0 (September 02, 2011)
2
+ Bugfix: created_at now defined for stubbed models
3
+ Gemspec updated for use with Rails 3.1
4
+ Factories can now be modified post-definition (useful for overriding defaults from gems/plugins)
5
+ All factories can now be reloaded with Factory.reload
6
+ Add :method => build to factory associations to prevent saving of associated objects
7
+ Factories defined in {Rails.root}/factories are now loaded by default
8
+ Various documentation updates
9
+
1
10
  1.1.4 (November 28, 2008)
2
11
  Factory.build now uses Factory.create for associations of the built object
3
12
  Factory definitions are now detected in subdirectories, such as
data/GETTING_STARTED.md CHANGED
@@ -4,13 +4,13 @@ Getting Started
4
4
  Update Your Gemfile
5
5
  -------------------
6
6
 
7
- If you're using Rails, you'll need to upgrade `factory_girl_rails` to the latest RC:
7
+ If you're using Rails, you'll need to change the required version of `factory_girl_rails`:
8
8
 
9
- gem "factory_girl_rails", "~> 1.1"
9
+ gem "factory_girl_rails", "~> 1.2"
10
10
 
11
11
  If you're *not* using Rails, you'll just have to change the required version of `factory_girl`:
12
12
 
13
- gem "factory_girl", "~> 2.0.0"
13
+ gem "factory_girl", "~> 2.1.0"
14
14
 
15
15
  Once your Gemfile is updated, you'll want to update your bundle.
16
16
 
@@ -57,7 +57,7 @@ are defined in files at the following locations:
57
57
  Using factories
58
58
  ---------------
59
59
 
60
- factory_girl supports several different build strategies: build, create, attributes_for and stub:
60
+ factory\_girl supports several different build strategies: build, create, attributes\_for and stub:
61
61
 
62
62
  # Returns a User instance that's not saved
63
63
  user = FactoryGirl.build(:user)
@@ -101,7 +101,11 @@ This would allow you to write:
101
101
  Lazy Attributes
102
102
  ---------------
103
103
 
104
- Most factory attributes can be added using static values that are evaluated when the factory is defined, but some attributes (such as associations and other attributes that must be dynamically generated) will need values assigned each time an instance is generated. These "lazy" attributes can be added by passing a block instead of a parameter:
104
+ Most factory attributes can be added using static values that are evaluated when
105
+ the factory is defined, but some attributes (such as associations and other
106
+ attributes that must be dynamically generated) will need values assigned each
107
+ time an instance is generated. These "lazy" attributes can be added by passing a
108
+ block instead of a parameter:
105
109
 
106
110
  factory :user do
107
111
  # ...
@@ -169,9 +173,14 @@ There may be times where your code can be DRYed up by passing in transient attri
169
173
  FactoryGirl.create(:user, :upcased => true).name
170
174
  #=> "JOHN DOE - ROCKSTAR"
171
175
 
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.
176
+ Static and dynamic attributes can be ignored. Ignored attributes will be ignored
177
+ within attributes\_for and won't be set on the model, even if the attribute
178
+ exists or you attempt to override it.
173
179
 
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.
180
+ Within Factory Girl's dynamic attributes, you can access ignored attributes as
181
+ you would expect. If you need to access the proxy in a Factory Girl callback,
182
+ you'll need to declare a second block argument (for the proxy) and access
183
+ ignored attributes from there.
175
184
 
176
185
  Associations
177
186
  ------------
@@ -241,7 +250,10 @@ You can also assign the parent explicitly:
241
250
  approved true
242
251
  end
243
252
 
244
- As mentioned above, it's good practice to define a basic factory for each class with only the attributes required to create it. Then, create more specific factories that inherit from this basic parent. Factory definitions are still code, so keep them DRY.
253
+ As mentioned above, it's good practice to define a basic factory for each class
254
+ with only the attributes required to create it. Then, create more specific
255
+ factories that inherit from this basic parent. Factory definitions are still
256
+ code, so keep them DRY.
245
257
 
246
258
  Sequences
247
259
  ---------
@@ -367,10 +379,28 @@ the trait that defines the attribute latest gets precedence.
367
379
  factory :female_admin, :traits => [:admin, :female] # login will be "Jane Doe (F)"
368
380
  end
369
381
 
382
+ You can also override individual attributes granted by a trait in subclasses.
383
+
384
+ factory :user do
385
+ name "Friendly User"
386
+ login { name }
387
+
388
+ trait :male do
389
+ name "John Doe"
390
+ gender "Male"
391
+ login { "#{name} (M)" }
392
+ end
393
+
394
+ factory :brandon do
395
+ male
396
+ name "Brandon"
397
+ end
398
+ end
399
+
370
400
  Callbacks
371
401
  ---------
372
402
 
373
- Factory_girl makes available three callbacks for injecting some code:
403
+ factory\_girl makes available three callbacks for injecting some code:
374
404
 
375
405
  * after_build - called after a factory is built (via FactoryGirl.build)
376
406
  * after_create - called after a factory is saved (via FactoryGirl.create)
@@ -399,7 +429,7 @@ Factories can also define any number of the same kind of callback. These callba
399
429
  after_create { then_this }
400
430
  end
401
431
 
402
- Calling FactoryGirl.create will invoke both after_build and after_create callbacks.
432
+ Calling FactoryGirl.create will invoke both after\_build and after\_create callbacks.
403
433
 
404
434
  Also, like standard attributes, child factories will inherit (and can also define) callbacks from their parent factory.
405
435
 
@@ -445,10 +475,8 @@ When modifying a factory, you can change any of the attributes you want (aside f
445
475
 
446
476
  `FactoryGirl.modify` must be called outside of a `FactoryGirl.define` block as it operates on factories differently.
447
477
 
448
- A couple caveats: you can only modify factories (not sequences or traits) and callbacks *still compound as they normally would*. So, if
478
+ A caveat: you can only modify factories (not sequences or traits) and callbacks *still compound as they normally would*. So, if
449
479
  the factory you're modifying defines an `after_create` callback, you defining an `after_create` won't override it, it'll just get run after the first callback.
450
- You also can't modify attributes assigned by traits. So, if you have a trait that grants a name attribute, and you modify the factory to set the name,
451
- it currently will reflect the name in the trait instead of the modified name.
452
480
 
453
481
  Building or Creating Multiple Records
454
482
  -------------------------------------
@@ -466,14 +494,17 @@ To set the attributes for each of the factories, you can pass in a hash as you n
466
494
  Cucumber Integration
467
495
  --------------------
468
496
 
469
- factory_girl ships with step definitions that make calling factories from Cucumber easier. To use them:
497
+ factory\_girl ships with step definitions that make calling factories from Cucumber easier. To use them, add the following to features/support/env.rb:
470
498
 
471
- require 'factory_girl/step_definitions'
499
+ require 'factory_girl/step_definitions'
472
500
 
473
501
  Alternate Syntaxes
474
502
  ------------------
475
503
 
476
- Users' tastes for syntax vary dramatically, but most users are looking for a common feature set. Because of this factory_girl supports "syntax layers" which provide alternate interfaces. See Factory::Syntax for information about the various layers available. For example, the Machinist-style syntax is popular:
504
+ Users' tastes for syntax vary dramatically, but most users are looking for a
505
+ common feature set. Because of this factory\_girl supports "syntax layers" which
506
+ provide alternate interfaces. See Factory::Syntax for information about the
507
+ various layers available. For example, the Machinist-style syntax is popular:
477
508
 
478
509
  require 'factory_girl/syntax/blueprint'
479
510
  require 'factory_girl/syntax/make'
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- factory_girl (2.1.0)
4
+ factory_girl (2.1.2)
5
+ activesupport
5
6
 
6
7
  GEM
7
8
  remote: http://rubygems.org/
@@ -28,31 +29,31 @@ GEM
28
29
  cucumber (>= 1.0.2)
29
30
  rdiscount (>= 1.6.8)
30
31
  rspec (>= 2.6.0)
31
- bcat (0.6.1)
32
+ bcat (0.6.2)
32
33
  rack (~> 1.0)
33
- bcrypt-ruby (3.0.0)
34
+ bcrypt-ruby (3.0.1)
34
35
  bluecloth (2.1.0)
35
36
  bourne (1.0)
36
37
  mocha (= 0.9.8)
37
38
  builder (3.0.0)
38
39
  childprocess (0.2.2)
39
40
  ffi (~> 1.0.6)
40
- cucumber (1.0.2)
41
+ cucumber (1.0.6)
41
42
  builder (>= 2.1.2)
42
43
  diff-lcs (>= 1.1.2)
43
- gherkin (~> 2.4.5)
44
+ gherkin (~> 2.4.18)
44
45
  json (>= 1.4.6)
45
- term-ansicolor (>= 1.0.5)
46
+ term-ansicolor (>= 1.0.6)
46
47
  diff-lcs (1.1.3)
47
48
  ffi (1.0.9)
48
- gherkin (2.4.16)
49
+ gherkin (2.4.21)
49
50
  json (>= 1.4.6)
50
51
  i18n (0.6.0)
51
- json (1.5.4)
52
+ json (1.6.1)
52
53
  mocha (0.9.8)
53
54
  rake
54
55
  multi_json (1.0.3)
55
- rack (1.3.2)
56
+ rack (1.3.3)
56
57
  rake (0.9.2)
57
58
  rcov (0.9.10)
58
59
  rdiscount (1.6.8)
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: /Users/joshuaclayton/dev/gems/factory_girl
3
3
  specs:
4
- factory_girl (2.1.0)
4
+ factory_girl (2.1.2)
5
+ activesupport
5
6
 
6
7
  GEM
7
8
  remote: http://rubygems.org/
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: /Users/joshuaclayton/dev/gems/factory_girl
3
3
  specs:
4
- factory_girl (2.1.0)
4
+ factory_girl (2.1.2)
5
+ activesupport
5
6
 
6
7
  GEM
7
8
  remote: http://rubygems.org/
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: /Users/joshuaclayton/dev/gems/factory_girl
3
3
  specs:
4
- factory_girl (2.1.0)
4
+ factory_girl (2.1.2)
5
+ activesupport
5
6
 
6
7
  GEM
7
8
  remote: http://rubygems.org/
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: /Users/joshuaclayton/dev/gems/factory_girl
3
3
  specs:
4
- factory_girl (2.1.0)
4
+ factory_girl (2.1.2)
5
+ activesupport
5
6
 
6
7
  GEM
7
8
  remote: http://rubygems.org/
data/lib/factory_girl.rb CHANGED
@@ -9,10 +9,13 @@ require 'factory_girl/attribute'
9
9
  require 'factory_girl/attribute/static'
10
10
  require 'factory_girl/attribute/dynamic'
11
11
  require 'factory_girl/attribute/association'
12
- require 'factory_girl/attribute/callback'
13
12
  require 'factory_girl/attribute/sequence'
14
- require 'factory_girl/attribute/implicit'
15
- require 'factory_girl/attribute/trait'
13
+ require 'factory_girl/callback'
14
+ require 'factory_girl/declaration'
15
+ require 'factory_girl/declaration/static'
16
+ require 'factory_girl/declaration/dynamic'
17
+ require 'factory_girl/declaration/association'
18
+ require 'factory_girl/declaration/implicit'
16
19
  require 'factory_girl/sequence'
17
20
  require 'factory_girl/attribute_list'
18
21
  require 'factory_girl/trait'
@@ -3,6 +3,8 @@ module FactoryGirl
3
3
 
4
4
  class Static < Attribute #:nodoc:
5
5
 
6
+ attr_reader :value
7
+
6
8
  def initialize(name, value)
7
9
  super(name)
8
10
  @value = value
@@ -15,6 +17,12 @@ module FactoryGirl
15
17
  def priority
16
18
  0
17
19
  end
20
+
21
+ def ==(another)
22
+ self.name == another.name &&
23
+ self.value == another.value &&
24
+ self.ignored == another.ignored
25
+ end
18
26
  end
19
27
  end
20
28
  end
@@ -2,9 +2,17 @@ module FactoryGirl
2
2
  class AttributeList
3
3
  include Enumerable
4
4
 
5
+ attr_reader :callbacks, :declarations
6
+
5
7
  def initialize
6
8
  @attributes = {}
9
+ @declarations = []
7
10
  @overridable = false
11
+ @callbacks = []
12
+ end
13
+
14
+ def declare_attribute(declaration)
15
+ @declarations << declaration
8
16
  end
9
17
 
10
18
  def define_attribute(attribute)
@@ -15,12 +23,8 @@ module FactoryGirl
15
23
  add_attribute attribute
16
24
  end
17
25
 
18
- def add_callback(name, &block)
19
- unless valid_callback_names.include?(name.to_sym)
20
- raise InvalidCallbackNameError, "#{name} is not a valid callback name. Valid callback names are #{valid_callback_names.inspect}"
21
- end
22
-
23
- add_attribute Attribute::Callback.new(name.to_sym, block)
26
+ def add_callback(callback)
27
+ @callbacks << callback
24
28
  end
25
29
 
26
30
  def each(&block)
@@ -32,6 +36,7 @@ module FactoryGirl
32
36
  end
33
37
 
34
38
  def apply_attributes(attributes_to_apply)
39
+ attributes_to_apply.callbacks.reverse.each { |callback| prepend_callback(callback) }
35
40
  new_attributes = []
36
41
 
37
42
  attributes_to_apply.each do |attribute|
@@ -56,12 +61,12 @@ module FactoryGirl
56
61
  @overridable
57
62
  end
58
63
 
59
- private
60
-
61
- def valid_callback_names
62
- [:after_build, :after_create, :after_stub]
64
+ def size
65
+ to_a.size
63
66
  end
64
67
 
68
+ private
69
+
65
70
  def add_attribute(attribute)
66
71
  delete_attribute(attribute.name) if overridable?
67
72
 
@@ -70,6 +75,10 @@ module FactoryGirl
70
75
  attribute
71
76
  end
72
77
 
78
+ def prepend_callback(callback)
79
+ @callbacks.unshift(callback)
80
+ end
81
+
73
82
  def prepend_attributes(new_attributes)
74
83
  new_attributes.group_by {|attr| attr.priority }.each do |priority, attributes|
75
84
  @attributes[priority] ||= []
@@ -86,8 +95,7 @@ module FactoryGirl
86
95
 
87
96
  def find_attribute(attribute_name)
88
97
  @attributes.values.flatten.detect do |attribute|
89
- attribute.name == attribute_name &&
90
- !attribute.is_a?(FactoryGirl::Attribute::Callback)
98
+ attribute.name == attribute_name
91
99
  end
92
100
  end
93
101
 
@@ -0,0 +1,30 @@
1
+ module FactoryGirl
2
+ class Callback
3
+ VALID_NAMES = [:after_build, :after_create, :after_stub].freeze
4
+
5
+ attr_reader :name, :block
6
+
7
+ def initialize(name, block)
8
+ @name = name.to_sym
9
+ @block = block
10
+ check_name
11
+ end
12
+
13
+ def run(instance, proxy)
14
+ case block.arity
15
+ when 1 then block.call(instance)
16
+ when 2 then block.call(instance, proxy)
17
+ else block.call
18
+ end
19
+ end
20
+
21
+ private
22
+
23
+ def check_name
24
+ unless VALID_NAMES.include?(name)
25
+ raise InvalidCallbackNameError, "#{name} is not a valid callback name. " +
26
+ "Valid callback names are #{VALID_NAMES.inspect}"
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,19 @@
1
+ module FactoryGirl
2
+ class Declaration
3
+ attr_reader :name
4
+
5
+ def initialize(name)
6
+ @name = name
7
+ end
8
+
9
+ def ignore
10
+ @ignored = true
11
+ end
12
+
13
+ def to_attributes
14
+ build.tap do |attributes|
15
+ attributes.each(&:ignore) if @ignored
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ module FactoryGirl
2
+ class Declaration
3
+ class Association < Declaration
4
+ def initialize(name, options)
5
+ super(name)
6
+ @options = options
7
+ end
8
+
9
+ private
10
+
11
+ def build
12
+ factory_name = @options.delete(:factory) || name
13
+ [Attribute::Association.new(name, factory_name, @options)]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ module FactoryGirl
2
+ class Declaration
3
+ class Dynamic < Declaration
4
+ def initialize(name, block)
5
+ super(name)
6
+ @block = block
7
+ end
8
+
9
+ private
10
+
11
+ def build
12
+ [Attribute::Dynamic.new(name, @block)]
13
+ end
14
+ end
15
+ end
16
+ end