Class: Factory

Inherits:
Object
  • Object
show all
Defined in:
lib/factory_girl/aliases.rb,
lib/factory_girl/factory.rb,
lib/factory_girl/sequence.rb,
lib/factory_girl/attribute.rb,
lib/factory_girl/attribute_proxy.rb

Defined Under Namespace

Classes: Attribute, AttributeDefinitionError, AttributeProxy, ScopeDefinitionError, ScopeNotFoundError, Sequence

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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

:nodoc:



47
48
49
50
51
52
53
# File 'lib/factory_girl/factory.rb', line 47

def initialize (name, options = {}) #:nodoc:
  assert_valid_options(options)
  @factory_name = factory_name_for(name)
  @options      = options
  @attributes   = []
  @scopes       = {}
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.



110
111
112
# File 'lib/factory_girl/factory.rb', line 110

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.



16
17
18
# File 'lib/factory_girl/factory.rb', line 16

def definition_file_paths
  @definition_file_paths
end

.factoriesObject

:nodoc:



10
11
12
# File 'lib/factory_girl/factory.rb', line 10

def factories
  @factories
end

.sequencesObject

:nodoc:



19
20
21
# File 'lib/factory_girl/sequence.rb', line 19

def sequences
  @sequences
end

Instance Attribute Details

#factory_nameObject (readonly)

Returns the value of attribute factory_name.



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

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 insert like String#sub.

Example:

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


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

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

.aliases_for(attribute) ⇒ Object

:nodoc:



28
29
30
31
32
33
34
35
36
37
# File 'lib/factory_girl/aliases.rb', line 28

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, attrs = {}) ⇒ 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:

attrs: (Hash)
  Attributes to overwrite for this set.

Returns:

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


204
205
206
# File 'lib/factory_girl/factory.rb', line 204

def attributes_for (name, attrs = {})
  factory_by_name(name).attributes_for(attrs)
end

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

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

Arguments:

attrs: (Hash)
  See attributes_for

Returns:

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


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

def build (name, attrs = {})
  factory_by_name(name).build(attrs)
end

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

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

If the instance is not valid, an ActiveRecord::Invalid exception will be raised.

Arguments:

attrs: (Hash)
  See attributes_for

Returns:

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


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

def create (name, attrs = {})
  factory_by_name(name).create(attrs)
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)
  A unique name used to identify this factory.
options: (Hash)
  class: the class that will be used when generating instances for this
         factory. If not specified, the class will be guessed from the
         factory name.

Yields:

The newly created factory (Factory)

Yields:

  • (instance)


37
38
39
40
41
# File 'lib/factory_girl/factory.rb', line 37

def self.define (name, options = {})
  instance = Factory.new(name, options)
  yield(instance)
  self.factories[instance.factory_name] = instance
end

.find_definitionsObject

:nodoc:



244
245
246
247
248
249
250
251
252
253
254
# File 'lib/factory_girl/factory.rb', line 244

def 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

.method_missing(chain, *args, &block) ⇒ Object

Raises:



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/factory_girl/factory.rb', line 114

def self.method_missing(chain, *args, &block)
  name    = args[0]
  chain   = chain.to_s
  options = args.extract_options!
  factory = Factory.factories[name.to_sym]
  super(*args, &block) unless factory

  names = factory.scope_names.map(&:to_s)
  super(*args, &block) if names.empty?

  rs = true
  assigned = {}
  while rs
    rs = names.any? do |n|
      if chain.start_with?(n)
        assigned.merge!(factory.scope_attributes_for(n.to_sym))
        chain.gsub!(/^#{n}_?/, "")
        !chain.empty?
      end
    end
  end

  raise ScopeNotFoundError, "Can't found scope with name '#{chain}'" unless chain.empty?
  Factory(name.to_sym, assigned.merge(options))
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)


50
51
52
53
54
55
56
# File 'lib/factory_girl/sequence.rb', line 50

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

  self.sequences[sequence].next
end

.scope_attributes_for(name, scope, attrs = {}) ⇒ Object

:nodoc



208
209
210
# File 'lib/factory_girl/factory.rb', line 208

def scope_attributes_for(name, scope, attrs = {}) #:nodoc
  factory_by_name(name).scope_attributes_for(scope, attrs)
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" }


38
39
40
# File 'lib/factory_girl/sequence.rb', line 38

def self.sequence (name, &block)
  self.sequences[name] = Sequence.new(&block)
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::AttributeProxy will be yielded, allowing associations to be built using the correct build strategy.

Arguments:

name: (Symbol)
  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.


73
74
75
76
77
78
79
80
81
# File 'lib/factory_girl/factory.rb', line 73

def add_attribute (name, value = nil, &block)
  attribute = Attribute.new(name, value, block)

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

  @attributes << attribute
end

#add_scope(name, attr = {}) ⇒ Object



83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/factory_girl/factory.rb', line 83

def add_scope(name, attr = {})
  if @scopes.has_key?(name.to_sym)
    raise ScopeDefinitionError, "Scope already defined: #{name}"
  end

  attrs = []
  attr.each_pair do |k,v|
    attrs << Attribute.new(k, v, nil)
  end

  @scopes[name.to_sym] = attrs
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)
  factory: (Symbol)
    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.


161
162
163
164
165
166
167
# File 'lib/factory_girl/factory.rb', line 161

def association (name, options = {})
  name    = name.to_sym
  options = symbolize_keys(options)
  association_factory = options[:factory] || name

  add_attribute(name) {|a| a.association(association_factory) }
end

#attributes_for(attrs = {}) ⇒ Object

:nodoc:



169
170
171
# File 'lib/factory_girl/factory.rb', line 169

def attributes_for (attrs = {}) #:nodoc:
  build_attributes_hash(attrs, :attributes_for)
end

#build(attrs = {}) ⇒ Object

:nodoc:



181
182
183
# File 'lib/factory_girl/factory.rb', line 181

def build (attrs = {}) #:nodoc:
  build_instance(attrs, :build)
end

#build_classObject

:nodoc:



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

def build_class #:nodoc:
  @build_class ||= class_for(@options[:class] || factory_name)
end

#create(attrs = {}) ⇒ Object

:nodoc:



185
186
187
188
189
# File 'lib/factory_girl/factory.rb', line 185

def create (attrs = {}) #:nodoc:
  instance = build_instance(attrs, :create)
  instance.save!
  instance
end

#scope_attributes_for(scope, attrs = {}) ⇒ Object

:nodoc



173
174
175
# File 'lib/factory_girl/factory.rb', line 173

def scope_attributes_for(scope, attrs = {}) #:nodoc
  build_attributes_hash(attrs, :attributes_for, @scopes[scope])
end

#scope_namesObject



177
178
179
# File 'lib/factory_girl/factory.rb', line 177

def scope_names
  @scopes.keys
end