factory_girl 2.5.2 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/.travis.yml +0 -1
  2. data/Changelog +6 -0
  3. data/GETTING_STARTED.md +52 -7
  4. data/Gemfile.lock +1 -1
  5. data/gemfiles/2.3.gemfile.lock +1 -1
  6. data/gemfiles/3.0.gemfile.lock +1 -1
  7. data/gemfiles/3.1.gemfile.lock +1 -1
  8. data/gemfiles/3.2.gemfile.lock +1 -1
  9. data/lib/factory_girl.rb +2 -1
  10. data/lib/factory_girl/association_runner.rb +50 -0
  11. data/lib/factory_girl/definition_proxy.rb +1 -1
  12. data/lib/factory_girl/evaluator.rb +12 -1
  13. data/lib/factory_girl/factory.rb +5 -5
  14. data/lib/factory_girl/strategy.rb +32 -0
  15. data/lib/factory_girl/{proxy → strategy}/attributes_for.rb +5 -2
  16. data/lib/factory_girl/strategy/build.rb +15 -0
  17. data/lib/factory_girl/{proxy → strategy}/create.rb +6 -2
  18. data/lib/factory_girl/{proxy → strategy}/stub.rb +4 -5
  19. data/lib/factory_girl/syntax/generate.rb +3 -3
  20. data/lib/factory_girl/syntax/make.rb +2 -2
  21. data/lib/factory_girl/syntax/methods.rb +6 -6
  22. data/lib/factory_girl/version.rb +1 -1
  23. data/spec/acceptance/build_spec.rb +2 -2
  24. data/spec/acceptance/create_list_spec.rb +41 -0
  25. data/spec/acceptance/create_spec.rb +39 -10
  26. data/spec/acceptance/stub_spec.rb +40 -13
  27. data/spec/acceptance/syntax/vintage_spec.rb +10 -10
  28. data/spec/acceptance/traits_spec.rb +1 -1
  29. data/spec/acceptance/transient_attributes_spec.rb +2 -2
  30. data/spec/factory_girl/association_runner_spec.rb +31 -0
  31. data/spec/factory_girl/attribute/association_spec.rb +0 -1
  32. data/spec/factory_girl/attribute_spec.rb +0 -1
  33. data/spec/factory_girl/declaration/implicit_spec.rb +0 -1
  34. data/spec/factory_girl/factory_spec.rb +16 -16
  35. data/spec/factory_girl/{proxy → strategy}/attributes_for_spec.rb +2 -2
  36. data/spec/factory_girl/strategy/build_spec.rb +7 -0
  37. data/spec/factory_girl/{proxy → strategy}/create_spec.rb +3 -3
  38. data/spec/factory_girl/{proxy → strategy}/stub_spec.rb +4 -4
  39. data/spec/factory_girl/strategy_spec.rb +21 -0
  40. data/spec/support/shared_examples/strategy.rb +112 -0
  41. metadata +47 -48
  42. data/gemfiles/2.1.gemfile +0 -8
  43. data/gemfiles/2.1.gemfile.lock +0 -74
  44. data/lib/factory_girl/proxy.rb +0 -64
  45. data/lib/factory_girl/proxy/build.rb +0 -27
  46. data/spec/factory_girl/proxy/build_spec.rb +0 -7
  47. data/spec/factory_girl/proxy_spec.rb +0 -19
  48. data/spec/support/shared_examples/proxy.rb +0 -90
data/.travis.yml CHANGED
@@ -7,7 +7,6 @@ before_install:
7
7
  - gem update --system
8
8
  script: "bundle exec rake spec:unit spec:acceptance features"
9
9
  gemfile:
10
- - gemfiles/2.1.gemfile
11
10
  - gemfiles/2.3.gemfile
12
11
  - gemfiles/3.0.gemfile
13
12
  - gemfiles/3.1.gemfile
data/Changelog CHANGED
@@ -1,3 +1,9 @@
1
+ 2.6.0 (February 17, 2012)
2
+ Improve documentation of has_many associations in the GETTING_STARTED
3
+ document
4
+ Deprecate :method in favor of :strategy when overriding an association's
5
+ build strategy
6
+
1
7
  2.5.2 (February 10, 2012)
2
8
  Fix step definitions to use associations defined in parent factories
3
9
  Add inline trait support to (build|create)_list
