2010-06-24 09:45:57 -04:00
|
|
|
module FactoryGirl
|
2010-06-10 14:58:47 -04:00
|
|
|
class DefinitionProxy
|
2011-07-05 18:29:55 -04:00
|
|
|
UNPROXIED_METHODS = %w(__send__ __id__ nil? send object_id extend instance_eval initialize block_given? raise)
|
2011-07-05 18:20:39 -04:00
|
|
|
|
|
|
|
(instance_methods + private_instance_methods).each do |method|
|
2011-07-06 18:18:19 -04:00
|
|
|
undef_method(method) unless UNPROXIED_METHODS.include?(method.to_s)
|
2010-06-10 14:58:47 -04:00
|
|
|
end
|
|
|
|
|
2011-06-29 16:49:45 -04:00
|
|
|
attr_reader :child_factories
|
2011-08-12 14:49:21 -04:00
|
|
|
|
2011-10-28 17:01:27 -04:00
|
|
|
def initialize(definition, ignore = false)
|
|
|
|
@definition = definition
|
2011-10-07 18:19:27 -04:00
|
|
|
@ignore = ignore
|
2011-06-29 16:49:45 -04:00
|
|
|
@child_factories = []
|
2010-06-10 14:58:47 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Adds an attribute that should be assigned on generated instances for this
|
|
|
|
# factory.
|
|
|
|
#
|
|
|
|
# This method should be called with either a value or block, but not both. If
|
|
|
|
# called with a block, the attribute will be generated "lazily," whenever an
|
|
|
|
# instance is generated. Lazy attribute blocks will not be called if that
|
|
|
|
# attribute is overridden for a specific instance.
|
|
|
|
#
|
2012-02-08 10:17:57 -05:00
|
|
|
# When defining lazy attributes, an instance of FactoryGirl::Strategy will
|
2010-06-10 14:58:47 -04:00
|
|
|
# be yielded, allowing associations to be built using the correct build
|
|
|
|
# strategy.
|
|
|
|
#
|
|
|
|
# Arguments:
|
|
|
|
# * name: +Symbol+ or +String+
|
2011-02-07 17:48:00 -05:00
|
|
|
# The name of this attribute. This will be assigned using "name=" for
|
2010-06-10 14:58:47 -04:00
|
|
|
# generated instances.
|
|
|
|
# * value: +Object+
|
|
|
|
# If no block is given, this value will be used for this attribute.
|
2010-07-06 21:15:16 -04:00
|
|
|
def add_attribute(name, value = nil, &block)
|
2011-10-09 17:14:40 -04:00
|
|
|
raise AttributeDefinitionError, "Both value and block given" if value && block_given?
|
|
|
|
|
|
|
|
declaration = if block_given?
|
|
|
|
Declaration::Dynamic.new(name, @ignore, block)
|
2010-06-10 14:58:47 -04:00
|
|
|
else
|
2011-10-09 17:14:40 -04:00
|
|
|
Declaration::Static.new(name, value, @ignore)
|
2010-06-10 14:58:47 -04:00
|
|
|
end
|
|
|
|
|
2011-10-28 17:01:27 -04:00
|
|
|
@definition.declare_attribute(declaration)
|
2010-06-10 14:58:47 -04:00
|
|
|
end
|
|
|
|
|
2011-10-07 18:19:27 -04:00
|
|
|
def ignore(&block)
|
2011-10-28 17:01:27 -04:00
|
|
|
proxy = DefinitionProxy.new(@definition, true)
|
2011-10-07 18:19:27 -04:00
|
|
|
proxy.instance_eval(&block)
|
|
|
|
end
|
|
|
|
|
2010-06-10 14:58:47 -04:00
|
|
|
# Calls add_attribute using the missing method name as the name of the
|
|
|
|
# attribute, so that:
|
|
|
|
#
|
2010-10-01 18:50:01 -04:00
|
|
|
# factory :user do
|
|
|
|
# name 'Billy Idol'
|
2010-06-10 14:58:47 -04:00
|
|
|
# end
|
|
|
|
#
|
|
|
|
# and:
|
|
|
|
#
|
2010-10-01 18:50:01 -04:00
|
|
|
# factory :user do
|
|
|
|
# add_attribute :name, 'Billy Idol'
|
|
|
|
# end
|
|
|
|
#
|
2011-07-01 19:08:03 -04:00
|
|
|
# are equivalent.
|
2010-10-01 18:50:01 -04:00
|
|
|
#
|
|
|
|
# If no argument or block is given, factory_girl will look for a sequence
|
|
|
|
# or association with the same name. This means that:
|
|
|
|
#
|
|
|
|
# factory :user do
|
2011-01-25 17:55:40 -05:00
|
|
|
# email { create(:email) }
|
2010-10-01 18:50:01 -04:00
|
|
|
# association :account
|
|
|
|
# end
|
|
|
|
#
|
|
|
|
# and:
|
|
|
|
#
|
|
|
|
# factory :user do
|
|
|
|
# email
|
|
|
|
# account
|
2010-06-10 14:58:47 -04:00
|
|
|
# end
|
|
|
|
#
|
2011-07-01 19:08:03 -04:00
|
|
|
# are equivalent.
|
2010-07-06 21:15:16 -04:00
|
|
|
def method_missing(name, *args, &block)
|
|
|
|
if args.empty? && block.nil?
|
2011-10-28 17:01:27 -04:00
|
|
|
@definition.declare_attribute(Declaration::Implicit.new(name, @definition, @ignore))
|
2010-11-28 13:55:26 -05:00
|
|
|
elsif args.first.is_a?(Hash) && args.first.has_key?(:factory)
|
|
|
|
association(name, *args)
|
2012-02-17 17:55:30 -05:00
|
|
|
elsif FactoryGirl.callback_names.include?(name)
|
|
|
|
@definition.add_callback(Callback.new(name, block))
|
2010-07-06 21:15:16 -04:00
|
|
|
else
|
|
|
|
add_attribute(name, *args, &block)
|
|
|
|
end
|
2010-06-10 14:58:47 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Adds an attribute that will have unique values generated by a sequence with
|
|
|
|
# a specified format.
|
|
|
|
#
|
|
|
|
# The result of:
|
2010-10-01 18:50:01 -04:00
|
|
|
# factory :user do
|
|
|
|
# sequence(:email) { |n| "person#{n}@example.com" }
|
2010-06-10 14:58:47 -04:00
|
|
|
# end
|
|
|
|
#
|
|
|
|
# Is equal to:
|
2010-10-01 18:50:01 -04:00
|
|
|
# sequence(:email) { |n| "person#{n}@example.com" }
|
2010-06-10 14:58:47 -04:00
|
|
|
#
|
2010-10-01 18:50:01 -04:00
|
|
|
# factory :user do
|
2011-01-25 17:55:40 -05:00
|
|
|
# email { FactoryGirl.create(:email) }
|
2010-06-10 14:58:47 -04:00
|
|
|
# end
|
|
|
|
#
|
|
|
|
# Except that no globally available sequence will be defined.
|
2012-04-06 14:41:13 -04:00
|
|
|
def sequence(name, *args, &block)
|
|
|
|
sequence = Sequence.new(name, *args, &block)
|
2011-05-19 10:56:45 -04:00
|
|
|
add_attribute(name) { sequence.next }
|
2010-06-10 14:58:47 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
# Adds an attribute that builds an association. The associated instance will
|
|
|
|
# be built using the same build strategy as the parent instance.
|
|
|
|
#
|
|
|
|
# Example:
|
2010-10-01 18:50:01 -04:00
|
|
|
# factory :user do
|
|
|
|
# name 'Joey'
|
2010-06-10 14:58:47 -04:00
|
|
|
# end
|
|
|
|
#
|
2010-10-01 18:50:01 -04:00
|
|
|
# factory :post do
|
2012-03-09 17:20:38 -05:00
|
|
|
# association :author, factory: :user
|
2010-06-10 14:58:47 -04:00
|
|
|
# end
|
|
|
|
#
|
|
|
|
# Arguments:
|
|
|
|
# * name: +Symbol+
|
|
|
|
# The name of this attribute.
|
|
|
|
# * options: +Hash+
|
|
|
|
#
|
|
|
|
# Options:
|
|
|
|
# * factory: +Symbol+ or +String+
|
|
|
|
# The name of the factory to use when building the associated instance.
|
|
|
|
# If no name is given, the name of the attribute is assumed to be the
|
|
|
|
# name of the factory. For example, a "user" association will by
|
|
|
|
# default use the "user" factory.
|
|
|
|
def association(name, options = {})
|
2011-10-28 17:01:27 -04:00
|
|
|
@definition.declare_attribute(Declaration::Association.new(name, options))
|
2010-06-10 14:58:47 -04:00
|
|
|
end
|
|
|
|
|
2010-11-12 16:21:16 -05:00
|
|
|
def to_create(&block)
|
2011-10-28 17:01:27 -04:00
|
|
|
@definition.to_create(&block)
|
2010-11-12 16:21:16 -05:00
|
|
|
end
|
2011-06-29 16:49:45 -04:00
|
|
|
|
|
|
|
def factory(name, options = {}, &block)
|
|
|
|
@child_factories << [name, options, block]
|
|
|
|
end
|
2011-08-12 14:49:21 -04:00
|
|
|
|
2011-08-12 16:16:17 -04:00
|
|
|
def trait(name, &block)
|
2011-10-28 17:01:27 -04:00
|
|
|
@definition.define_trait(Trait.new(name, &block))
|
2011-08-09 20:29:02 -04:00
|
|
|
end
|
2012-01-20 13:04:48 -05:00
|
|
|
|
|
|
|
def initialize_with(&block)
|
|
|
|
@definition.define_constructor(&block)
|
|
|
|
end
|
2010-06-10 14:58:47 -04:00
|
|
|
end
|
|
|
|
end
|