gabrielg-factory_girl 1.1.8 → 1.1.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  class Factory
2
-
2
+
3
3
  cattr_accessor :factories #:nodoc:
4
4
  self.factories = {}
5
5
 
@@ -10,7 +10,7 @@ class Factory
10
10
  cattr_accessor :definition_file_paths
11
11
  self.definition_file_paths = %w(factories test/factories spec/factories)
12
12
 
13
- attr_reader :factory_name
13
+ attr_reader :factory_name, :inherited_factory
14
14
 
15
15
  # Defines a new factory that can be used by the build strategies (create and
16
16
  # build) to build new objects.
@@ -20,14 +20,16 @@ class Factory
20
20
  # A unique name used to identify this factory.
21
21
  # options: (Hash)
22
22
  # class: the class that will be used when generating instances for this
23
- # factory. If not specified, the class will be guessed from the
23
+ # factory. If not specified, the class will be guessed from the
24
24
  # factory name.
25
25
  #
26
26
  # Yields:
27
27
  # The newly created factory (Factory)
28
28
  def self.define (name, options = {})
29
29
  inherit_from = options.delete(:inherit)
30
- instance = (inherit_from.nil?) ? Factory.new(name, options) : self.factories[inherit_from]
30
+ options = inherit_from ? options.merge(:inherit => factories[inherit_from]) : options
31
+ raise(ArgumentError, "Inherited factory not defined") if inherit_from && options[:inherit].blank?
32
+ instance = Factory.new(name, options)
31
33
  yield(instance)
32
34
  self.factories[instance.factory_name] = instance
33
35
  end
@@ -37,7 +39,7 @@ class Factory
37
39
  end
38
40
 
39
41
  def initialize (name, options = {}) #:nodoc:
40
- options.assert_valid_keys(:class)
42
+ options.assert_valid_keys(:class, :inherit)
41
43
  @factory_name = factory_name_for(name)
42
44
  @options = options
43
45
  @attributes = []
@@ -45,6 +47,8 @@ class Factory
45
47
  @lazy_attribute_blocks = {}
46
48
  @lazy_attribute_names = []
47
49
  @callbacks = {}
50
+ @inherited_factory = options[:inherit]
51
+ @options[:class] = inherited_factory.build_class if inherited_factory && !@options.has_key?(:class)
48
52
  end
49
53
 
50
54
  # Adds an attribute that should be assigned on generated instances for this
@@ -88,7 +92,7 @@ class Factory
88
92
  # f.add_attribute :name, 'Billy Idol'
89
93
  # end
90
94
  #
91
- # are equivilent.
95
+ # are equivilent.
92
96
  def method_missing (name, *args, &block)
93
97
  add_attribute(name, *args, &block)
94
98
  end
@@ -133,13 +137,16 @@ class Factory
133
137
  def create (attrs = {}) #:nodoc:
134
138
  instance, final_attrs = build_instance(attrs, :create)
135
139
  instance.save!
136
- instance_exec(instance, final_attrs, &@callbacks[:after_create]) unless @callbacks[:after_create].nil?
140
+ if callback = @callbacks[:after_create]
141
+ params = (callback.arity > 1) ? [instance, final_attrs] : [instance]
142
+ instance_exec(*params, &callback)
143
+ end
137
144
  instance
138
145
  end
139
146
 
140
- # Allows a block to be evaluated after the factory object has been built, but before
141
- # it is saved to the database. The block is passed the instance so you can do stuff
142
- # to it. For example, maybe you want to stub a method whose result normally relies on
147
+ # Allows a block to be evaluated after the factory object has been built, but before
148
+ # it is saved to the database. The block is passed the instance so you can do stuff
149
+ # to it. For example, maybe you want to stub a method whose result normally relies on
143
150
  # complex computation on attributes and associations:
144
151
  #
145
152
  # Factory.define :a_boy_that_never_goes_out, :class => Boy do |f|
@@ -152,7 +159,7 @@ class Factory
152
159
  @callbacks[:after_build] = block
153
160
  end
154
161
 
155
- # Allows a block to be evaluated after the factory object has been saved to the
162
+ # Allows a block to be evaluated after the factory object has been saved to the
156
163
  # database. The block is passed the instance so you can do stuff to it. For example
157
164
  # maybe you want to stub a method whose result normally relies on complex computation
158
165
  # on attributes and associations:
@@ -239,13 +246,13 @@ class Factory
239
246
  def build_attributes_hash (values, strategy)
240
247
  values = values.symbolize_keys
241
248
  passed_keys = values.keys.collect {|key| Factory.aliases_for(key) }.flatten
