masa-iwasaki-factory_girl 1.2.1.1 → 1.2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +56 -9
- data/Rakefile +19 -11
- data/lib/factory_girl.rb +2 -0
- data/lib/factory_girl/attribute/association.rb +2 -0
- data/lib/factory_girl/attribute/callback.rb +16 -0
- data/lib/factory_girl/attribute/dynamic.rb +1 -1
- data/lib/factory_girl/factory.rb +64 -44
- data/lib/factory_girl/proxy.rb +19 -0
- data/lib/factory_girl/proxy/build.rb +1 -0
- data/lib/factory_girl/proxy/create.rb +53 -1
- data/lib/factory_girl/proxy/stub.rb +7 -6
- data/lib/factory_girl/step_definitions.rb +54 -0
- data/spec/factory_girl/aliases_spec.rb +29 -0
- data/spec/factory_girl/attribute/association_spec.rb +29 -0
- data/spec/factory_girl/attribute/callback_spec.rb +23 -0
- data/spec/factory_girl/attribute/dynamic_spec.rb +49 -0
- data/spec/factory_girl/attribute/static_spec.rb +29 -0
- data/spec/factory_girl/attribute_spec.rb +30 -0
- data/spec/factory_girl/factory_spec.rb +582 -0
- data/spec/factory_girl/proxy/attributes_for_spec.rb +52 -0
- data/spec/factory_girl/proxy/build_spec.rb +81 -0
- data/spec/factory_girl/proxy/create_spec.rb +97 -0
- data/spec/factory_girl/proxy/stub_spec.rb +79 -0
- data/spec/factory_girl/proxy_spec.rb +84 -0
- data/spec/factory_girl/sequence_spec.rb +66 -0
- data/spec/factory_girl/syntax/blueprint_spec.rb +35 -0
- data/spec/factory_girl/syntax/generate_spec.rb +58 -0
- data/spec/factory_girl/syntax/make_spec.rb +35 -0
- data/spec/factory_girl/syntax/sham_spec.rb +36 -0
- data/spec/integration_spec.rb +304 -0
- data/spec/models.rb +43 -0
- data/spec/spec_helper.rb +18 -0
- metadata +49 -9
data/README.rdoc
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
= What this fork added to original factory_girl
|
2
|
-
==
|
2
|
+
== Caching
|
3
3
|
By default, the association created by factory_girl is based on Factory#create. This means there would be twice creation for project_1 in the code shown below.
|
4
4
|
|
5
5
|
# Factory definitions
|
@@ -26,9 +26,19 @@ By default, the association created by factory_girl is based on Factory#create.
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
-
This fork added Factory
|
29
|
+
This fork added @@instances to Factory::Proxy::Create. @@instances keeps instances which has already created. This means you would not have the creation of a same factory and the code shown above turns green.
|
30
30
|
|
31
|
-
|
31
|
+
== How to enable caching of instances
|
32
|
+
At default, all instances will be cached. But you can toggle this option by calling these methods:
|
33
|
+
|
34
|
+
- Factory::Proxy::Create.disable_cache
|
35
|
+
- Factory::Proxy::Create.enable_cache
|
36
|
+
|
37
|
+
== Other changes
|
38
|
+
These modification affects the definitions written in some syntax.
|
39
|
+
|
40
|
+
- If you are using bluprint or sham syntax, you might need to use "Factory.create(factory_name)" explicityly instead of "Facotry(factory_name)"
|
41
|
+
- With generate syntas, Factory.generate will raise an exception as same as Factory.generate!
|
32
42
|
|
33
43
|
= factory_girl
|
34
44
|
|
@@ -39,14 +49,13 @@ factory_girl is a fixtures replacement with a straightforward definition syntax,
|
|
39
49
|
Github: http://github.com/thoughtbot/factory_girl/tree/master
|
40
50
|
|
41
51
|
Gem:
|
42
|
-
gem install
|
52
|
+
gem install factory_girl --source http://gemcutter.org
|
43
53
|
|
44
|
-
Note: if you install factory_girl using the gem from
|
54
|
+
Note: if you install factory_girl using the gem from Gemcutter, you'll need this
|
45
55
|
in your environment.rb if you want to use Rails 2.1+'s dependency manager:
|
46
56
|
|
47
|
-
config.gem "
|
48
|
-
|
49
|
-
:source => "http://gems.github.com"
|
57
|
+
config.gem "factory_girl",
|
58
|
+
:source => "http://gemcutter.org"
|
50
59
|
|
51
60
|
== Defining factories
|
52
61
|
|
@@ -75,6 +84,8 @@ Each factory has a name and a set of attributes. The name is used to guess the c
|
|
75
84
|
|
76
85
|
It is highly recommended that you have one factory for each class that provides the simplest set of attributes necessary to create an instance of that class. If you're creating ActiveRecord objects, that means that you should only provide attributes that are required through validations and that do not have defaults. Other factories can be created through inheritance to cover common scenarios for each class.
|
77
86
|
|
87
|
+
Attempting to define multiple factories with the same name will raise an error.
|
88
|
+
|
78
89
|
Factories can either be defined anywhere, but will automatically be loaded if they are defined in files at the following locations:
|
79
90
|
|
80
91
|
test/factories.rb
|
@@ -112,7 +123,7 @@ The default strategy can be overriden:
|
|
112
123
|
|
113
124
|
user = Factory(:user)
|
114
125
|
|
115
|
-
No matter which
|
126
|
+
No matter which strategy is used, it's possible to override the defined attributes by passing a hash:
|
116
127
|
|
117
128
|
# Build a User instance and override the first_name property
|
118
129
|
user = Factory.build(:user, :first_name => 'Joe')
|
@@ -224,6 +235,41 @@ a particular factory:
|
|
224
235
|
f.sequence(:email) {|n| "person#{n}@example.com" }
|
225
236
|
end
|
226
237
|
|
238
|
+
== Callbacks
|
239
|
+
|
240
|
+
Factory_girl makes available three callbacks for injecting some code:
|
241
|
+
|
242
|
+
* after_build - called after a factory is built (via Factory.build)
|
243
|
+
* after_create - called after a factory is saved (via Factory.create)
|
244
|
+
* after_stub - called after a factory is stubbed (via Factory.stub)
|
245
|
+
|
246
|
+
Examples:
|
247
|
+
|
248
|
+
# Define a factory that calls the generate_hashed_password method after it is built
|
249
|
+
Factory.define :user do |u|
|
250
|
+
u.after_build { |user| do_something_to(user) }
|
251
|
+
end
|
252
|
+
|
253
|
+
Note that you'll have an instance of the user in the block. This can be useful.
|
254
|
+
|
255
|
+
You can also define multiple types of callbacks on the same factory:
|
256
|
+
|
257
|
+
Factory.define :user do |u|
|
258
|
+
u.after_build { |user| do_something_to(user) }
|
259
|
+
u.after_create { |user| do_something_else_to(user) }
|
260
|
+
end
|
261
|
+
|
262
|
+
Factories can also define any number of the same kind of callback. These callbacks will be executed in the order they are specified:
|
263
|
+
|
264
|
+
Factory.define :user do |u|
|
265
|
+
u.after_create { this_runs_first }
|
266
|
+
u.after_create { then_this }
|
267
|
+
end
|
268
|
+
|
269
|
+
Calling Factory.create will invoke both after_build and after_create callbacks.
|
270
|
+
|
271
|
+
Also, like standard attributes, child factories will inherit (and can define additional) callbacks from their parent factory.
|
272
|
+
|
227
273
|
== Alternate Syntaxes
|
228
274
|
|
229
275
|
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.
|
@@ -250,6 +296,7 @@ factory_girl was written by Joe Ferris with contributions from several authors,
|
|
250
296
|
* Jon Yurek
|
251
297
|
* Josh Nichols
|
252
298
|
* Josh Owens
|
299
|
+
* Nate Sutton
|
253
300
|
|
254
301
|
The syntax layers are derived from software written by the following authors:
|
255
302
|
* Pete Yandell
|
data/Rakefile
CHANGED
@@ -6,9 +6,10 @@ require 'rcov/rcovtask'
|
|
6
6
|
require 'date'
|
7
7
|
|
8
8
|
require 'spec/rake/spectask'
|
9
|
+
require 'cucumber/rake/task'
|
9
10
|
|
10
|
-
desc 'Default: run the specs.'
|
11
|
-
task :default => :spec
|
11
|
+
desc 'Default: run the specs and features.'
|
12
|
+
task :default => [:spec, :features]
|
12
13
|
|
13
14
|
Spec::Rake::SpecTask.new do |t|
|
14
15
|
t.spec_opts = ['--options', "spec/spec.opts"]
|
@@ -36,13 +37,14 @@ task :sync_docs => 'rdoc' do
|
|
36
37
|
end
|
37
38
|
|
38
39
|
spec = Gem::Specification.new do |s|
|
39
|
-
s.name = %q{factory_girl}
|
40
|
-
s.version = "1.2.
|
41
|
-
s.summary = %q{factory_girl
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
s.name = %q{masa-iwasaki-factory_girl}
|
41
|
+
s.version = "1.2.3.1"
|
42
|
+
s.summary = %q{factory_girl with singleton support}
|
43
|
+
s.description = %q{This forked factory_girl has been added a singleton
|
44
|
+
support. You can specify ':singleton => true' option
|
45
|
+
on factory definition and an instance created by this
|
46
|
+
definition will be an singleton instance.
|
47
|
+
}
|
46
48
|
|
47
49
|
s.files = FileList['[A-Z]*', 'lib/**/*.rb', 'spec/**/*.rb']
|
48
50
|
s.require_path = 'lib'
|
@@ -52,8 +54,9 @@ spec = Gem::Specification.new do |s|
|
|
52
54
|
s.extra_rdoc_files = ["README.rdoc"]
|
53
55
|
s.rdoc_options = ['--line-numbers', "--main", "README.rdoc"]
|
54
56
|
|
55
|
-
s.authors = ["
|
56
|
-
s.email = %q{
|
57
|
+
s.authors = ["Masatoshi Iwasaki"]
|
58
|
+
s.email = %q{mstshiwasaki@gmail.com}
|
59
|
+
s.homepage = "http://github.com/masa-iwasaki/factory_girl"
|
57
60
|
|
58
61
|
s.platform = Gem::Platform::RUBY
|
59
62
|
end
|
@@ -72,3 +75,8 @@ task :gemspec do
|
|
72
75
|
f.write spec.to_ruby
|
73
76
|
end
|
74
77
|
end
|
78
|
+
|
79
|
+
Cucumber::Rake::Task.new(:features) do |t|
|
80
|
+
t.fork = true
|
81
|
+
t.cucumber_opts = ['--format', (ENV['CUCUMBER_FORMAT'] || 'progress')]
|
82
|
+
end
|
data/lib/factory_girl.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'active_support'
|
2
|
+
require 'digest'
|
2
3
|
require 'factory_girl/proxy'
|
3
4
|
require 'factory_girl/proxy/build'
|
4
5
|
require 'factory_girl/proxy/create'
|
@@ -9,6 +10,7 @@ require 'factory_girl/attribute'
|
|
9
10
|
require 'factory_girl/attribute/static'
|
10
11
|
require 'factory_girl/attribute/dynamic'
|
11
12
|
require 'factory_girl/attribute/association'
|
13
|
+
require 'factory_girl/attribute/callback'
|
12
14
|
require 'factory_girl/sequence'
|
13
15
|
require 'factory_girl/aliases'
|
14
16
|
|
data/lib/factory_girl/factory.rb
CHANGED
@@ -4,13 +4,17 @@ class Factory
|
|
4
4
|
class AssociationDefinitionError < RuntimeError
|
5
5
|
end
|
6
6
|
|
7
|
+
# Raised when a callback is defined that has an invalid name
|
8
|
+
class InvalidCallbackNameError < RuntimeError
|
9
|
+
end
|
10
|
+
|
11
|
+
# Raised when a factory is defined with the same name as a previously-defined factory.
|
12
|
+
class DuplicateDefinitionError < RuntimeError
|
13
|
+
end
|
14
|
+
|
7
15
|
class << self
|
8
16
|
attr_accessor :factories #:nodoc:
|
9
17
|
|
10
|
-
# An array of used in find_or_create to keep AR instances created
|
11
|
-
# by Proxy::Create
|
12
|
-
attr_accessor :instances
|
13
|
-
|
14
18
|
# An Array of strings specifying locations that should be searched for
|
15
19
|
# factory definitions. By default, factory_girl will attempt to require
|
16
20
|
# "factories," "test/factories," and "spec/factories." Only the first
|
@@ -19,10 +23,10 @@ class Factory
|
|
19
23
|
end
|
20
24
|
|
21
25
|
self.factories = {}
|
22
|
-
self.instances = {}
|
23
26
|
self.definition_file_paths = %w(factories test/factories spec/factories)
|
24
27
|
|
25
28
|
attr_reader :factory_name #:nodoc:
|
29
|
+
attr_reader :singleton #:nodoc:
|
26
30
|
attr_reader :attributes #:nodoc:
|
27
31
|
|
28
32
|
# Defines a new factory that can be used by the build strategies (create and
|
@@ -52,8 +56,20 @@ class Factory
|
|
52
56
|
if parent = options.delete(:parent)
|
53
57
|
instance.inherit_from(Factory.factory_by_name(parent))
|
54
58
|
end
|
59
|
+
if singleton = options.delete(:singleton)
|
60
|
+
instance.singleton = true
|
61
|
+
end
|
62
|
+
if self.factories[instance.factory_name]
|
63
|
+
raise DuplicateDefinitionError, "Factory already defined: #{name}"
|
64
|
+
end
|
65
|
+
|
55
66
|
self.factories[instance.factory_name] = instance
|
56
67
|
end
|
68
|
+
|
69
|
+
# Call Proxy::Create.clear_caches
|
70
|
+
def self.clear_caches
|
71
|
+
::Factory::Proxy::Create.clear_caches
|
72
|
+
end
|
57
73
|
|
58
74
|
def class_name #:nodoc:
|
59
75
|
@options[:class] || factory_name
|
@@ -64,13 +80,14 @@ class Factory
|
|
64
80
|
end
|
65
81
|
|
66
82
|
def default_strategy #:nodoc:
|
67
|
-
@options[:default_strategy] || :
|
83
|
+
@options[:default_strategy] || :create
|
68
84
|
end
|
69
85
|
|
70
86
|
def initialize (name, options = {}) #:nodoc:
|
71
87
|
assert_valid_options(options)
|
72
88
|
@factory_name = factory_name_for(name)
|
73
89
|
@options = options
|
90
|
+
@singleton = false
|
74
91
|
@attributes = []
|
75
92
|
end
|
76
93
|
|
@@ -189,6 +206,25 @@ class Factory
|
|
189
206
|
add_attribute(name) { s.next }
|
190
207
|
end
|
191
208
|
|
209
|
+
def after_build(&block)
|
210
|
+
callback(:after_build, &block)
|
211
|
+
end
|
212
|
+
|
213
|
+
def after_create(&block)
|
214
|
+
callback(:after_create, &block)
|
215
|
+
end
|
216
|
+
|
217
|
+
def after_stub(&block)
|
218
|
+
callback(:after_stub, &block)
|
219
|
+
end
|
220
|
+
|
221
|
+
def callback(name, &block)
|
222
|
+
unless [:after_build, :after_create, :after_stub].include?(name.to_sym)
|
223
|
+
raise InvalidCallbackNameError, "#{name} is not a valid callback name. Valid callback names are :after_build, :after_create, and :after_stub"
|
224
|
+
end
|
225
|
+
@attributes << Attribute::Callback.new(name.to_sym, block)
|
226
|
+
end
|
227
|
+
|
192
228
|
# Generates and returns a Hash of attributes from this factory. Attributes
|
193
229
|
# can be individually overridden by passing in a Hash of attribute => value
|
194
230
|
# pairs.
|
@@ -241,37 +277,7 @@ class Factory
|
|
241
277
|
def self.create (name, overrides = {})
|
242
278
|
factory_by_name(name).run(Proxy::Create, overrides)
|
243
279
|
end
|
244
|
-
|
245
|
-
# Returns an object if an instance from this factory was already created.
|
246
|
-
# Or call self.create and register an instance to the list of instances.
|
247
|
-
#
|
248
|
-
# Arguments:
|
249
|
-
# * name: +Symbol+ or +String+
|
250
|
-
# The name of the factory that should be used.
|
251
|
-
# * overrides: +Hash+
|
252
|
-
# Attributes to overwrite for this instance.
|
253
|
-
#
|
254
|
-
# Returns: +Object+
|
255
|
-
# A saved instance of the class this factory generates, with generated
|
256
|
-
# attributes assigned.
|
257
|
-
def self.find_or_create(name, overrides = {})
|
258
|
-
if self.instances[name].nil?
|
259
|
-
self.instances[name] = self.create(name, overrides)
|
260
|
-
else
|
261
|
-
# Need reloading in terms of tearing down of fixtures on each test
|
262
|
-
begin
|
263
|
-
self.instances[name].reload
|
264
|
-
rescue ActiveRecord::RecordNotFound
|
265
|
-
self.instances[name] = self.create(name, overrides)
|
266
|
-
rescue
|
267
|
-
# TODO: Better handling for other exceptions if it is needed
|
268
|
-
self.instances[name] = self.create(name, overrides)
|
269
|
-
end
|
270
|
-
end
|
271
|
-
|
272
|
-
self.instances[name]
|
273
|
-
end
|
274
|
-
|
280
|
+
|
275
281
|
# Generates and returns an object with all attributes from this factory
|
276
282
|
# stubbed out. Attributes can be individually overridden by passing in a Hash
|
277
283
|
# of attribute => value pairs.
|
@@ -287,7 +293,7 @@ class Factory
|
|
287
293
|
def self.stub (name, overrides = {})
|
288
294
|
factory_by_name(name).run(Proxy::Stub, overrides)
|
289
295
|
end
|
290
|
-
|
296
|
+
|
291
297
|
# Executes the default strategy for the given factory. This is usually create,
|
292
298
|
# but it can be overridden for each factory.
|
293
299
|
#
|
@@ -325,15 +331,29 @@ class Factory
|
|
325
331
|
attribute.add_to(proxy)
|
326
332
|
end
|
327
333
|
end
|
334
|
+
proxy.factory_name = factory_name
|
335
|
+
proxy.singleton = singleton
|
328
336
|
proxy.result
|
329
337
|
end
|
330
338
|
|
331
|
-
private
|
332
|
-
|
333
339
|
def self.factory_by_name (name)
|
334
340
|
factories[name.to_sym] or raise ArgumentError.new("No such factory: #{name.to_s}")
|
335
341
|
end
|
336
342
|
|
343
|
+
def human_name(*args, &block)
|
344
|
+
if args.size == 0 && block.nil?
|
345
|
+
factory_name.to_s.gsub('_', ' ')
|
346
|
+
else
|
347
|
+
add_attribute(:human_name, *args, &block)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def associations
|
352
|
+
attributes.select {|attribute| attribute.is_a?(Attribute::Association) }
|
353
|
+
end
|
354
|
+
|
355
|
+
private
|
356
|
+
|
337
357
|
def class_for (class_or_to_s)
|
338
358
|
if class_or_to_s.respond_to?(:to_sym)
|
339
359
|
Object.const_get(variable_name_to_class_name(class_or_to_s))
|
@@ -351,7 +371,7 @@ class Factory
|
|
351
371
|
end
|
352
372
|
|
353
373
|
def attribute_defined? (name)
|
354
|
-
!@attributes.detect {|attr| attr.name == name }.nil?
|
374
|
+
!@attributes.detect {|attr| attr.name == name && !attr.is_a?(Factory::Attribute::Callback) }.nil?
|
355
375
|
end
|
356
376
|
|
357
377
|
def assert_valid_options(options)
|
@@ -361,7 +381,7 @@ class Factory
|
|
361
381
|
end
|
362
382
|
assert_valid_strategy(options[:default_strategy]) if options[:default_strategy]
|
363
383
|
end
|
364
|
-
|
384
|
+
|
365
385
|
def assert_valid_strategy(strategy)
|
366
386
|
unless Factory::Proxy.const_defined? variable_name_to_class_name(strategy)
|
367
387
|
raise ArgumentError, "Unknown strategy: #{strategy}"
|
@@ -381,14 +401,14 @@ class Factory
|
|
381
401
|
def variable_name_to_class_name(name)
|
382
402
|
name.to_s.
|
383
403
|
gsub(/\/(.?)/) { "::#{$1.upcase}" }.
|
384
|
-
|
404
|
+
gsub(/(?:^|_)(.)/) { $1.upcase }
|
385
405
|
end
|
386
406
|
|
387
407
|
# From ActiveSupport
|
388
408
|
def symbolize_keys(hash)
|
389
409
|
hash.inject({}) do |options, (key, value)|
|
390
410
|
options[(key.to_sym rescue key) || key] = value
|
391
|
-
|
411
|
+
options
|
392
412
|
end
|
393
413
|
end
|
394
414
|
|
data/lib/factory_girl/proxy.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
class Factory
|
2
2
|
|
3
3
|
class Proxy #:nodoc:
|
4
|
+
|
5
|
+
attr_reader :callbacks
|
6
|
+
attr_accessor :factory_name
|
7
|
+
attr_accessor :singleton
|
8
|
+
|
4
9
|
def initialize(klass)
|
5
10
|
end
|
6
11
|
|
@@ -14,6 +19,20 @@ class Factory
|
|
14
19
|
def associate(name, factory, attributes)
|
15
20
|
end
|
16
21
|
|
22
|
+
def add_callback(name, block)
|
23
|
+
@callbacks ||= {}
|
24
|
+
@callbacks[name] ||= []
|
25
|
+
@callbacks[name] << block
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_callbacks(name)
|
29
|
+
if @callbacks && @callbacks[name]
|
30
|
+
@callbacks[name].each do |block|
|
31
|
+
block.arity.zero? ? block.call : block.call(@instance)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
17
36
|
# Generates an association using the current build strategy.
|
18
37
|
#
|
19
38
|
# Arguments:
|