data/GETTING_STARTED.md CHANGED
@@ -165,7 +165,7 @@ end
165
165
  Dependent Attributes
166
166
  --------------------
167
167
 
168
- Attributes can be based on the values of other attributes using the proxy that is yielded to lazy attribute blocks:
168
+ Attributes can be based on the values of other attributes using the evaluator that is yielded to lazy attribute blocks:
169
169
 
170
170
  ```ruby
171
171
  factory :user do
@@ -193,8 +193,8 @@ factory :user do
193
193
  name { "John Doe#{" - Rockstar" if rockstar}" }
194
194
  email { "#{name.downcase}@example.com" }
195
195
 
196
- after_create do |user, proxy|
197
- user.name.upcase! if proxy.upcased
196
+ after_create do |user, evaluator|
197
+ user.name.upcase! if evaluator.upcased
198
198
  end
199
199
  end
200
200
 
@@ -207,8 +207,8 @@ within attributes\_for and won't be set on the model, even if the attribute
207
207
  exists or you attempt to override it.
208
208
 
209
209
  Within Factory Girl's dynamic attributes, you can access ignored attributes as
210
- you would expect. If you need to access the proxy in a Factory Girl callback,
211
- you'll need to declare a second block argument (for the proxy) and access
210
+ you would expect. If you need to access the evaluator in a Factory Girl callback,
211
+ you'll need to declare a second block argument (for the evaluator) and access
212
212
  ignored attributes from there.
213
213
 
214
214
  Associations
@@ -246,12 +246,12 @@ post.new_record? # => true
246
246
  post.author.new_record? # => false
247
247
  ```
248
248
 
249
- To not save the associated object, specify :method => :build in the factory:
249
+ To not save the associated object, specify :strategy => :build in the factory:
250
250
 
251
251
  ```ruby
252
252
  factory :post do
253
253
  # ...
254
- association :author, :factory => :user, :method => :build
254
+ association :author, :factory => :user, :strategy => :build
255
255
  end
256
256
 
257
257
  # Builds a User, and then builds a Post, but does not save either
@@ -260,6 +260,51 @@ post.new_record? # => true
260
260
  post.author.new_record? # => true
261
261
  ```
262
262
 
263
+ Generating data for a `has_many` relationship is a bit more involved,
264
+ depending on the amount of flexibility desired, but here's a surefire example
265
+ of generating associated data.
266
+
267
+ ```ruby
268
+ FactoryGirl.define do
269
+
270
+ # post factory with a `belongs_to` association for the user
271
+ factory :post do
272
+ title "Through the Looking Glass"
273
+ user
274
+ end
275
+
276
+ # user factory without associated posts
277
+ factory :user do
278
+ name "John Doe"
279
+
280
+ # user_with_posts will create post data after the user has been created
281
+ factory :user_with_posts do
282
+ # posts_count is declared as an ignored attribute and available in
283
+ # attributes on the factory, as well as the callback via the evaluator
284
+ ignore do
285
+ posts_count 5
286
+ end
287
+
288
+ # the after_create yields two values; the user instance itself and the
289
+ # evaluator, which stores all values from the factory, including ignored
290
+ # attributes; `create_list`'s second argument is the number of records
291
+ # to create and we make sure the user is associated properly to the post
292
+ after_create do |user, evaluator|
293
+ FactoryGirl.create_list(:post, evaluator.posts_count, :user => user)
294
+ end
295
+ end
296
+ end
297
+ end
298
+ ```
299
+
300
+ This allows us to do:
301
+
302
+ ```ruby
303
+ FactoryGirl.create(:user).posts.length # 0
304
+ FactoryGirl.create(:user_with_posts).posts.length # 5
305
+ FactoryGirl.create(:user_with_posts, :posts_count => 15).posts.length # 15
306
+ ```
307
+
263
308
  Inheritance
264
309
  -----------
265
310
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- factory_girl (2.5.2)
4
+ factory_girl (2.6.0)
5
5
  activesupport (>= 2.3.9)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/joshuaclayton/dev/gems/factory_girl
3
3
  specs:
4
- factory_girl (2.5.2)
4
+ factory_girl (2.6.0)
5
5
  activesupport (>= 2.3.9)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/joshuaclayton/dev/gems/factory_girl
3
3
  specs:
4
- factory_girl (2.5.2)
4
+ factory_girl (2.6.0)
5
5
  activesupport (>= 2.3.9)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/joshuaclayton/dev/gems/factory_girl