242
- @attributes.each do |attribute|
243
- unless passed_keys.include?(attribute.name)
244
- proxy = AttributeProxy.new(self, attribute.name, strategy, values)
245
- values[attribute.name] = attribute.value(proxy)
246
- end
249
+ attrs = @attributes.inject(values) do |vals,attribute|
250
+ next(vals) if passed_keys.include?(attribute.name)
251
+ proxy = AttributeProxy.new(self, attribute.name, strategy, vals)
252
+ vals[attribute.name] = attribute.value(proxy)
253
+ vals
247
254
  end
248
- values
255
+ inherited_factory ? inherited_factory.attributes_for.merge(attrs) : attrs
249
256
  end
250
257
 
251
258
  def build_instance (override, strategy)
@@ -254,7 +261,10 @@ class Factory
254
261
  attrs.each do |attr, value|
255
262
  instance.send(:"#{attr}=", value) if instance.respond_to?(:"#{attr}=")
256
263
  end
257
- instance_exec(instance, attrs, &@callbacks[:after_build]) unless @callbacks[:after_build].nil?
264
+ if callback = @callbacks[:after_build]
265
+ params = (callback.arity > 1) ? [instance, attrs] : [instance]
266
+ instance_exec(*params, &callback)
267
+ end
258
268
  [instance, attrs]
259
269
  end
260
270
 
data/test/factory_test.rb CHANGED
@@ -46,13 +46,13 @@ class FactoryTest < Test::Unit::TestCase
46
46
 
47
47
  should "add the factory to the list of factories" do
48
48
  Factory.define(@name) {|f| }
49
- assert_equal Factory.factories[@name],
49
+ assert_equal Factory.factories[@name],
50
50
  @factory,
51
51
  "Factories: #{Factory.factories.inspect}"
52
52
  end
53
53
 
54
54
  end
55
-
55
+
56
56
  context "a factory" do
57
57
 
58
58
  setup do
@@ -68,7 +68,7 @@ class FactoryTest < Test::Unit::TestCase
68
68
  should "have a build class" do
69
69
  assert_equal @class, @factory.build_class
70
70
  end
71
-
71
+
72
72
  should "have a set of callbacks" do
73
73
  assert @factory.instance_eval {@callbacks}
74
74
  end
@@ -77,6 +77,62 @@ class FactoryTest < Test::Unit::TestCase
77
77
  assert @factory.instance_eval {@callbacks.empty?}
78
78
  end
79
79
 
80
+ context "when inheriting from a prior factory" do
81
+ setup do
82
+ @factory.foo "bar"
83
+ @factory.snafu "foo"
84
+ @new_factory = Factory.new(:user_with_stuff, :inherit => @factory)
85
+ @new_factory.foo "fighters"
86
+ @instance = @new_factory.build
87
+ end
88
+
89
+ should "use subfactory's class if not specified" do
90
+ assert_equal User, @factory.build_class
91
+ end
92
+
93
+ should "allow overriding subfactory's class" do
94
+ newer_factory = Factory.new(:user_with_more_stuff, :inherit => @new_factory, :class => Post)
95
+ assert_equal Post, newer_factory.build_class
96
+ end
97
+
98
+ should "override previously configured attributes" do
99
+ assert_equal "fighters", @instance.foo
100
+ end
101
+
102
+ should "inherit attributes that arent overridden" do
103
+ assert_equal "foo", @instance.snafu
104
+ end
105
+
106
+ end
107
+
108
+ context "when defining an inheriting factory" do
109
+ setup do
110
+ @original_user_with_stuff_factory = Factory.factories[:user_with_stuff]
111
+ end
112
+
113
+ teardown do
114
+ Factory.factories[:user_with_stuff] = @original_user_with_stuff_factory
115
+ end
116
+
117
+ should "pass in an instance of the inherited factory as the inherited_factory" do
118
+ assert_not_nil Factory.factories[:user]
119
+ instance = Factory.define(:user_with_stuff, :inherit => :user) {}
120
+ assert_equal Factory.factories[:user], instance.inherited_factory
121
+ end
122
+
123
+ should "get its own factory definition" do
124
+ instance = Factory.define(:user_with_stuff, :inherit => :user) { }
125
+ assert_equal instance, Factory.factories[:user_with_stuff]
126
+ end
127
+
128
+ should "raise if inherited factory isnt found" do
129
+ assert_raise(ArgumentError) do
130
+ Factory.define(:user_with_stuff, :inherit => :foobar) { }
131
+ end
132
+ end
133
+
134
+ end
135
+
80
136
  context "when adding an after_build callback" do
