Class: Factory

Inherits:
Object
  • Object
show all
Defined in:
lib/factory_girl/proxy.rb,
lib/factory_girl/syntax.rb,
lib/factory_girl/aliases.rb,
lib/factory_girl/factory.rb,
lib/factory_girl/sequence.rb,
lib/factory_girl/attribute.rb,
lib/factory_girl/proxy/stub.rb,
lib/factory_girl/proxy/build.rb,
lib/factory_girl/syntax/make.rb,
lib/factory_girl/syntax/sham.rb,
lib/factory_girl/proxy/create.rb,
lib/factory_girl/syntax/generate.rb,
lib/factory_girl/attribute/static.rb,
lib/factory_girl/syntax/blueprint.rb,
lib/factory_girl/attribute/dynamic.rb,
lib/factory_girl/attribute/callback.rb,
lib/factory_girl/proxy/attributes_for.rb,
lib/factory_girl/attribute/association.rb

Defined Under Namespace

Modules: Syntax Classes: AssociationDefinitionError, Attribute, AttributeDefinitionError, DuplicateDefinitionError, FileDefinitionError, InvalidCallbackNameError, Proxy, Sequence, SequenceAbuseError

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name, options = {}) ⇒ Factory

:nodoc:



81
82
83
84
85
86
# File 'lib/factory_girl/factory.rb', line 81

def initialize (name, options = {}) #:nodoc:
  assert_valid_options(options)
  @factory_name = factory_name_for(name)
  @options      = options      
  @attributes   = []
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.define :user do |f|
  f.name 'Billy Idol'
end

and:

Factory.define :user do |f|
  f.add_attribute :name, 'Billy Idol'
end

are equivilent.



147
148
149
# File 'lib/factory_girl/factory.rb', line 147

def method_missing (name, *args, &block)
  add_attribute(name, *args, &block)
end

Class Attribute Details

.aliasesObject

:nodoc:



4
5
6
# File 'lib/factory_girl/aliases.rb', line 4

def aliases
  @aliases
end

.definition_file_pathsObject

An Array of strings specifying locations that should be searched for factory definitions. By default, factory_girl will attempt to require “factories,” “test/factories,” and “spec/factories.” Only the first existing file will be loaded.



27
28
29
# File 'lib/factory_girl/factory.rb', line 27

def definition_file_paths
  @definition_file_paths
end

.factoriesObject

:nodoc:



21
22
23
# File 'lib/factory_girl/factory.rb', line 21

def factories
  @factories
end

.sequencesObject

:nodoc:



24
25
26
# File 'lib/factory_girl/sequence.rb', line 24

def sequences
  @sequences
end

Instance Attribute Details

#attributesObject (readonly)

:nodoc:



34
35
36
# File 'lib/factory_girl/factory.rb', line 34

def attributes
  @attributes
end

#factory_nameObject (readonly)

:nodoc:



33
34
35
# File 'lib/factory_girl/factory.rb', line 33

def factory_name
  @factory_name
end

Class Method Details

.alias(pattern, replace) ⇒ Object

Defines a new alias for attributes.

Arguments:

  • pattern: Regexp A pattern that will be matched against attributes when looking for aliases. Contents captured in the pattern can be used in the alias.

  • replace: String The alias that results from the matched pattern. Captured strings can be substituded like with String#sub.

Example:

Factory.alias /(.*)_confirmation/, '\1'

factory_girl starts with aliases for foreign keys, so that a :user association can be overridden by a :user_id parameter:

Factory.define :post do |p|
  p.association :user
end

# The user association will not be built in this example. The user_id
# will be used instead.
Factory(:post, :user_id => 1)


35
36
37
# File 'lib/factory_girl/aliases.rb', line 35

def self.alias (pattern, replace)
  self.aliases << [pattern, replace]
end

.aliases_for(attribute) ⇒ Object

:nodoc:



39
40
41
42
43
44
45
46
47
48
# File 'lib/factory_girl/aliases.rb', line 39