3
3
  specs:
4
- factory_girl (2.5.2)
4
+ factory_girl (2.6.0)
5
5
  activesupport (>= 2.3.9)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/joshuaclayton/dev/gems/factory_girl
3
3
  specs:
4
- factory_girl (2.5.2)
4
+ factory_girl (2.6.0)
5
5
  activesupport (>= 2.3.9)
6
6
 
7
7
  GEM
data/lib/factory_girl.rb CHANGED
@@ -1,7 +1,8 @@
1
1
  require "active_support/core_ext/module/delegation"
2
2
 
3
3
  require 'factory_girl/errors'
4
- require 'factory_girl/proxy'
4
+ require 'factory_girl/association_runner'
5
+ require 'factory_girl/strategy'
5
6
  require 'factory_girl/registry'
6
7
  require 'factory_girl/null_factory'
7
8
  require 'factory_girl/null_object'
@@ -0,0 +1,50 @@
1
+ module FactoryGirl
2
+ class AssociationRunner
3
+ def initialize(factory_name, strategy_name_or_object, overrides)
4
+ @factory_name = factory_name
5
+ @strategy_name_or_object = strategy_name_or_object
6
+ @overrides = overrides
7
+ end
8
+
9
+ def run(strategy_override = nil)
10
+ strategy_name_or_object = strategy_override || @strategy_name_or_object
11
+ strategy = StrategyCalculator.new(strategy_name_or_object).strategy
12
+ factory.run(strategy, @overrides)
13
+ end
14
+
15
+ private
16
+
17
+ def factory
18
+ FactoryGirl.factory_by_name(@factory_name)
19
+ end
20
+
21
+ class StrategyCalculator
22
+ def initialize(name_or_object)
23
+ @name_or_object = name_or_object
24
+ end
25
+
26
+ def strategy
27
+ if strategy_is_object?
28
+ @name_or_object
29
+ else
30
+ strategy_name_to_object
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def strategy_is_object?
37
+ @name_or_object.is_a?(Class) && @name_or_object.ancestors.include?(::FactoryGirl::Strategy)
38
+ end
39
+
40
+ def strategy_name_to_object
41
+ case @name_or_object
42
+ when :build then Strategy::Build
43
+ when :create then Strategy::Create
44
+ when nil then Strategy::Create
45
+ else raise "unrecognized method #{@name_or_object}"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -22,7 +22,7 @@ module FactoryGirl
22
22
  # instance is generated. Lazy attribute blocks will not be called if that
23
23
  # attribute is overridden for a specific instance.
24
24
  #
25
- # When defining lazy attributes, an instance of FactoryGirl::Proxy will
25
+ # When defining lazy attributes, an instance of FactoryGirl::Strategy will
26
26
  # be yielded, allowing associations to be built using the correct build
27
27
  # strategy.
28
28
  #
@@ -1,3 +1,4 @@
1
+ require "active_support/core_ext/hash/except"
1
2
  require "active_support/core_ext/class/attribute"
2
3
 
3
4
  module FactoryGirl
@@ -29,7 +30,17 @@ module FactoryGirl
29
30
  @build_strategy.add_observer(CallbackRunner.new(self.class.callbacks, self))
30
31
  end
31
32
 
32
- delegate :association, :to => :@build_strategy
33
+ def association(factory_name, overrides = {})
34
+ build_strategy = if overrides.has_key?(:method)
35
+ $stderr.puts "DEPRECATION WARNING: using :method to specify a build strategy is deprecated; use :strategy instead"
36
+ overrides[:method]
37
+ elsif overrides.has_key?(:strategy)
38
+ overrides[:strategy]
39
+ end
40
+
41
+ runner = AssociationRunner.new(factory_name, build_strategy, overrides.except(:method, :strategy))
42
+ @build_strategy.association(runner)
43
+ end
33
44
 
34
45
  def instance=(object_instance)
35
46
  @instance = object_instance
@@ -36,16 +36,16 @@ module FactoryGirl
36
36
  @default_strategy || parent.default_strategy
37
37
  end
38
38
 
39
- def run(proxy_class, overrides, &block) #:nodoc:
39
+ def run(strategy_class, overrides, &block) #:nodoc:
40
40
  block ||= lambda {|result| result }
41
41
  compile
42
42
 
43
- proxy = proxy_class.new
43
+ strategy = strategy_class.new
44
44
 
