class FactoryBot::DefinitionProxy
def __declare_attribute__(name, block)
def __declare_attribute__(name, block) if block.nil? declaration = Declaration::Implicit.new(name, @definition, @ignore) @definition.declare_attribute(declaration) else add_attribute(name, &block) end end
def __valid_association_options?(options)
def __valid_association_options?(options) options.respond_to?(:has_key?) && options.has_key?(:factory) end
def add_attribute(name, &block)
The name of this attribute. This will be assigned using "name=" for
* name: +Symbol+ or +String+
Arguments:
attribute is overridden for a specific instance.
The block will not be called if the
by calling the block whenever an instance is generated.
The attribute value will be generated "lazily"
Adds an attribute to the factory.
def add_attribute(name, &block) declaration = Declaration::Dynamic.new(name, @ignore, block) @definition.declare_attribute(declaration) end
def association(name, *options)
name of the factory. For example, a "user" association will by
If no name is given, the name of the attribute is assumed to be the
The name of the factory to use when building the associated instance.
* factory: +Symbol+ or +String+
Options:
* options: +Hash+
The name of this attribute.
* name: +Symbol+
Arguments:
end
association :author, factory: :user
factory :post do
end
name 'Joey'
factory :user do
Example:
be built using the same build strategy as the parent instance.
Adds an attribute that builds an association. The associated instance will
def association(name, *options) if block_given? raise AssociationDefinitionError.new( "Unexpected block passed to '#{name}' association " \ "in '#{@definition.name}' factory" ) else declaration = Declaration::Association.new(name, *options) @definition.declare_attribute(declaration) end end
def factory(name, options = {}, &block)
def factory(name, options = {}, &block) @child_factories << [name, options, block] end
def initialize(definition, ignore = false)
def initialize(definition, ignore = false) @definition = definition @ignore = ignore @child_factories = [] end
def initialize_with(&block)
def initialize_with(&block) @definition.define_constructor(&block) end
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing
are equivalent.
end
account
admin
factory :user do
and:
end
association :account
email { generate(:email) }
factory :user, traits: [:admin] do
"account" factory:
name. This means that given an "admin" trait, an "email" sequence, and an
association, then for a sequence, and finally for a trait with the same
If no argument or block is given, factory_bot will first look for an
are equivalent.
end
add_attribute(:name) { 'Billy Idol' }
factory :user do
and:
end
name { 'Billy Idol' }
factory :user do
attribute, so that:
Calls add_attribute using the missing method name as the name of the
def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing association_options = args.first if association_options.nil? __declare_attribute__(name, block) elsif __valid_association_options?(association_options) association(name, association_options) else raise NoMethodError.new(<<~MSG) undefined method '#{name}' in '#{@definition.name}' factory Did you mean? '#{name} { #{association_options.inspect} }' MSG end end
def sequence(name, ...)
end
email { FactoryBot.generate(:email) }
factory :user do
sequence(:email) { |n| "person#{n}@example.com" }
Is equal to:
end
sequence(:email) { |n| "person#{n}@example.com" }
factory :user do
The result of:
a specified format.
Adds an attribute that will have unique values generated by a sequence with
def sequence(name, ...) sequence = Sequence.new(name, ...) FactoryBot::Internal.register_inline_sequence(sequence) add_attribute(name) { increment_sequence(sequence) } end
def singleton_method_added(name)
def singleton_method_added(name) message = "Defining methods in blocks (trait or factory) is not supported (#{name})" raise FactoryBot::MethodDefinitionError, message end
def skip_create
def skip_create @definition.skip_create end
def to_create(&block)
def to_create(&block) @definition.to_create(&block) end
def trait(name, &block)
def trait(name, &block) @definition.define_trait(Trait.new(name, &block)) end
def traits_for_enum(attribute_name, values = nil)
attempt to get the values by calling the pluralized `attribute_name`
those traits. When this argument is not provided, factory_bot will
An array of trait names, or a mapping of trait names to values for
values: +Array+, +Hash+, or other +Enumerable+
the name of the attribute these traits will set the value of
attribute_name: +Symbol+ or +String+
Arguments:
end
end
status { 2 }
trait :finished do
end
status { 1 }
trait :started do
factory :task do
Both equivalent to:
end
traits_for_enum :status
factory :task do
end
end
{started: 1, finished: 2}
def statuses
class Task
Example:
end
traits_for_enum :status, {started: 1, finished: 2}
factory :task do
Example:
end
end
status { :finished }
trait :finished do
end
status { :started }
trait :started do
factory :task do
Equivalent to:
end
traits_for_enum :status, [:started, :finished]
factory :task do
Example:
Creates traits for enumerable values.
def traits_for_enum(attribute_name, values = nil) @definition.register_enum(Enum.new(attribute_name, values)) end
def transient(&block)
def transient(&block) proxy = DefinitionProxy.new(@definition, true) proxy.instance_eval(&block) end