81
137
  setup do
82
138
  @the_block = lambda{|u| }
@@ -86,7 +142,7 @@ class FactoryTest < Test::Unit::TestCase
86
142
  should "have something in the set of callbacks" do
87
143
  assert_equal 1, @factory.instance_eval {@callbacks.size}
88
144
  end
89
-
145
+
90
146
  should "record the callback in the set of callbacks" do
91
147
  assert @factory.instance_eval {@callbacks.values}.include?(@the_block)
92
148
  end
@@ -94,6 +150,7 @@ class FactoryTest < Test::Unit::TestCase
94
150
  should "record the callback in the set of callbacks under the after_build key" do
95
151
  assert_equal @the_block, @factory.instance_eval {@callbacks[:after_build]}
96
152
  end
153
+
97
154
  end
98
155
 
99
156
  context "when adding an after_create callback" do
@@ -105,7 +162,7 @@ class FactoryTest < Test::Unit::TestCase
105
162
  should "have something in the set of callbacks" do
106
163
  assert_equal 1, @factory.instance_eval {@callbacks.size}
107
164
  end
108
-
165
+
109
166
  should "record the callback in the set of callbacks" do
110
167
  assert @factory.instance_eval {@callbacks.values}.include?(@the_block)
111
168
  end
@@ -177,7 +234,7 @@ class FactoryTest < Test::Unit::TestCase
177
234
  end
178
235
 
179
236
  context "when other attributes have previously been defined" do
180
-
237
+
181
238
  setup do
182
239
  @attr = :unimportant