45
- evaluator = evaluator_class.new(proxy, overrides.symbolize_keys)
45
+ evaluator = evaluator_class.new(strategy, overrides.symbolize_keys)
46
46
  attribute_assigner = AttributeAssigner.new(evaluator, &instance_builder)
47
47
 
48
- proxy.result(attribute_assigner, to_create).tap(&block)
48
+ strategy.result(attribute_assigner, to_create).tap(&block)
49
49
  end
50
50
 
51
51
  def human_names
@@ -133,7 +133,7 @@ module FactoryGirl
133
133
  options.assert_valid_keys(:class, :parent, :default_strategy, :aliases, :traits)
134
134
 
135
135
  if options[:default_strategy]
136
- Proxy.ensure_strategy_exists!(options[:default_strategy])
136
+ Strategy.ensure_strategy_exists!(options[:default_strategy])
137
137
  $stderr.puts "DEPRECATION WARNING: default_strategy is deprecated."
138
138
  $stderr.puts "Override to_create if you need to prevent a call to #save!."
139
139
  end
@@ -0,0 +1,32 @@
1
+ require "factory_girl/strategy/build"
2
+ require "factory_girl/strategy/create"
3
+ require "factory_girl/strategy/attributes_for"
4
+ require "factory_girl/strategy/stub"
5
+ require "observer"
6
+
7
+ module FactoryGirl
8
+ class Strategy #:nodoc:
9
+ include Observable
10
+
11
+ def association(runner)
12
+ raise NotImplementedError, "Strategies must return an association"
13
+ end
14
+
15
+ def result(attribute_assigner, to_create)
16
+ raise NotImplementedError, "Strategies must return a result"
17
+ end
18
+
19
+ def self.ensure_strategy_exists!(strategy)
20
+ unless Strategy.const_defined? strategy.to_s.camelize
21
+ raise ArgumentError, "Unknown strategy: #{strategy}"
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def run_callbacks(name, result_instance)
28
+ changed
29
+ notify_observers(name, result_instance)
30
+ end
31
+ end
32
+ end
@@ -1,6 +1,9 @@
1
1
  module FactoryGirl
2
- class Proxy #:nodoc:
3
- class AttributesFor < Proxy #:nodoc:
2
+ class Strategy #:nodoc:
3
+ class AttributesFor < Strategy #:nodoc:
4
+ def association(runner)
5
+ end
6
+
4
7
  def result(attribute_assigner, to_create)
5
8
  attribute_assigner.hash
6
9
  end
@@ -0,0 +1,15 @@
1
+ module FactoryGirl
2
+ class Strategy #:nodoc:
3
+ class Build < Strategy #:nodoc:
4
+ def association(runner)
5
+ runner.run
6
+ end
7
+
8
+ def result(attribute_assigner, to_create)
9
+ attribute_assigner.object.tap do |result_instance|
10
+ run_callbacks(:after_build, result_instance)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,6 +1,10 @@
1
1
  module FactoryGirl
2
- class Proxy #:nodoc:
3
- class Create < Build #:nodoc:
2
+ class Strategy #:nodoc:
3
+ class Create < Strategy #:nodoc:
4
+ def association(runner)
5
+ runner.run
6
+ end
7
+
4
8
  def result(attribute_assigner, to_create)
5
9
  attribute_assigner.object.tap do |result_instance|
6
10
  run_callbacks(:after_build, result_instance)
@@ -1,11 +1,10 @@
1
1
  module FactoryGirl
2
- class Proxy
3
- class Stub < Proxy #:nodoc:
2
+ class Strategy
3
+ class Stub < Strategy #:nodoc:
4
4
  @@next_id = 1000
5
5
 
6
- def association(factory_name, overrides = {})
7
- factory = FactoryGirl.factory_by_name(factory_name)
8
- factory.run(Proxy::Stub, overrides.except(:method))
6
+ def association(runner)
7
+ runner.run(Strategy::Stub)
9
8
  end
10
9
 
11
10
  def result(attribute_assigner, to_create)
@@ -43,7 +43,7 @@ module FactoryGirl
43
43
 
44
44
  def generate(overrides = {}, &block)
45
45
  factory = FactoryGirl.factory_by_name(name.underscore)
46
- instance = factory.run(Proxy::Build, overrides)
46
+ instance = factory.run(Strategy::Build, overrides)
47
47
  instance.save
