Class: FactoryBot::DefinitionProxy
- Inherits:
-
Object
- Object
- FactoryBot::DefinitionProxy
- Defined in:
- lib/factory_bot/definition_proxy.rb
Constant Summary collapse
- UNPROXIED_METHODS =
%w[ __send__ __id__ nil? send object_id extend instance_eval initialize block_given? raise caller method ].freeze
Instance Attribute Summary collapse
-
#child_factories ⇒ Object
readonly
Returns the value of attribute child_factories.
Instance Method Summary collapse
-
#add_attribute(name, &block) ⇒ Object
Adds an attribute to the factory.
-
#association(name, *options) ⇒ Object
Adds an attribute that builds an association.
- #factory(name, options = {}, &block) ⇒ Object
-
#initialize(definition, ignore = false) ⇒ DefinitionProxy
constructor
A new instance of DefinitionProxy.
- #initialize_with(&block) ⇒ Object
-
#method_missing(name, *args, &block) ⇒ Object
Calls add_attribute using the missing method name as the name of the attribute, so that:.
-
#sequence(name) ⇒ Object
Adds an attribute that will have unique values generated by a sequence with a specified format.
- #singleton_method_added(name) ⇒ Object
- #skip_create ⇒ Object
- #to_create(&block) ⇒ Object
- #trait(name, &block) ⇒ Object
-
#traits_for_enum(attribute_name, values = nil) ⇒ Object
Creates traits for enumerable values.
- #transient(&block) ⇒ Object
Constructor Details
#initialize(definition, ignore = false) ⇒ DefinitionProxy
Returns a new instance of DefinitionProxy.
26 27 28 29 30 |
# File 'lib/factory_bot/definition_proxy.rb', line 26 def initialize(definition, ignore = false) @definition = definition @ignore = ignore @child_factories = [] end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ Object
Calls add_attribute using the missing method name as the name of the attribute, so that:
factory :user do
name { 'Billy Idol' }
end
and:
factory :user do
add_attribute(:name) { 'Billy Idol' }
end
are equivalent.
If no argument or block is given, factory_bot will first look for an association, then for a sequence, and finally for a trait with the same name. This means that given an “admin” trait, an “email” sequence, and an “account” factory:
factory :user, traits: [:admin] do
email { generate(:email) }
association :account
end
and:
factory :user do
admin
email
account
end
are equivalent.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/factory_bot/definition_proxy.rb', line 91 def method_missing(name, *args, &block) # rubocop:disable Style/MissingRespondToMissing = args.first if .nil? __declare_attribute__(name, block) elsif () association(name, ) else raise NoMethodError.new(<<~MSG) undefined method '#{name}' in '#{@definition.name}' factory Did you mean? '#{name} { #{.inspect} }' MSG end end |
Instance Attribute Details
#child_factories ⇒ Object (readonly)
Returns the value of attribute child_factories.
24 25 26 |
# File 'lib/factory_bot/definition_proxy.rb', line 24 def child_factories @child_factories end |
Instance Method Details
#add_attribute(name, &block) ⇒ Object
Adds an attribute to the factory. The attribute value will be generated “lazily” by calling the block whenever an instance is generated. The block will not be called if the attribute is overridden for a specific instance.
Arguments:
-
name:
Symbol
orString
The name of this attribute. This will be assigned using “name=” for generated instances.
47 48 49 50 |
# File 'lib/factory_bot/definition_proxy.rb', line 47 def add_attribute(name, &block) declaration = Declaration::Dynamic.new(name, @ignore, block) @definition.declare_attribute(declaration) end |
#association(name, *options) ⇒ Object
Adds an attribute that builds an association. The associated instance will be built using the same build strategy as the parent instance.
Example:
factory :user do
name 'Joey'
end
factory :post do
association :author, factory: :user
end
Arguments:
-
name:
Symbol
The name of this attribute. -
options:
Hash
Options:
-
factory:
Symbol
orString
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.
151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/factory_bot/definition_proxy.rb', line 151 def association(name, *) if block_given? raise AssociationDefinitionError.new( "Unexpected block passed to '#{name}' association " \ "in '#{@definition.name}' factory" ) else declaration = Declaration::Association.new(name, *) @definition.declare_attribute(declaration) end end |
#factory(name, options = {}, &block) ⇒ Object
171 172 173 |
# File 'lib/factory_bot/definition_proxy.rb', line 171 def factory(name, = {}, &block) @child_factories << [name, , block] end |
#initialize_with(&block) ⇒ Object
237 238 239 |
# File 'lib/factory_bot/definition_proxy.rb', line 237 def initialize_with(&block) @definition.define_constructor(&block) end |
#sequence(name) ⇒ Object
Adds an attribute that will have unique values generated by a sequence with a specified format.
The result of:
factory :user do
sequence(:email) { |n| "person#{n}@example.com" }
end
Is equal to:
sequence(:email) { |n| "person#{n}@example.com" }
factory :user do
email { FactoryBot.generate(:email) }
end
Except that no globally available sequence will be defined.
122 123 124 125 126 |
# File 'lib/factory_bot/definition_proxy.rb', line 122 def sequence(name, ...) sequence = Sequence.new(name, ...) FactoryBot::Internal.register_inline_sequence(sequence) add_attribute(name) { increment_sequence(sequence) } end |
#singleton_method_added(name) ⇒ Object
32 33 34 35 |
# File 'lib/factory_bot/definition_proxy.rb', line 32 def singleton_method_added(name) = "Defining methods in blocks (trait or factory) is not supported (#{name})" raise FactoryBot::MethodDefinitionError, end |
#skip_create ⇒ Object
167 168 169 |
# File 'lib/factory_bot/definition_proxy.rb', line 167 def skip_create @definition.skip_create end |
#to_create(&block) ⇒ Object
163 164 165 |
# File 'lib/factory_bot/definition_proxy.rb', line 163 def to_create(&block) @definition.to_create(&block) end |
#trait(name, &block) ⇒ Object
175 176 177 |
# File 'lib/factory_bot/definition_proxy.rb', line 175 def trait(name, &block) @definition.define_trait(Trait.new(name, &block)) end |
#traits_for_enum(attribute_name, values = nil) ⇒ Object
Creates traits for enumerable values.
Example:
factory :task do
traits_for_enum :status, [:started, :finished]
end
Equivalent to:
factory :task do
trait :started do
status { :started }
end
trait :finished do
status { :finished }
end
end
Example:
factory :task do
traits_for_enum :status, {started: 1, finished: 2}
end
Example:
class Task
def statuses
{started: 1, finished: 2}
end
end
factory :task do
traits_for_enum :status
end
Both equivalent to:
factory :task do
trait :started do
status { 1 }
end
trait :finished do
status { 2 }
end
end
Arguments:
attribute_name: +Symbol+ or +String+
the name of the attribute these traits will set the value of
values: +Array+, +Hash+, or other +Enumerable+
An array of trait names, or a mapping of trait names to values for
those traits. When this argument is not provided, factory_bot will
attempt to get the values by calling the pluralized `attribute_name`
class method.
233 234 235 |
# File 'lib/factory_bot/definition_proxy.rb', line 233 def traits_for_enum(attribute_name, values = nil) @definition.register_enum(Enum.new(attribute_name, values)) end |
#transient(&block) ⇒ Object
52 53 54 55 |
# File 'lib/factory_bot/definition_proxy.rb', line 52 def transient(&block) proxy = DefinitionProxy.new(@definition, true) proxy.instance_eval(&block) end |