2011-09-23 15:00:00 -04:00
|
|
|
require "active_support/core_ext/hash/keys"
|
|
|
|
require "active_support/inflector"
|
|
|
|
|
2010-06-24 09:45:57 -04:00
|
|
|
module FactoryGirl
|
|
|
|
class Factory
|
2011-10-28 17:01:27 -04:00
|
|
|
attr_reader :name, :definition #:nodoc:
|
2011-08-12 10:35:41 -04:00
|
|
|
|
2010-10-02 00:00:58 -04:00
|
|
|
def initialize(name, options = {}) #:nodoc:
|
2010-06-24 09:45:57 -04:00
|
|
|
assert_valid_options(options)
|
2011-10-27 21:45:37 +02:00
|
|
|
@name = name.is_a?(Symbol) ? name : name.to_s.underscore.to_sym
|
2011-09-23 16:33:39 -04:00
|
|
|
@parent = options[:parent]
|
|
|
|
@aliases = options[:aliases] || []
|
|
|
|
@class_name = options[:class]
|
|
|
|
@default_strategy = options[:default_strategy]
|
2011-10-28 17:01:27 -04:00
|
|
|
@definition = Definition.new(@name)
|
2011-10-28 23:01:50 -04:00
|
|
|
|
|
|
|
inherit_traits(options[:traits] || [])
|
2011-09-02 12:05:00 -04:00
|
|
|
end
|
|
|
|
|
2011-10-28 17:01:27 -04:00
|
|
|
delegate :add_callback, :declare_attribute, :to_create, :define_trait,
|
2011-10-28 23:01:50 -04:00
|
|
|
:defined_traits, :traits, :inherit_traits, :to => :@definition
|
2011-10-14 22:34:51 -04:00
|
|
|
|
2011-10-07 16:15:15 -04:00
|
|
|
def factory_name
|
2011-10-09 17:03:22 -04:00
|
|
|
$stderr.puts "DEPRECATION WARNING: factory.factory_name is deprecated; use factory.name instead."
|
2011-10-07 16:15:15 -04:00
|
|
|
name
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_class #:nodoc:
|
2011-11-18 08:42:05 -05:00
|
|
|
class_name.to_s.camelize.constantize
|
2011-10-07 16:15:15 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def default_strategy #:nodoc:
|
2011-12-19 21:41:10 -05:00
|
|
|
@default_strategy || parent.default_strategy
|
2011-10-07 16:15:15 -04:00
|
|
|
end
|
|
|
|
|
2011-10-12 09:35:10 -06:00
|
|
|
def run(proxy_class, overrides, &block) #:nodoc:
|
2011-11-20 21:42:59 -05:00
|
|
|
block ||= lambda {|result| result }
|
|
|
|
|
2011-10-20 11:29:57 -04:00
|
|
|
runner_options = {
|
|
|
|
:attributes => attributes,
|
|
|
|
:callbacks => callbacks,
|
2011-10-28 17:01:27 -04:00
|
|
|
:to_create => to_create,
|
2011-10-20 11:29:57 -04:00
|
|
|
:build_class => build_class,
|
2011-12-02 10:13:34 -05:00
|
|
|
:proxy_class => proxy_class,
|
|
|
|
:overrides => overrides.dup
|
2011-10-20 11:29:57 -04:00
|
|
|
}
|
|
|
|
|
2011-12-02 10:13:34 -05:00
|
|
|
block[Runner.new(runner_options).run]
|
2010-06-24 09:45:57 -04:00
|
|
|
end
|
2009-09-15 15:47:47 -04:00
|
|
|
|
2011-06-30 18:27:25 -04:00
|
|
|
def human_names
|
2011-09-23 15:00:00 -04:00
|
|
|
names.map {|name| name.to_s.humanize.downcase }
|
2009-09-15 15:47:47 -04:00
|
|
|
end
|
|
|
|
|
2010-06-24 09:45:57 -04:00
|
|
|
def associations
|
2011-05-19 10:56:45 -04:00
|
|
|
attributes.select {|attribute| attribute.association? }
|
2010-06-24 09:45:57 -04:00
|
|
|
end
|
2009-09-15 16:56:20 -04:00
|
|
|
|
2011-01-25 17:55:40 -05:00
|
|
|
# Names for this factory, including aliases.
|
2010-11-11 16:34:01 -06:00
|
|
|
#
|
|
|
|
# Example:
|
|
|
|
#
|
|
|
|
# factory :user, :aliases => [:author] do
|
|
|
|
# # ...
|
|
|
|
# end
|
|
|
|
#
|
2011-01-26 20:55:06 -05:00
|
|
|
# FactoryGirl.create(:author).class
|
2010-11-11 16:34:01 -06:00
|
|
|
# # => User
|
|
|
|
#
|
|
|
|
# Because an attribute defined without a value or block will build an
|
|
|
|
# association with the same name, this allows associations to be defined
|
|
|
|
# without factories, such as:
|
|
|
|
#
|
|
|
|
# factory :user, :aliases => [:author] do
|
|
|
|
# # ...
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# factory :post do
|
|
|
|
# author
|
|
|
|
# end
|
|
|
|
#
|
2011-01-26 20:55:06 -05:00
|
|
|
# FactoryGirl.create(:post).author.class
|
2010-11-11 16:34:01 -06:00
|
|
|
# # => User
|
2011-01-25 17:55:40 -05:00
|
|
|
def names
|
2011-09-23 16:33:39 -04:00
|
|
|
[name] + @aliases
|
2010-11-11 16:34:01 -06:00
|
|
|
end
|
|
|
|
|
2011-10-28 10:59:49 -04:00
|
|
|
def compile
|
2011-10-28 21:23:06 -04:00
|
|
|
parent.defined_traits.each {|trait| define_trait(trait) }
|
|
|
|
parent.compile
|
2011-10-30 15:45:00 -04:00
|
|
|
@definition.compile
|
2011-10-07 15:00:38 -04:00
|
|
|
end
|
|
|
|
|
Traits can be added to factories when the factory creates an instance
This allows for traits to be used with normal factories without having
to name every single factory that uses one (or many) traits.
So, instead of creating male_admin and female_admin factories:
FactoryGirl.define do
factory :user do
trait(:admin) { admin true }
trait(:male) { gender "Male" }
trait(:female) { gender "Female" }
factory :male_admin, :traits => [:male, :admin]
factory :female_admin, :traits => [:admin, :female]
end
end
FactoryGirl.create(:male_admin)
FactoryGirl.create(:female_admin)
You could just create a user with those traits assigned:
FactoryGirl.create(:user, :admin, :male)
FactoryGirl.create(:user, :admin, :female)
This can be combined with attribute overrides as expected.
FactoryGirl.create(:user, :admin, :male, :name => "John Doe")
FactoryGirl.create(:user, :admin, :female, :name => "Jane Doe")
2011-11-18 09:25:49 -05:00
|
|
|
def with_traits(traits)
|
|
|
|
self.clone.tap do |factory_with_traits|
|
|
|
|
factory_with_traits.inherit_traits traits
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-10-07 15:00:38 -04:00
|
|
|
protected
|
|
|
|
|
|
|
|
def class_name #:nodoc:
|
2011-10-28 21:23:06 -04:00
|
|
|
@class_name || parent.class_name || name
|
2011-12-02 10:13:34 -05:00
|
|
|
|
2011-10-07 15:00:38 -04:00
|
|
|
end
|
|
|
|
|
2011-10-07 16:43:36 -04:00
|
|
|
def attributes
|
2011-10-28 10:59:49 -04:00
|
|
|
compile
|
2011-10-28 17:01:27 -04:00
|
|
|
AttributeList.new(@name).tap do |list|
|
2011-10-28 10:59:49 -04:00
|
|
|
traits.each do |trait|
|
2011-10-30 15:45:00 -04:00
|
|
|
list.apply_attributes(trait.attributes)
|
2011-10-07 16:43:36 -04:00
|
|
|
end
|
|
|
|
|
2011-10-30 15:45:00 -04:00
|
|
|
list.apply_attributes(@definition.attributes)
|
|
|
|
list.apply_attributes(parent.attributes)
|
2011-10-07 16:43:36 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-10-07 16:06:28 -04:00
|
|
|
def callbacks
|
2011-11-23 18:40:35 -05:00
|
|
|
[parent.callbacks, traits.map(&:callbacks).reverse, @definition.callbacks].flatten
|
2011-10-07 16:06:28 -04:00
|
|
|
end
|
|
|
|
|
2011-10-28 10:59:49 -04:00
|
|
|
private
|
2011-09-23 13:14:02 -04:00
|
|
|
|
2010-06-24 09:45:57 -04:00
|
|
|
def assert_valid_options(options)
|
2011-09-23 15:00:00 -04:00
|
|
|
options.assert_valid_keys(:class, :parent, :default_strategy, :aliases, :traits)
|
|
|
|
|
2011-01-19 19:26:27 -05:00
|
|
|
if options[:default_strategy]
|
2011-10-20 16:21:50 -04:00
|
|
|
Proxy.ensure_strategy_exists!(options[:default_strategy])
|
2011-10-09 17:03:22 -04:00
|
|
|
$stderr.puts "DEPRECATION WARNING: default_strategy is deprecated."
|
|
|
|
$stderr.puts "Override to_create if you need to prevent a call to #save!."
|
2011-01-19 19:26:27 -05:00
|
|
|
end
|
2008-12-11 15:54:33 -05:00
|
|
|
end
|
2010-06-07 15:51:18 -04:00
|
|
|
|
2011-10-07 15:00:38 -04:00
|
|
|
def parent
|
2011-10-28 21:23:06 -04:00
|
|
|
if @parent
|
|
|
|
FactoryGirl.factory_by_name(@parent)
|
|
|
|
else
|
|
|
|
NullFactory.new
|
|
|
|
end
|
2011-10-07 15:00:38 -04:00
|
|
|
end
|
2011-10-20 11:29:57 -04:00
|
|
|
|
Traits can be added to factories when the factory creates an instance
This allows for traits to be used with normal factories without having
to name every single factory that uses one (or many) traits.
So, instead of creating male_admin and female_admin factories:
FactoryGirl.define do
factory :user do
trait(:admin) { admin true }
trait(:male) { gender "Male" }
trait(:female) { gender "Female" }
factory :male_admin, :traits => [:male, :admin]
factory :female_admin, :traits => [:admin, :female]
end
end
FactoryGirl.create(:male_admin)
FactoryGirl.create(:female_admin)
You could just create a user with those traits assigned:
FactoryGirl.create(:user, :admin, :male)
FactoryGirl.create(:user, :admin, :female)
This can be combined with attribute overrides as expected.
FactoryGirl.create(:user, :admin, :male, :name => "John Doe")
FactoryGirl.create(:user, :admin, :female, :name => "Jane Doe")
2011-11-18 09:25:49 -05:00
|
|
|
def initialize_copy(source)
|
|
|
|
super
|
|
|
|
@definition = @definition.clone
|
|
|
|
end
|
|
|
|
|
2011-10-20 11:29:57 -04:00
|
|
|
class Runner
|
|
|
|
def initialize(options = {})
|
|
|
|
@attributes = options[:attributes]
|
|
|
|
@callbacks = options[:callbacks]
|
|
|
|
@to_create = options[:to_create]
|
|
|
|
@build_class = options[:build_class]
|
|
|
|
@proxy_class = options[:proxy_class]
|
2011-12-02 10:13:34 -05:00
|
|
|
@overrides = options[:overrides]
|
2011-10-20 11:29:57 -04:00
|
|
|
end
|
|
|
|
|
2011-12-02 10:13:34 -05:00
|
|
|
def run
|
2011-10-20 11:29:57 -04:00
|
|
|
apply_attributes
|
2011-10-20 12:00:01 -04:00
|
|
|
apply_remaining_overrides
|
2011-10-20 11:29:57 -04:00
|
|
|
|
|
|
|
proxy.result(@to_create)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
def apply_attributes
|
|
|
|
@attributes.each do |attribute|
|
|
|
|
if overrides_for_attribute(attribute).any?
|
2011-10-20 12:00:01 -04:00
|
|
|
handle_attribute_with_overrides(attribute)
|
2011-10-20 11:29:57 -04:00
|
|
|
else
|
|
|
|
handle_attribute_without_overrides(attribute)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-10-20 12:00:01 -04:00
|
|
|
def apply_remaining_overrides
|
2011-10-31 23:13:19 -04:00
|
|
|
@overrides.each { |attr, val| add_static_attribute(attr, val) }
|
2011-10-20 12:00:01 -04:00
|
|
|
end
|
|
|
|
|
2011-10-20 11:29:57 -04:00
|
|
|
def overrides_for_attribute(attribute)
|
2011-11-25 21:06:50 -05:00
|
|
|
@overrides.select { |attr, val| attribute.alias_for?(attr) }
|
2011-10-20 11:29:57 -04:00
|
|
|
end
|
|
|
|
|
2011-10-20 12:00:01 -04:00
|
|
|
def handle_attribute_with_overrides(attribute)
|
2011-10-20 11:29:57 -04:00
|
|
|
overrides_for_attribute(attribute).each do |attr, val|
|
2011-10-31 23:13:19 -04:00
|
|
|
add_static_attribute(attr, val, attribute.ignored)
|
2011-10-20 11:29:57 -04:00
|
|
|
@overrides.delete(attr)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2011-10-31 23:13:19 -04:00
|
|
|
def add_static_attribute(attr, val, ignored = false)
|
2011-11-30 22:13:55 -05:00
|
|
|
proxy.set(Attribute::Static.new(attr, val, ignored))
|
2011-10-31 23:13:19 -04:00
|
|
|
end
|
|
|
|
|
2011-10-20 11:29:57 -04:00
|
|
|
def handle_attribute_without_overrides(attribute)
|
2011-11-30 22:13:55 -05:00
|
|
|
proxy.set(attribute)
|
2011-10-20 11:29:57 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def proxy
|
2011-10-20 14:19:09 -04:00
|
|
|
@proxy ||= @proxy_class.new(@build_class, @callbacks)
|
2011-10-20 11:29:57 -04:00
|
|
|
end
|
|
|
|
end
|
2010-06-24 09:45:57 -04:00
|
|
|
end
|
2008-05-28 18:20:25 -04:00
|
|
|
end
|