48
48
  yield(instance) if block_given?
49
49
  instance
@@ -51,14 +51,14 @@ module FactoryGirl
51
51
 
52
52
  def generate!(overrides = {}, &block)
53
53
  factory = FactoryGirl.factory_by_name(name.underscore)
54
- instance = factory.run(Proxy::Create, overrides)
54
+ instance = factory.run(Strategy::Create, overrides)
55
55
  yield(instance) if block_given?
56
56
  instance
57
57
  end
58
58
 
59
59
  def spawn(overrides = {}, &block)
60
60
  factory = FactoryGirl.factory_by_name(name.underscore)
61
- instance = factory.run(Proxy::Build, overrides)
61
+ instance = factory.run(Strategy::Build, overrides)
62
62
  yield(instance) if block_given?
63
63
  instance
64
64
  end
@@ -28,11 +28,11 @@ module FactoryGirl
28
28
  module ClassMethods #:nodoc:
29
29
 
30
30
  def make(overrides = {})
31
- FactoryGirl.factory_by_name(name.underscore).run(Proxy::Build, overrides)
31
+ FactoryGirl.factory_by_name(name.underscore).run(Strategy::Build, overrides)
32
32
  end
33
33
 
34
34
  def make!(overrides = {})
35
- FactoryGirl.factory_by_name(name.underscore).run(Proxy::Create, overrides)
35
+ FactoryGirl.factory_by_name(name.underscore).run(Strategy::Create, overrides)
36
36
  end
37
37
 
38
38
  end
@@ -18,7 +18,7 @@ module FactoryGirl
18
18
  # A set of attributes that can be used to build an instance of the class
19
19
  # this factory generates.
20
20
  def attributes_for(name, *traits_and_overrides, &block)
21
- run_factory_girl_proxy(name, traits_and_overrides, Proxy::AttributesFor, &block)
21
+ run_factory_girl_strategy(name, traits_and_overrides, Strategy::AttributesFor, &block)
22
22
  end
23
23
 
24
24
  # Generates and returns an instance from this factory. Attributes can be
@@ -37,7 +37,7 @@ module FactoryGirl
37
37
  # An instance of the class this factory generates, with generated attributes
38
38
  # assigned.
39
39
  def build(name, *traits_and_overrides, &block)
40
- run_factory_girl_proxy(name, traits_and_overrides, Proxy::Build, &block)
40
+ run_factory_girl_strategy(name, traits_and_overrides, Strategy::Build, &block)
41
41
  end
42
42
 
43
43
  # Generates, saves, and returns an instance from this factory. Attributes can
@@ -60,7 +60,7 @@ module FactoryGirl
60
60
  # A saved instance of the class this factory generates, with generated
61
61
  # attributes assigned.
62
62
  def create(name, *traits_and_overrides, &block)
63
- run_factory_girl_proxy(name, traits_and_overrides, Proxy::Create, &block)
63
+ run_factory_girl_strategy(name, traits_and_overrides, Strategy::Create, &block)
64
64
  end
65
65
 
66
66
  # Generates and returns an object with all attributes from this factory
@@ -79,7 +79,7 @@ module FactoryGirl
79
79
  # Returns: +Object+
80
80
  # An object with generated attributes stubbed out.
81
81
  def build_stubbed(name, *traits_and_overrides, &block)
82
- run_factory_girl_proxy(name, traits_and_overrides, Proxy::Stub, &block)
82
+ run_factory_girl_strategy(name, traits_and_overrides, Strategy::Stub, &block)
83
83
  end
84
84
 
85
85
  # Builds and returns multiple instances from this factory as an array. Attributes can be
@@ -134,7 +134,7 @@ module FactoryGirl
134
134
 
135
135
  private
136
136
 
137
- def run_factory_girl_proxy(name, traits_and_overrides, proxy, &block)
137
+ def run_factory_girl_strategy(name, traits_and_overrides, strategy, &block)
138
138
  overrides = if traits_and_overrides.last.respond_to?(:has_key?)
139
139
  traits_and_overrides.pop
140
140
  else
@@ -147,7 +147,7 @@ module FactoryGirl
147
147
  factory = factory.with_traits(traits_and_overrides)
148
148
  end
149
149
 
150
- factory.run(proxy, overrides, &block)
150
+ factory.run(strategy, overrides, &block)
151
151
  end
152
152
  end
153
153
  end