def self.aliases_for (attribute) #:nodoc:
  aliases.collect do |params|
    pattern, replace = *params
    if pattern.match(attribute.to_s)
      attribute.to_s.sub(pattern, replace).to_sym
    else
      nil
    end
  end.compact << attribute
end

.attributes_for(name, overrides = {}) ⇒ Object

Generates and returns a Hash of attributes from this factory. Attributes can be individually overridden by passing in a Hash of attribute => value pairs.

Arguments:

  • name: Symbol or String The name of the factory that should be used.

  • overrides: Hash Attributes to overwrite for this set.

Returns: Hash A set of attributes that can be used to build an instance of the class this factory generates.



260
261
262
# File 'lib/factory_girl/factory.rb', line 260

def self.attributes_for (name, overrides = {})
  factory_by_name(name).run(Proxy::AttributesFor, overrides)
end

.build(name, overrides = {}) ⇒ Object

Generates and returns an instance from this factory. Attributes can be individually overridden by passing in a Hash of attribute => value pairs.

Arguments:

  • name: Symbol or String The name of the factory that should be used.

  • overrides: Hash Attributes to overwrite for this instance.

Returns: Object An instance of the class this factory generates, with generated attributes assigned.



276
277
278
# File 'lib/factory_girl/factory.rb', line 276

def self.build (name, overrides = {})
  factory_by_name(name).run(Proxy::Build, overrides)
end

.create(name, overrides = {}) ⇒ Object

Generates, saves, and returns an instance from this factory. Attributes can be individually overridden by passing in a Hash of attribute => value pairs.

Instances are saved using the save! method, so ActiveRecord models will raise ActiveRecord::RecordInvalid exceptions for invalid attribute sets.

Arguments:

  • name: Symbol or String The name of the factory that should be used.

  • overrides: Hash Attributes to overwrite for this instance.

Returns: Object A saved instance of the class this factory generates, with generated attributes assigned.



296
297
298
# File 'lib/factory_girl/factory.rb', line 296

def self.create (name, overrides = {})
  factory_by_name(name).run(Proxy::Create, overrides)
end

.default_strategy(name, overrides = {}) ⇒ Object

Executes the default strategy for the given factory. This is usually create, but it can be overridden for each factory.

Arguments:

  • name: Symbol or String The name of the factory that should be used.

  • overrides: Hash Attributes to overwrite for this instance.

Returns: Object The result of the default strategy.



327
328
329
# File 'lib/factory_girl/factory.rb', line 327

def self.default_strategy (name, overrides = {})  
  self.send(factory_by_name(name).default_strategy, name, overrides)
end

.define(name, options = {}) {|instance| ... } ⇒ Object

Defines a new factory that can be used by the build strategies (create and build) to build new objects.

Arguments:

  • name: Symbol or String A unique name used to identify this factory.

  • options: Hash

Options:

  • class: Symbol, Class, or String The class that will be used when generating instances for this factory. If not specified, the class will be guessed from the factory name.

  • parent: Symbol The parent factory. If specified, the attributes from the parent factory will be copied to the current one with an ability to override them.

  • default_strategy: Symbol The strategy that will be used by the Factory shortcut method. Defaults to :create.

Yields: Factory The newly created factory.

Yields:

  • (instance)


57
58
59
60
61
62
63
64
65
66
67
# File 'lib/factory_girl/factory.rb', line 57

def self.define (name, options = {})
  instance = Factory.new(name, options)
  yield(instance)
  if parent = options.delete(:parent)
    instance.inherit_from(Factory.factory_by_name(parent))
  end    
  if self.factories[instance.factory_name] 
    raise DuplicateDefinitionError, "Factory already defined: #{name}"
  end
  self.factories[instance.factory_name] = instance
end

.factory_by_name(name) ⇒ Object



356
357
358
# File 'lib/factory_girl/factory.rb', line 356

def self.factory_by_name (name)
  factories[name.to_sym] or raise ArgumentError.new("No such factory: #{name.to_s}")