183
240
  @attrs = {
@@ -237,11 +294,11 @@ class FactoryTest < Test::Unit::TestCase
237
294
  end
238
295
 
239
296
  end
240
-
297
+
241
298
  context "specifying an association on a factory with a count" do
242
299
  setup do
243
300
  Factory.define(:post) { |f| f.name "Article" }
244
- Factory.define(:user) do |u|
301
+ Factory.define(:user) do |u|
245
302
  u.first_name "Joe"
246
303
  u.last_name "Bloggs"
247
304
  u.email "joe@example.com"
@@ -249,20 +306,20 @@ class FactoryTest < Test::Unit::TestCase
249
306
  end
250
307
  @user = Factory(:user)
251
308
  end
252
-
309
+
253
310
  should "set up five associated post objects" do
254
311
  assert_equal 5, @user.posts.size
255
312
  end
256
-
313
+
257
314
  should "have the user as the author on each object" do
258
315
  @user.posts.each { |p| assert_equal @user, p.author }
259
316
  end
260
-
317
+
261
318
  should "have saved all the posts" do
262
319
  @user.posts.each { |p| assert !p.new_record? }
263
320
  end
264
-
265
- end
321
+
322
+ end
266
323
 
267
324
  should "add an attribute using the method name when passed an undefined method" do
268
325
  @attr = :first_name
@@ -380,84 +437,111 @@ class FactoryTest < Test::Unit::TestCase
380
437
  end
381
438
 
382
439
  context "and an after_build callback has been registered" do
440
+ saved = nil
383
441
  setup do
384
- @the_block = lambda {|user| assert user.new_record?; @saved = user}
385
-
442
+ @the_block = lambda {|user| assert user.new_record?; saved = user}
443
+
386
444
  @factory.after_build &@the_block
387
445
  end
388
-
446
+
389
447
  should "call the callback when the object is built" do
390
- @the_block.expects(:call).once
448
+ @factory.expects(:instance_exec)
391
449
  @factory.build
392
450
  end
393
451
 
394
452
  should "call the callback when the object is created" do
395
- @the_block.expects(:call).once
453
+ @factory.expects(:instance_exec)
396
454
  @factory.create
397
455
  end
398
456
 
457
+ should "yield the instance to block if block arity is <= 1" do
458
+ @factory.after_build(&(lambda{|user|}))
459
+ @factory.expects(:instance_exec).with(anything)
460
+ @factory.build
461
+ end
462
+
463
+ should "yield the instance and attrs to block if block arity is > 1" do
464
+ @factory.after_build(&(lambda{|user,attrs|}))
465
+ @factory.expects(:instance_exec).with(anything, instance_of(Hash))
466
+ @factory.build
467
+ end
468
+
399
469
  should "yield the instance to the callback when called" do
400
470
  instance = @factory.build
401
- assert_equal @saved, instance
471
+ assert_equal saved, instance
402
472
  end
403
473
  end
404
474
 
405
475
  context "and an after_create callback has been registered" do
476
+ saved = nil
406
477
  setup do
407
- @the_block = lambda {|user| assert !user.new_record?; @saved = user}
408
-
478
+ @the_block = lambda {|user| assert !user.new_record?; saved = user}
479
+
409
480
  @factory.after_create &@the_block
410
481
  end
411
-
482
+
412
483
  should "not call the callback when the object is built" do
413
484
  @the_block.expects(:call).never
414
485
  @factory.build
415
486
  end
416
487
 
417
488
  should "call the callback when the object is created" do
418
- @the_block.expects(:call).once
489
+ @factory.expects(:instance_exec)
490
+ @factory.create
491
+ end
492
+
493
+ should "yield the instance to block if block arity is <= 1" do
494
+ @factory.after_create(&(lambda{|user|}))
495
+ @factory.expects(:instance_exec).with(anything)
496
+ @factory.create
497
+ end
498
+
499
+ should "yield the instance and attrs to block if block arity is > 1" do
500
+ @factory.after_create(&(lambda{|user,attrs|}))
501
+ @factory.expects(:instance_exec).with(anything, instance_of(Hash))
419
502
  @factory.create
420
503
  end
421
504
 
422
505
  should "yield the instance to the callback when called" do
423
506
  instance = @factory.create
424
- assert_equal @saved, instance
507
+ assert_equal saved, instance
425
508
  end
426
509
  end
427
510
 
428
511
  context "and both after_build and after_create callbacks have been registered" do
512
+ post_build, = post_create = nil
429
513
  setup do
430
- @the_after_build_block = lambda {|user| assert user.new_record?; @post_build = user}
431
- @the_after_create_block = lambda {|user| assert !user.new_record?; @post_create = user}
432
-
514
+ test = self
515
+ @the_after_build_block = lambda {|user| test.assert(user.new_record?); post_build = user}
516
+ @the_after_create_block = lambda {|user| test.assert(!user.new_record?); post_create = user}
517
+
433
518
  @factory.after_build &@the_after_build_block
434
519
  @factory.after_create &@the_after_create_block
435
520
  end
436
-
521
+
437
522
  should "only call the after_build callback when the object is built" do
438
- @the_after_build_block.expects(:call).once
439
- @the_after_create_block.expects(:call).never
523
+ @factory.expects(:instance_exec).once
440
524
  @factory.build
441
525
  end
442
526
 
443
527
  should "call both callbacks when the object is created" do
444
- @the_after_build_block.expects(:call).once
445
- @the_after_create_block.expects(:call).once
528
+ @factory.expects(:instance_exec).at_least(2)
446
529
  @factory.create
447
530
  end
448
531
 
449
532
  should "yield the same instance to each callback when called" do
450
533
  instance = @factory.create
451
- assert_equal @post_build, instance
452
- assert_equal @post_create, instance
453
- assert_equal @post_create, @post_build
534
+ assert_equal post_build, instance
535
+ assert_equal post_create, instance
536
+ assert_equal post_create, post_build
454
537
  end
455
-
538
+
456
539
  should "call the after_build callback before the after_create callback when objects are created" do
457
540
  # TODO - is this good enough to detect "beforeness"?
458
- @the_after_build_block = lambda {|user| assert_nil @post_build; assert_nil @post_create; @post_build = user}
459
- @the_after_create_block = lambda {|user| assert_not_nil @post_build; assert_nil @post_create; @post_create = user}
460
-
541
+ test = self
542
+ @the_after_build_block = lambda {|user| test.assert_nil @post_build; test.assert_nil @post_create; @post_build = user}
543
+ @the_after_create_block = lambda {|user| test.assert_not_nil @post_build; test.assert_nil @post_create; @post_create = user}
544
+
461
545
  @factory.after_build &@the_after_build_block
462
546
  @factory.after_create &@the_after_create_block
463
547
  @factory.create
@@ -477,7 +561,7 @@ class FactoryTest < Test::Unit::TestCase
477
561
  end
478
562
 
479
563
  end
480
-
564
+
481
565
  context "when creating an instance" do
482
566
 
483
567
  setup do
data/test/models.rb CHANGED
@@ -22,6 +22,7 @@ end
22
22
  CreateSchema.suppress_messages { CreateSchema.migrate(:up) }
23
23
 
24
24
  class User < ActiveRecord::Base
25
+ attr_accessor :foo, :snafu
25
26
  validates_presence_of :first_name, :last_name, :email
26
27
  has_many :posts, :foreign_key => 'author_id', :validate => false
27
28
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gabrielg-factory_girl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.8
4
+ version: 1.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Joe Ferris