end

.find_definitionsObject

:nodoc:



331
332
333
334
335
336
337
338
339
340
341
# File 'lib/factory_girl/factory.rb', line 331

def self.find_definitions #:nodoc:
  definition_file_paths.each do |path|
    require("#{path}.rb") if File.exists?("#{path}.rb")

    if File.directory? path
      Dir[File.join(path, '*.rb')].each do |file|
        require file
      end
    end
  end
end

.next(sequence) ⇒ Object

Generates and returns the next value in a sequence.

Arguments:

name: (Symbol)
  The name of the sequence that a value should be generated for.

Returns:

The next value in the sequence. (Object)


55
56
57
58
59
60
61
# File 'lib/factory_girl/sequence.rb', line 55

def self.next (sequence)
  unless self.sequences.key?(sequence)
    raise "No such sequence: #{sequence}"
  end

  self.sequences[sequence].next
end

.sequence(name, &block) ⇒ Object

Defines a new sequence that can be used to generate unique values in a specific format.

Arguments:

name: (Symbol)
  A unique name for this sequence. This name will be referenced when
  calling next to generate new values from this sequence.
block: (Proc)
  The code to generate each value in the sequence. This block will be
  called with a unique number each time a value in the sequence is to be
  generated. The block should return the generated value for the
  sequence.

Example:

Factory.sequence(:email) {|n| "somebody_#{n}@example.com" }


43
44
45
# File 'lib/factory_girl/sequence.rb', line 43

def self.sequence (name, &block)
  self.sequences[name] = Sequence.new(&block)
end

.stub(name, overrides = {}) ⇒ Object

Generates and returns an object with all attributes from this factory stubbed out. Attributes can be individually overridden by passing in a Hash of attribute => value pairs.

Arguments:

  • name: Symbol or String The name of the factory that should be used.

  • overrides: Hash Attributes to overwrite for this instance.

Returns: Object An object with generated attributes stubbed out.



312
313
314
# File 'lib/factory_girl/factory.rb', line 312

def self.stub (name, overrides = {})
  factory_by_name(name).run(Proxy::Stub, overrides)
end

Instance Method Details

#add_attribute(name, value = nil, &block) ⇒ Object

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 overriden for a specific instance.

When defining lazy attributes, an instance of Factory::Proxy will be yielded, allowing associations to be built using the correct build strategy.

Arguments:

  • name: Symbol or String The name of this attribute. This will be assigned using :“#name=” for generated instances.

  • value: Object If no block is given, this value will be used for this attribute.



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/factory_girl/factory.rb', line 115

def add_attribute (name, value = nil, &block)
  if block_given?
    if value
      raise AttributeDefinitionError, "Both value and block given"
    else
      attribute = Attribute::Dynamic.new(name, block)
    end
  else
    attribute = Attribute::Static.new(name, value)
  end

  if attribute_defined?(attribute.name)
    raise AttributeDefinitionError, "Attribute already defined: #{name}"
  end

  @attributes << attribute
end

#after_build(&block) ⇒ Object



228
229
230
# File 'lib/factory_girl/factory.rb', line 228

def after_build(&block)
  callback(:after_build, &block)
end

#after_create(&block) ⇒ Object



232
233
234
# File 'lib/factory_girl/factory.rb', line 232

def after_create(&block)
  callback(:after_create, &block)
end

#after_stub(&block) ⇒ Object



236
237
238
# File 'lib/factory_girl/factory.rb', line 236

def after_stub(&block)
  callback(:after_stub, &block)
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.define :user do |f|
  f.name 'Joey'
end

Factory.define :post do |f|
  f.association :author, :factory => :user
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.
    


174
175
176
177
178
179
180
# File 'lib/factory_girl/factory.rb', line 174

def association (name, options = {})
  factory_name = options.delete(:factory) || name
  if factory_name_for(factory_name) == self.factory_name
    raise AssociationDefinitionError, "Self-referencing association '#{name}' in factory '#{self.factory_name}'"
  end
  @attributes << Attribute::Association.new(name, factory_name, options)
end

#associationsObject



368
369
370
# File 'lib/factory_girl/factory.rb', line 368

def associations
  attributes.select {|attribute| attribute.is_a?(Attribute::Association) }
end

#build_classObject

:nodoc:



73
74
75
# File 'lib/factory_girl/factory.rb', line 73

def build_class #:nodoc:
  @build_class ||= class_for(class_name)
end

#callback(name, &block) ⇒ Object



240
241
242
243
244
245
# File 'lib/factory_girl/factory.rb', line 240

def callback(name, &block)
  unless [:after_build, :after_create, :after_stub].include?(name.to_sym)
    raise InvalidCallbackNameError, "#{name} is not a valid callback name. Valid callback names are :after_build, :after_create, and :after_stub"
  end
  @attributes << Attribute::Callback.new(name.to_sym, block)
end

#class_nameObject

:nodoc:



69
70
71
# File 'lib/factory_girl/factory.rb', line 69

def class_name #:nodoc:
  @options[:class] || factory_name
end

#default_strategyObject

:nodoc:



77
78
79
# File 'lib/factory_girl/factory.rb', line 77

def default_strategy #:nodoc:
  @options[:default_strategy] || :create
end

#human_name(*args, &block) ⇒ Object



360
361
362
363
364
365
366
# File 'lib/factory_girl/factory.rb', line 360

def human_name(*args, &block)
  if args.size == 0 && block.nil?
    factory_name.to_s.gsub('_', ' ')
  else
    add_attribute(:human_name, *args, &block)
  end
end

#inherit_from(parent) ⇒ Object

:nodoc:



88
89
90
91
92
93
94
95
# File 'lib/factory_girl/factory.rb', line 88

def inherit_from(parent) #:nodoc:
  @options[:class] ||= parent.class_name
  parent.attributes.each do |attribute|
    unless attribute_defined?(attribute.name)
      @attributes << attribute.clone
    end
  end
end

#paperclip(attr, file, *options) ⇒ Object

Add a file to a paperclip association Example

Factory.define :fact do |f| 
  f.paperclip :image, 'path_to_image', 'image/jpeg'
end

Arguments:

  • attr: Symbol The name of the paperclip association.

  • file: String A path to the file

Options:

  • content_type: String The content_type of the file

  • binary: Boolean+ whether it’s binary or not default is false

All options regarding to ActionController::TestUploadedFile



201
202
203
204
205
# File 'lib/factory_girl/factory.rb', line 201

def paperclip(attr, file, *options)
  raise FileDefinitionError unless file
  file = ActionController::TestUploadedFile.new(file, *options)
  add_attribute attr, file
end

#run(proxy_class, overrides) ⇒ Object

:nodoc:



343
344
345
346
347
348
349
350
351
352
353
354
# File 'lib/factory_girl/factory.rb', line 343

def run (proxy_class, overrides) #:nodoc:
  proxy = proxy_class.new(build_class)
  overrides = symbolize_keys(overrides)
  overrides.each {|attr, val| proxy.set(attr, val) }
  passed_keys = overrides.keys.collect {|k| Factory.aliases_for(k) }.flatten
  @attributes.each do |attribute|
    unless passed_keys.include?(attribute.name)
      attribute.add_to(proxy)
    end
  end
  proxy.result
end

#sequence(name, &block) ⇒ Object

Adds an attribute that will have unique values generated by a sequence with a specified format.

The result of:

Factory.define :user do |f|
 f.sequence(:email) { |n| "person#{n}@example.com" }
end

Is equal to:

Factory.sequence(:email) { |n| "person#{n}@example.com" }

Factory.define :user do |f|
 f.email { Factory.next(:email) }
end

Except that no globally available sequence will be defined.



223
224
225
226
# File 'lib/factory_girl/factory.rb', line 223

def sequence (name, &block)
  s = Sequence.new(&block)
  add_attribute(name) { s.next }
end