factory_girl 1.2.4 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/README.rdoc +10 -10
  2. data/Rakefile +21 -38
  3. data/features/factory_girl_steps.feature +125 -0
  4. data/features/step_definitions/database_steps.rb +18 -0
  5. data/features/support/env.rb +15 -0
  6. data/features/support/factories.rb +62 -0
  7. data/lib/factory_girl.rb +2 -12
  8. data/lib/factory_girl/aliases.rb +1 -1
  9. data/lib/factory_girl/attribute.rb +2 -2
  10. data/lib/factory_girl/factory.rb +28 -22
  11. data/lib/factory_girl/proxy.rb +1 -1
  12. data/lib/factory_girl/proxy/stub.rb +9 -1
  13. data/lib/factory_girl/sequence.rb +1 -1
  14. data/lib/factory_girl/step_definitions.rb +4 -6
  15. data/lib/factory_girl/syntax/blueprint.rb +0 -1
  16. data/lib/factory_girl/syntax/make.rb +1 -1
  17. data/rails/init.rb +2 -0
  18. data/spec/acceptance/acceptance_helper.rb +16 -0
  19. data/spec/{integration_spec.rb → acceptance/acceptance_spec.rb} +2 -1
  20. data/spec/{models.rb → acceptance/models.rb} +8 -3
  21. data/spec/{factory_girl → acceptance}/syntax/blueprint_spec.rb +1 -1
  22. data/spec/{factory_girl → acceptance}/syntax/generate_spec.rb +1 -1
  23. data/spec/{factory_girl → acceptance}/syntax/make_spec.rb +1 -1
  24. data/spec/{factory_girl → acceptance}/syntax/sham_spec.rb +1 -1
  25. data/spec/factory_girl/aliases_spec.rb +1 -1
  26. data/spec/factory_girl/attribute/association_spec.rb +1 -1
  27. data/spec/factory_girl/attribute/callback_spec.rb +1 -1
  28. data/spec/factory_girl/attribute/dynamic_spec.rb +1 -1
  29. data/spec/factory_girl/attribute/static_spec.rb +1 -1
  30. data/spec/factory_girl/attribute_spec.rb +1 -1
  31. data/spec/factory_girl/factory_spec.rb +80 -3
  32. data/spec/factory_girl/proxy/attributes_for_spec.rb +1 -1
  33. data/spec/factory_girl/proxy/build_spec.rb +1 -1
  34. data/spec/factory_girl/proxy/create_spec.rb +1 -1
  35. data/spec/factory_girl/proxy/stub_spec.rb +1 -1
  36. data/spec/factory_girl/proxy_spec.rb +1 -1
  37. data/spec/factory_girl/sequence_spec.rb +1 -1
  38. data/spec/spec_helper.rb +31 -7
  39. metadata +75 -30
  40. data/VERSION +0 -1
@@ -2,17 +2,16 @@
2
2
 
3
3
  factory_girl is a fixtures replacement with a straightforward definition syntax, support for multiple build strategies (saved instances, unsaved instances, attribute hashes, and stubbed objects), and support for multiple factories for the same class (user, admin_user, and so on), including factory inheritance.
4
4
 
5
+ If you want to use factory_girl with Rails 3, use the factory_girl_rails gem, not this one.
6
+
7
+ If you want to use factory_girl with Rails versions prior to Rails 3, use version 1.2.4.
8
+
5
9
  == Download
6
10
 
7
11
  Github: http://github.com/thoughtbot/factory_girl/tree/master
8
12
 
9
13
  Gem:
10
- gem install factory_girl --source http://gemcutter.org
11
-
12
- Note: if you install factory_girl using the gem from Gemcutter, you'll need this
13
- in your environment.rb if you want to use Rails 2.1+'s dependency manager:
14
-
15
- config.gem "factory_girl", :source => "http://gemcutter.org"
14
+ gem install factory_girl
16
15
 
17
16
  == Defining factories
18
17
 
@@ -43,7 +42,8 @@ It is highly recommended that you have one factory for each class that provides
43
42
 
44
43
  Attempting to define multiple factories with the same name will raise an error.
45
44
 
46
- Factories can either be defined anywhere, but will automatically be loaded if they are defined in files at the following locations:
45
+ Factories can be defined anywhere, but will be automatically loaded if they
46
+ are defined in files at the following locations:
47
47
 
48
48
  test/factories.rb
49
49
  spec/factories.rb
@@ -127,14 +127,14 @@ The behavior of the association method varies depending on the build strategy us
127
127
  post.author.new_record # => false
128
128
 
129
129
  # Builds and saves a User, and then builds but does not save a Post
130
- Factory.build(:post)
130
+ post = Factory.build(:post)
131
131
  post.new_record? # => true
132
132
  post.author.new_record # => false
133
133
 
134
134
  Because this pattern is so common, a prettier syntax is available for defining
135
135
  associations:
136
136
 
137
- # The following definitions are equivilent:
137
+ # The following definitions are equivalent:
138
138
  Factory.define :post do |p|
139
139
  p.author {|a| a.association(:user) }
140
140
  end
@@ -201,7 +201,7 @@ Factory_girl makes available three callbacks for injecting some code:
201
201
 
202
202
  Examples:
203
203
 
204
- # Define a factory that calls the generate_hashed_password method after it is built
204
+ # Define a factory that calls the generate_hashed_password method after it is built
205
205
  Factory.define :user do |u|
206
206
  u.after_build { |user| do_something_to(user) }
207
207
  end
data/Rakefile CHANGED
@@ -8,12 +8,30 @@ require 'spec/rake/spectask'
8
8
  require 'cucumber/rake/task'
9
9
 
10
10
  desc 'Default: run the specs and features.'
11
- task :default => [:spec, :features]
11
+ task :default do
12
+ system("rake -s spec:unit;")
13
+ %w(2.1 2.3 3.0).each do |version|
14
+ system("RAILS_VERSION=#{version} rake -s spec:acceptance features;")
15
+ end
16
+ end
17
+
18
+ namespace :spec do
19
+ desc "Run unit specs"
20
+ Spec::Rake::SpecTask.new('unit') do |t|
21
+ t.spec_opts = ['--options', "spec/spec.opts"]
22
+ t.spec_files = FileList['spec/factory_girl/**/*_spec.rb']
23
+ end
12
24
 
13
- Spec::Rake::SpecTask.new do |t|
14
- t.spec_opts = ['--options', "spec/spec.opts"]
25
+ desc "Run acceptance specs"
26
+ Spec::Rake::SpecTask.new('acceptance') do |t|
27
+ t.spec_opts = ['--options', "spec/spec.opts"]
28
+ t.spec_files = FileList['spec/acceptance/**/*_spec.rb']
29
+ end
15
30
  end
16
31
 
32
+ desc "Run the unit and acceptance specs"
33
+ task :spec => ['spec:unit', 'spec:acceptance']
34
+
17
35
  desc 'Performs code coverage on the factory_girl plugin.'
18
36
  Rcov::RcovTask.new do |t|
19
37
  t.test_files = FileList['spec/*_spec.rb']
@@ -35,41 +53,6 @@ task :sync_docs => 'rdoc' do
35
53
  `rsync -ave ssh rdoc/ dev@dev.thoughtbot.com:/home/dev/www/dev.thoughtbot.com/factory_girl`
36
54
  end
37
55
 
38
- begin
39
- require 'jeweler'
40
- Jeweler::Tasks.new do |s|
41
- s.name = %q{factory_girl}
42
- s.summary = %q{factory_girl provides a framework and DSL for defining and
43
- using model instance factories.}
44
- s.description = %q{factory_girl provides a framework and DSL for defining and
45
- using factories - less error-prone, more explicit, and
46
- all-around easier to work with than fixtures.}
47
-
48
- s.files = FileList['[A-Z]*', 'lib/**/*.rb', 'spec/**/*.rb']
49
- s.require_path = 'lib'
50
- s.test_files = Dir[*['spec/**/*_spec.rb']]
51
-
52
- s.has_rdoc = true
53
- s.extra_rdoc_files = ["README.rdoc"]
54
- s.rdoc_options = ['--line-numbers', "--main", "README.rdoc"]
55
-
56
- s.authors = ["Joe Ferris"]
57
- s.email = %q{jferris@thoughtbot.com}
58
- s.homepage = "http://thoughtbot.com/projects/factory_girl"
59
-
60
- s.add_development_dependency('rcov')
61
- s.add_development_dependency('rspec')
62
- s.add_development_dependency('cucumber')
63
- s.add_development_dependency('activerecord')
64
- s.add_development_dependency('rr')
65
- s.add_development_dependency('sqlite3')
66
-
67
- s.platform = Gem::Platform::RUBY
68
- end
69
- rescue LoadError
70
- puts "Jeweler not available. Install it with: gem install jeweler"
71
- end
72
-
73
56
  desc "Clean files generated by rake tasks"
74
57
  task :clobber => [:clobber_rdoc, :clobber_rcov]
75
58
 
@@ -0,0 +1,125 @@
1
+ Feature: Use step definitions generated by factories
2
+
3
+ Scenario: create a post and verify its attributes
4
+ Given the following post exists:
5
+ | Title | Body |
6
+ | a fun title | here is the content |
7
+ Then I should find the following for the last post:
8
+ | title | body |
9
+ | a fun title | here is the content |
10
+
11
+ Scenario: create a post without a table and verify its attributes
12
+ Given a post exists with a title of "a fun title"
13
+ Then I should find the following for the last post:
14
+ | title |
15
+ | a fun title |
16
+
17
+ Scenario: flexible English when creating posts
18
+ Given an post exists with an title of "a fun title"
19
+ Then I should find the following for the last post:
20
+ | title |
21
+ | a fun title |
22
+
23
+ Scenario: create a post with an underscore in an attribute name
24
+ Given a post exists with an author ID of "5"
25
+ Then I should find the following for the last post:
26
+ | author_id |
27
+ | 5 |
28
+
29
+ Scenario: create several posts
30
+ Given the following posts exist:
31
+ | Title | Body |
32
+ | one | first |
33
+ | two | second |
34
+ | three | third |
35
+ Then I should find the following for the last post:
36
+ | title | body |
37
+ | three | third |
38
+ And there should be 3 posts
39
+
40
+ Scenario: create a post with a new author
41
+ Given the following post exists:
42
+ | Title | Author |
43
+ | a title | ID: 123 |
44
+ Then I should find the following for the last post:
45
+ | title | author_id |
46
+ | a title | 123 |
47
+ And I should find the following for the last user:
48
+ | id |
49
+ | 123 |
50
+
51
+ Scenario: create a post with an existing author
52
+ Given the following user exists:
53
+ | ID | Name |
54
+ | 123 | Joe |
55
+ And the following post exists:
56
+ | Title | Author |
57
+ | a title | Name: Joe |
58
+ Then I should find the following for the last post:
59
+ | title | author_id |
60
+ | a title | 123 |
61
+ And there should be 1 user
62
+
63
+ Scenario: create post with and without a category association
64
+ Given the following users exist:
65
+ | ID | Name |
66
+ | 123 | Joe |
67
+ And the following posts exist:
68
+ | Title | Author | Category |
69
+ | a title | Name: Joe | Name: programming |
70
+ | a title without a category | Name: Joe | |
71
+ Then I should find the following for the last post:
72
+ | title | category_id |
73
+ | a title without a category | |
74
+
75
+ Scenario: create a user without attributes
76
+ Given a user exists
77
+ Then there should be 1 user
78
+
79
+ Scenario: create several users without attributes
80
+ Given 3 users exist
81
+ Then there should be 3 users
82
+
83
+ Scenario: create several users with one attribute
84
+ Given 3 users exist with a name of "John"
85
+ Then there should be 3 users
86
+ And I should find the following for the last user:
87
+ | name |
88
+ | John |
89
+
90
+ Scenario: create instances of a factory with an underscore in its name
91
+ Given an admin user exists with a name of "John"
92
+ Then I should find the following for the last user:
93
+ | name | admin |
94
+ | John | true |
95
+
96
+ Scenario: create a several instances of a factory with an underscore in its name
97
+ Given 3 admin users exist
98
+ Then I should find the following for the last user:
99
+ | admin |
100
+ | true |
101
+
102
+ Scenario: use true values when creating instances
103
+ Given the following user exists:
104
+ | name | admin |
105
+ | Bill | true |
106
+ Then I should find the following for the last user:
107
+ | name | admin |
108
+ | Bill | true |
109
+
110
+ Scenario: use false values when creating instances
111
+ Given the following user exists:
112
+ | name | admin |
113
+ | Mike | false |
114
+ Then I should find the following for the last user:
115
+ | name | admin |
116
+ | Mike | false |
117
+
118
+ Scenario: Properly pluralize words
119
+ Given the following categories exist:
120
+ | name |
121
+ | Bed |
122
+ | Test Drive |
123
+ And 2 categories exist
124
+ And 2 categories exist with a name of "Future"
125
+ Then there should be 6 categories
@@ -0,0 +1,18 @@
1
+ Then /^I should find the following for the last (.*):$/ do |model, table|
2
+ model_class = model.camelize.constantize
3
+ last_instance = model_class.last or raise "No #{model.pluralize} exist"
4
+ table.hashes.first.each do |key, value|
5
+ last_instance.attributes[key].to_s.should == value
6
+ end
7
+ end
8
+
9
+ Then /^there should be (\d+) (.*)$/ do |count, model|
10
+ model_class = model.singularize.camelize.constantize
11
+ model_class.count.should == count.to_i
12
+ end
13
+
14
+ Before do
15
+ Post.delete_all
16
+ User.delete_all
17
+ Category.delete_all
18
+ end
@@ -0,0 +1,15 @@
1
+ PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
2
+
3
+ $: << File.join(PROJECT_ROOT, 'lib')
4
+
5
+ case ENV['RAILS_VERSION']
6
+ when '2.1' then
7
+ gem 'activerecord', '~>2.1.0'
8
+ when '3.0' then
9
+ gem 'activerecord', '~>3.0.0'
10
+ else
11
+ gem 'activerecord', '~>2.3.0'
12
+ end
13
+
14
+ require 'active_record'
15
+ require 'factory_girl'
@@ -0,0 +1,62 @@
1
+ ActiveRecord::Base.establish_connection(
2
+ :adapter => 'sqlite3',
3
+ :database => File.join(File.dirname(__FILE__), 'test.db')
4
+ )
5
+
6
+ class CreateSchema < ActiveRecord::Migration
7
+ def self.up
8
+ create_table :posts, :force => true do |t|
9
+ t.integer :author_id
10
+ t.integer :category_id
11
+ t.string :title
12
+ t.string :body
13
+ end
14
+
15
+ create_table :categories, :force => true do |t|
16
+ t.string :name
17
+ end
18
+
19
+ create_table :users, :force => true do |t|
20
+ t.string :name
21
+ t.boolean :admin, :default => false, :null => false
22
+ end
23
+ end
24
+ end
25
+
26
+ CreateSchema.suppress_messages { CreateSchema.migrate(:up) }
27
+
28
+ class User < ActiveRecord::Base
29
+ end
30
+
31
+ class Category < ActiveRecord::Base
32
+ end
33
+
34
+ class Post < ActiveRecord::Base
35
+ belongs_to :author, :class_name => 'User'
36
+ belongs_to :category
37
+ end
38
+
39
+ class NonActiveRecord
40
+ end
41
+
42
+ Factory.define :user do |f|
43
+ end
44
+
45
+ Factory.define :admin_user, :parent => :user do |f|
46
+ f.admin true
47
+ end
48
+
49
+ Factory.define :category do |f|
50
+ f.name "programming"
51
+ end
52
+
53
+ Factory.define :post do |f|
54
+ f.association :author, :factory => :user
55
+ f.association :category
56
+ end
57
+
58
+ # This is here to ensure that factory step definitions don't raise for a non-AR factory
59
+ Factory.define :non_active_record do |f|
60
+ end
61
+
62
+ require 'factory_girl/step_definitions'
@@ -1,4 +1,3 @@
1
- require 'active_support'
2
1
  require 'factory_girl/proxy'
3
2
  require 'factory_girl/proxy/build'
4
3
  require 'factory_girl/proxy/create'
@@ -21,15 +20,6 @@ def Factory (name, attrs = {})
21
20
  Factory.default_strategy(name, attrs)
22
21
  end
23
22
 
24
- if defined? Rails.configuration
25
- Rails.configuration.after_initialize do
26
- Factory.definition_file_paths = [
27
- File.join(RAILS_ROOT, 'test', 'factories'),
28
- File.join(RAILS_ROOT, 'spec', 'factories')
29
- ]
30
- Factory.find_definitions
31
- end
32
- else
33
- Factory.find_definitions
23
+ class Factory
24
+ VERSION = "1.3.0"
34
25
  end
35
-
@@ -19,7 +19,7 @@ class Factory
19
19
  # be substituded like with +String#sub+.
20
20
  #
21
21
  # Example:
22
- #
22
+ #
23
23
  # Factory.alias /(.*)_confirmation/, '\1'
24
24
  #
25
25
  # factory_girl starts with aliases for foreign keys, so that a :user
@@ -6,7 +6,7 @@ class Factory
6
6
  # * Defining an attribute twice in the same factory
7
7
  class AttributeDefinitionError < RuntimeError
8
8
  end
9
-
9
+
10
10
  class Attribute #:nodoc:
11
11
 
12
12
  attr_reader :name
@@ -16,7 +16,7 @@ class Factory
16
16
 
17
17
  if @name.to_s =~ /=$/
18
18
  attribute_name = $`
19
- raise AttributeDefinitionError,
19
+ raise AttributeDefinitionError,
20
20
  "factory_girl uses 'f.#{attribute_name} value' syntax " +
21
21
  "rather than 'f.#{attribute_name} = value'"
22
22
  end
@@ -1,9 +1,11 @@
1
1
  class Factory
2
+ undef :id if Factory.instance_methods.include?('id')
3
+ undef :type if Factory.instance_methods.include?('type')
2
4
 
3
5
  # Raised when a factory is defined that attempts to instantiate itself.
4
6
  class AssociationDefinitionError < RuntimeError
5
7
  end
6
-
8
+
7
9
  # Raised when a callback is defined that has an invalid name
8
10
  class InvalidCallbackNameError < RuntimeError
9
11
  end
@@ -11,7 +13,7 @@ class Factory
11
13
  # Raised when a factory is defined with the same name as a previously-defined factory.
12
14
  class DuplicateDefinitionError < RuntimeError
13
15
  end
14
-
16
+
15
17
  class << self
16
18
  attr_accessor :factories #:nodoc:
17
19
 
@@ -54,13 +56,13 @@ class Factory
54
56
  yield(instance)
55
57
  if parent = options.delete(:parent)
56
58
  instance.inherit_from(Factory.factory_by_name(parent))
57
- end
58
- if self.factories[instance.factory_name]
59
+ end
60
+ if self.factories[instance.factory_name]
59
61
  raise DuplicateDefinitionError, "Factory already defined: #{name}"
60
62
  end
61
63
  self.factories[instance.factory_name] = instance
62
64
  end
63
-
65
+
64
66
  def class_name #:nodoc:
65
67
  @options[:class] || factory_name
66
68
  end
@@ -68,7 +70,7 @@ class Factory
68
70
  def build_class #:nodoc:
69
71
  @build_class ||= class_for(class_name)
70
72
  end
71
-
73
+
72
74
  def default_strategy #:nodoc:
73
75
  @options[:default_strategy] || :create
74
76
  end
@@ -76,12 +78,13 @@ class Factory
76
78
  def initialize (name, options = {}) #:nodoc:
77
79
  assert_valid_options(options)
78
80
  @factory_name = factory_name_for(name)
79
- @options = options
81
+ @options = options
80
82
  @attributes = []
81
83
  end
82
-
84
+
83
85
  def inherit_from(parent) #:nodoc:
84
- @options[:class] ||= parent.class_name
86
+ @options[:class] ||= parent.class_name
87
+ @options[:default_strategy] ||= parent.default_strategy
85
88
  parent.attributes.each do |attribute|
86
89
  unless attribute_defined?(attribute.name)
87
90
  @attributes << attribute.clone
@@ -138,7 +141,7 @@ class Factory
138
141
  # f.add_attribute :name, 'Billy Idol'
139
142
  # end
140
143
  #
141
- # are equivilent.
144
+ # are equivilent.
142
145
  def method_missing (name, *args, &block)
143
146
  add_attribute(name, *args, &block)
144
147
  end
@@ -194,26 +197,26 @@ class Factory
194
197
  s = Sequence.new(&block)
195
198
  add_attribute(name) { s.next }
196
199
  end
197
-
200
+
198
201
  def after_build(&block)
199
202
  callback(:after_build, &block)
200
203
  end
201
-
204
+
202
205
  def after_create(&block)
203
206
  callback(:after_create, &block)
204
207
  end
205
-
208
+
206
209
  def after_stub(&block)
207
210
  callback(:after_stub, &block)
208
211
  end
209
-
212
+
210
213
  def callback(name, &block)
211
214
  unless [:after_build, :after_create, :after_stub].include?(name.to_sym)
212
215
  raise InvalidCallbackNameError, "#{name} is not a valid callback name. Valid callback names are :after_build, :after_create, and :after_stub"
213
216
  end
214
217
  @attributes << Attribute::Callback.new(name.to_sym, block)
215
218
  end
216
-
219
+
217
220
  # Generates and returns a Hash of attributes from this factory. Attributes
218
221
  # can be individually overridden by passing in a Hash of attribute => value
219
222
  # pairs.
@@ -226,7 +229,7 @@ class Factory
226
229
  #
227
230
  # Returns: +Hash+
228
231
  # A set of attributes that can be used to build an instance of the class
229
- # this factory generates.
232
+ # this factory generates.
230
233
  def self.attributes_for (name, overrides = {})
231
234
  factory_by_name(name).run(Proxy::AttributesFor, overrides)
232
235
  end
@@ -266,7 +269,7 @@ class Factory
266
269
  def self.create (name, overrides = {})
267
270
  factory_by_name(name).run(Proxy::Create, overrides)
268
271
  end
269
-
272
+
270
273
  # Generates and returns an object with all attributes from this factory
271
274
  # stubbed out. Attributes can be individually overridden by passing in a Hash
272
275
  # of attribute => value pairs.
@@ -282,7 +285,7 @@ class Factory
282
285
  def self.stub (name, overrides = {})
283
286
  factory_by_name(name).run(Proxy::Stub, overrides)
284
287
  end
285
-
288
+
286
289
  # Executes the default strategy for the given factory. This is usually create,
287
290
  # but it can be overridden for each factory.
288
291
  #
@@ -294,7 +297,7 @@ class Factory
294
297
  #
295
298
  # Returns: +Object+
296
299
  # The result of the default strategy.
297
- def self.default_strategy (name, overrides = {})
300
+ def self.default_strategy (name, overrides = {})
298
301
  self.send(factory_by_name(name).default_strategy, name, overrides)
299
302
  end
300
303
 
@@ -343,7 +346,10 @@ class Factory
343
346
 
344
347
  def class_for (class_or_to_s)
345
348
  if class_or_to_s.respond_to?(:to_sym)
346
- Object.const_get(variable_name_to_class_name(class_or_to_s))
349
+ class_name = variable_name_to_class_name(class_or_to_s)
350
+ class_name.split('::').inject(Object) do |object, string|
351
+ object.const_get(string)
352
+ end
347
353
  else
348
354
  class_or_to_s
349
355
  end
@@ -362,13 +368,13 @@ class Factory
362
368
  end
363
369
 
364
370
  def assert_valid_options(options)
365
- invalid_keys = options.keys - [:class, :parent, :default_strategy]
371
+ invalid_keys = options.keys - [:class, :parent, :default_strategy]
366
372
  unless invalid_keys == []
367
373
  raise ArgumentError, "Unknown arguments: #{invalid_keys.inspect}"
368
374
  end
369
375
  assert_valid_strategy(options[:default_strategy]) if options[:default_strategy]
370
376
  end
371
-
377
+
372
378
  def assert_valid_strategy(strategy)
373
379
  unless Factory::Proxy.const_defined? variable_name_to_class_name(strategy)
374
380
  raise ArgumentError, "Unknown strategy: #{strategy}"
@@ -59,7 +59,7 @@ class Factory
59
59
  # # Builds (but doesn't save) a Post and a User
60
60
  # Factory.build(:post)
61
61
  #
62
- # # Builds and saves a User, builds a Post, assigns the User to the
62
+ # # Builds and saves a User, builds a Post, assigns the User to the
63
63
  # # author association, and saves the User.
64
64
  # Factory.create(:post)
65
65
  #
@@ -1,4 +1,4 @@
1
- class Factory
1
+ class Factory
2
2
  class Proxy
3
3
  class Stub < Proxy #:nodoc:
4
4
  @@next_id = 1000
@@ -11,6 +11,14 @@ class Factory
11
11
  id.nil?
12
12
  end
13
13
 
14
+ def save(*args)
15
+ raise "stubbed models are not allowed to access the database"
16
+ end
17
+
18
+ def destroy(*args)
19
+ raise "stubbed models are not allowed to access the database"
20
+ end
21
+
14
22
  def connection
15
23
  raise "stubbed models are not allowed to access the database"
16
24
  end
@@ -38,7 +38,7 @@ class Factory
38
38
  # sequence.
39
39
  #
40
40
  # Example:
41
- #
41
+ #
42
42
  # Factory.sequence(:email) {|n| "somebody_#{n}@example.com" }
43
43
  def self.sequence (name, &block)
44
44
  self.sequences[name] = Sequence.new(&block)
@@ -23,8 +23,7 @@ end
23
23
  World(FactoryGirlStepHelpers)
24
24
 
25
25
  Factory.factories.values.each do |factory|
26
- # TODO: support irregular pluralizations
27
- Given /^the following #{factory.human_name}s? exists?:$/ do |table|
26
+ Given /^the following (?:#{factory.human_name}|#{factory.human_name.pluralize}) exists?:$/ do |table|
28
27
  table.hashes.each do |human_hash|
29
28
  attributes = convert_human_hash_to_attribute_hash(human_hash, factory.associations)
30
29
  Factory.create(factory.factory_name, attributes)
@@ -35,8 +34,8 @@ Factory.factories.values.each do |factory|
35
34
  Factory(factory.factory_name)
36
35
  end
37
36
 
38
- Given /^(\d+) #{factory.human_name}s exist$/ do |count|
39
- count.to_i.times { Factory(factory.human_name) }
37
+ Given /^(\d+) #{factory.human_name.pluralize} exist$/ do |count|
38
+ count.to_i.times { Factory(factory.factory_name) }
40
39
  end
41
40
 
42
41
  if factory.build_class.respond_to?(:columns)
@@ -46,10 +45,9 @@ Factory.factories.values.each do |factory|
46
45
  Factory(factory.factory_name, column.name => value)
47
46
  end
48
47
 
49
- Given /^(\d+) #{factory.human_name}s exist with an? #{human_column_name} of "([^"]*)"$/i do |count, value|
48
+ Given /^(\d+) #{factory.human_name.pluralize} exist with an? #{human_column_name} of "([^"]*)"$/i do |count, value|
50
49
  count.to_i.times { Factory(factory.factory_name, column.name => value) }
51
50
  end
52
51
  end
53
52
  end
54
53
  end
55
-
@@ -39,4 +39,3 @@ class Factory
39
39
  end
40
40
 
41
41
  ActiveRecord::Base.send(:include, Factory::Syntax::Blueprint::ActiveRecord)
42
-
@@ -7,7 +7,7 @@ class Factory
7
7
  # Usage:
8
8
  #
9
9
  # require 'factory_girl/syntax/make'
10
- #
10
+ #
11
11
  # Factory.define :user do |factory|
12
12
  # factory.name 'Billy Bob'
13
13
  # factory.email 'billy@bob.example.com'
@@ -0,0 +1,2 @@
1
+ require 'factory_girl'
2
+ Rails.configuration.after_initialize { Factory.find_definitions }
@@ -0,0 +1,16 @@
1
+ case ENV['RAILS_VERSION']
2
+ when '2.1' then
3
+ gem 'activerecord', '~>2.1.0'
4
+ when '3.0' then
5
+ gem 'activerecord', '~>3.0.0'
6
+ else
7
+ gem 'activerecord', '~>2.3.0'
8
+ end
9
+
10
+ require 'active_record'
11
+ require 'active_record/version'
12
+
13
+ puts "Running specs using Rails #{ActiveRecord::VERSION::STRING}"
14
+
15
+ require 'acceptance/models'
16
+
@@ -1,4 +1,5 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), 'spec_helper'))
1
+ require 'spec_helper'
2
+ require 'acceptance/acceptance_helper'
2
3
 
3
4
  describe "integration" do
4
5
  before do
@@ -14,12 +14,12 @@ class CreateSchema < ActiveRecord::Migration
14
14
  end
15
15
 
16
16
  create_table :posts, :force => true do |t|
17
- t.string :name
17
+ t.string :name
18
18
  t.integer :author_id
19
19
  end
20
-
20
+
21
21
  create_table :business, :force => true do |t|
22
- t.string :name
22
+ t.string :name
23
23
  t.integer :owner_id
24
24
  end
25
25
  end
@@ -41,3 +41,8 @@ class Post < ActiveRecord::Base
41
41
  validates_presence_of :name, :author_id
42
42
  belongs_to :author, :class_name => 'User'
43
43
  end
44
+
45
+ module Admin
46
+ class Settings
47
+ end
48
+ end
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  require 'factory_girl/syntax/blueprint'
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  require 'factory_girl/syntax/generate'
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  require 'factory_girl/syntax/make'
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
1
+ require 'spec_helper'
2
2
 
3
3
  require 'factory_girl/syntax/sham'
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory, "aliases" do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Attribute::Association do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Attribute::Callback do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Attribute::Dynamic do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Attribute::Static do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Attribute do
4
4
  before do
@@ -1,6 +1,15 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory do
4
+ include DefinesConstants
5
+
6
+ before do
7
+ define_constant('User')
8
+ define_constant('Admin', User)
9
+ define_constant('Business')
10
+ define_constant('Admin::Settings')
11
+ end
12
+
4
13
  describe "defining a factory" do
5
14
  before do
6
15
  @name = :user
@@ -36,7 +45,7 @@ describe Factory do
36
45
  end
37
46
 
38
47
  it "should not allow a duplicate factory definition" do
39
- lambda {
48
+ lambda {
40
49
  2.times { Factory.define(@name) {|f| } }
41
50
  }.should raise_error(Factory::DuplicateDefinitionError)
42
51
  end
@@ -62,6 +71,36 @@ describe Factory do
62
71
  @factory.default_strategy.should == :create
63
72
  end
64
73
 
74
+ it "should return static attribute when asked for a type" do
75
+ result = @factory.type
76
+ result.should be_kind_of(Array)
77
+ result.first.should be_kind_of(Factory::Attribute::Static)
78
+ result.first.name.should == :type
79
+ end
80
+
81
+ it "should define type as an attribute" do
82
+ @factory.type { "it's a type" }
83
+ attributes = @factory.attributes
84
+ attributes.should be_kind_of(Array)
85
+ attributes.size.should == 1
86
+ attributes.first.name.should == :type
87
+ end
88
+
89
+ it "should return static attribute when asked for the id" do
90
+ result = @factory.id
91
+ result.should be_kind_of(Array)
92
+ result.first.should be_kind_of(Factory::Attribute::Static)
93
+ result.first.name.should == :id
94
+ end
95
+
96
+ it "should define id as an attribute" do
97
+ @factory.id { "it's an id" }
98
+ attributes = @factory.attributes
99
+ attributes.should be_kind_of(Array)
100
+ attributes.size.should == 1
101
+ attributes.first.name.should == :id
102
+ end
103
+
65
104
  it "should not allow the same attribute to be added twice" do
66
105
  lambda {
67
106
  2.times { @factory.add_attribute :first_name }
@@ -368,6 +407,24 @@ describe Factory do
368
407
  end
369
408
  end
370
409
 
410
+ describe "a factory for namespaced class" do
411
+ before do
412
+ Factory.factories = {}
413
+ @name = :settings
414
+ @class = Admin::Settings
415
+ end
416
+
417
+ it "should build namespaced class passed by string" do
418
+ factory = Factory.define(@name.to_s, :class => @class.name) {}
419
+ factory.build_class.should == @class
420
+ end
421
+
422
+ it "should build Admin::Settings class from Admin::Settings string" do
423
+ factory = Factory.define(@name.to_s, :class => 'admin/settings') {}
424
+ factory.build_class.should == @class
425
+ end
426
+ end
427
+
371
428
  describe "after defining a factory" do
372
429
  before do
373
430
  @name = :user
@@ -497,6 +554,26 @@ describe Factory do
497
554
  factory = Factory.define(:object, :default_strategy => :stub) {}
498
555
  factory.default_strategy.should == :stub
499
556
  end
557
+
558
+ describe 'defining a child factory without setting default strategy' do
559
+ before do
560
+ @child = Factory.define(:child_object, :parent => :object) {}
561
+ end
562
+
563
+ it "should inherit default strategy from its parent" do
564
+ @child.default_strategy.should == :stub
565
+ end
566
+ end
567
+
568
+ describe 'defining a child factory with a default strategy' do
569
+ before do
570
+ @child2 = Factory.define(:child_object2, :parent => :object, :default_strategy => :build) {}
571
+ end
572
+
573
+ it "should not inherit default strategy from parent" do
574
+ @child2.default_strategy.should == :build
575
+ end
576
+ end
500
577
  end
501
578
 
502
579
  def self.in_directory_with_files(*files)
@@ -521,7 +598,7 @@ describe Factory do
521
598
 
522
599
  def require_definitions_from(file)
523
600
  simple_matcher do |given, matcher|
524
- has_received = have_received.require(file)
601
+ has_received = have_received.method_missing(:require, file)
525
602
  result = has_received.matches?(given)
526
603
  matcher.description = "require definitions from #{file}"
527
604
  matcher.failure_message = has_received.failure_message
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Proxy::AttributesFor do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Proxy::Build do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Proxy::Create do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Proxy::Stub do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Proxy do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.expand_path(File.join(File.dirname(__FILE__), '..', 'spec_helper'))
1
+ require 'spec_helper'
2
2
 
3
3
  describe Factory::Sequence do
4
4
  describe "a sequence" do
@@ -1,18 +1,42 @@
1
- $: << File.join(File.dirname(__FILE__), '..', 'lib')
2
- $: << File.join(File.dirname(__FILE__))
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
2
+ $LOAD_PATH << File.join(File.dirname(__FILE__))
3
3
 
4
4
  require 'rubygems'
5
-
6
- require 'activerecord'
7
-
8
5
  require 'spec'
9
6
  require 'spec/autorun'
10
7
  require 'rr'
11
8
 
12
- require 'models'
13
-
14
9
  require 'factory_girl'
15
10
 
16
11
  Spec::Runner.configure do |config|
17
12
  config.mock_with RR::Adapters::Rspec
18
13
  end
14
+
15
+ share_as :DefinesConstants do
16
+ before do
17
+ @defined_constants = []
18
+ end
19
+
20
+ after do
21
+ @defined_constants.reverse.each do |path|
22
+ namespace, class_name = *constant_path(path)
23
+ namespace.send(:remove_const, class_name)
24
+ end
25
+ end
26
+
27
+ def define_constant(path, base = Object, &block)
28
+ namespace, class_name = *constant_path(path)
29
+ klass = Class.new(base)
30
+ namespace.const_set(class_name, klass)
31
+ klass.class_eval(&block) if block_given?
32
+ @defined_constants << path
33
+ klass
34
+ end
35
+
36
+ def constant_path(constant_name)
37
+ names = constant_name.split('::')
38
+ class_name = names.pop
39
+ namespace = names.inject(Object) { |result, name| result.const_get(name) }
40
+ [namespace, class_name]
41
+ end
42
+ end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factory_girl
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 27
4
5
  prerelease: false
5
6
  segments:
6
7
  - 1
7
- - 2
8
- - 4
9
- version: 1.2.4
8
+ - 3
9
+ - 0
10
+ version: 1.3.0
10
11
  platform: ruby
11
12
  authors:
12
13
  - Joe Ferris
@@ -14,16 +15,18 @@ autorequire:
14
15
  bindir: bin
15
16
  cert_chain: []
16
17
 
17
- date: 2010-03-30 00:00:00 -04:00
18
+ date: 2010-06-11 00:00:00 -04:00
18
19
  default_executable:
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
22
  name: rcov
22
23
  prerelease: false
23
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
24
26
  requirements:
25
27
  - - ">="
26
28
  - !ruby/object:Gem::Version
29
+ hash: 3
27
30
  segments:
28
31
  - 0
29
32
  version: "0"
@@ -33,9 +36,11 @@ dependencies:
33
36
  name: rspec
34
37
  prerelease: false
35
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
36
40
  requirements:
37
41
  - - ">="
38
42
  - !ruby/object:Gem::Version
43
+ hash: 3
39
44
  segments:
40
45
  - 0
41
46
  version: "0"
@@ -45,9 +50,11 @@ dependencies:
45
50
  name: cucumber
46
51
  prerelease: false
47
52
  requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
48
54
  requirements:
49
55
  - - ">="
50
56
  - !ruby/object:Gem::Version
57
+ hash: 3
51
58
  segments:
52
59
  - 0
53
60
  version: "0"
@@ -57,38 +64,63 @@ dependencies:
57
64
  name: activerecord
58
65
  prerelease: false
59
66
  requirement: &id004 !ruby/object:Gem::Requirement
67
+ none: false
60
68
  requirements:
61
- - - ">="
69
+ - - ~>
62
70
  - !ruby/object:Gem::Version
71
+ hash: 9
63
72
  segments:
64
- - 0
65
- version: "0"
73
+ - 2
74
+ - 3
75
+ - 5
76
+ version: 2.3.5
66
77
  type: :development
67
78
  version_requirements: *id004
68
79
  - !ruby/object:Gem::Dependency
69
- name: rr
80
+ name: activerecord
70
81
  prerelease: false
71
82
  requirement: &id005 !ruby/object:Gem::Requirement
83
+ none: false
72
84
  requirements:
73
- - - ">="
85
+ - - ~>
74
86
  - !ruby/object:Gem::Version
87
+ hash: -1848230021
75
88
  segments:
89
+ - 3
76
90
  - 0
77
- version: "0"
91
+ - 0
92
+ - beta3
93
+ version: 3.0.0.beta3
78
94
  type: :development
79
95
  version_requirements: *id005
80
96
  - !ruby/object:Gem::Dependency
81
- name: sqlite3
97
+ name: rr
82
98
  prerelease: false
83
99
  requirement: &id006 !ruby/object:Gem::Requirement
100
+ none: false
84
101
  requirements:
85
102
  - - ">="
86
103
  - !ruby/object:Gem::Version
104
+ hash: 3
87
105
  segments:
88
106
  - 0
89
107
  version: "0"
90
108
  type: :development
91
109
  version_requirements: *id006
110
+ - !ruby/object:Gem::Dependency
111
+ name: sqlite3
112
+ prerelease: false
113
+ requirement: &id007 !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ hash: 3
119
+ segments:
120
+ - 0
121
+ version: "0"
122
+ type: :development
123
+ version_requirements: *id007
92
124
  description: |-
93
125
  factory_girl provides a framework and DSL for defining and
94
126
  using factories - less error-prone, more explicit, and
@@ -101,32 +133,38 @@ extensions: []
101
133
  extra_rdoc_files:
102
134
  - README.rdoc
103
135
  files:
104
- - CONTRIBUTION_GUIDELINES.rdoc
105
136
  - Changelog
137
+ - CONTRIBUTION_GUIDELINES.rdoc
106
138
  - LICENSE
107
- - README.rdoc
108
139
  - Rakefile
109
- - VERSION
110
- - lib/factory_girl.rb
140
+ - README.rdoc
111
141
  - lib/factory_girl/aliases.rb
112
- - lib/factory_girl/attribute.rb
113
142
  - lib/factory_girl/attribute/association.rb
114
143
  - lib/factory_girl/attribute/callback.rb
115
144
  - lib/factory_girl/attribute/dynamic.rb
116
145
  - lib/factory_girl/attribute/static.rb
146
+ - lib/factory_girl/attribute.rb
117
147
  - lib/factory_girl/factory.rb
118
- - lib/factory_girl/proxy.rb
119
148
  - lib/factory_girl/proxy/attributes_for.rb
120
149
  - lib/factory_girl/proxy/build.rb
121
150
  - lib/factory_girl/proxy/create.rb
122
151
  - lib/factory_girl/proxy/stub.rb
152
+ - lib/factory_girl/proxy.rb
123
153
  - lib/factory_girl/sequence.rb
124
154
  - lib/factory_girl/step_definitions.rb
125
- - lib/factory_girl/syntax.rb
126
155
  - lib/factory_girl/syntax/blueprint.rb
127
156
  - lib/factory_girl/syntax/generate.rb
128
157
  - lib/factory_girl/syntax/make.rb
129
158
  - lib/factory_girl/syntax/sham.rb
159
+ - lib/factory_girl/syntax.rb
160
+ - lib/factory_girl.rb
161
+ - spec/acceptance/acceptance_helper.rb
162
+ - spec/acceptance/acceptance_spec.rb
163
+ - spec/acceptance/models.rb
164
+ - spec/acceptance/syntax/blueprint_spec.rb
165
+ - spec/acceptance/syntax/generate_spec.rb
166
+ - spec/acceptance/syntax/make_spec.rb
167
+ - spec/acceptance/syntax/sham_spec.rb
130
168
  - spec/factory_girl/aliases_spec.rb
131
169
  - spec/factory_girl/attribute/association_spec.rb
132
170
  - spec/factory_girl/attribute/callback_spec.rb
@@ -140,13 +178,12 @@ files:
140
178
  - spec/factory_girl/proxy/stub_spec.rb
141
179
  - spec/factory_girl/proxy_spec.rb
142
180
  - spec/factory_girl/sequence_spec.rb
143
- - spec/factory_girl/syntax/blueprint_spec.rb
144
- - spec/factory_girl/syntax/generate_spec.rb
145
- - spec/factory_girl/syntax/make_spec.rb
146
- - spec/factory_girl/syntax/sham_spec.rb
147
- - spec/integration_spec.rb
148
- - spec/models.rb
149
181
  - spec/spec_helper.rb
182
+ - features/factory_girl_steps.feature
183
+ - features/step_definitions/database_steps.rb
184
+ - features/support/env.rb
185
+ - features/support/factories.rb
186
+ - rails/init.rb
150
187
  has_rdoc: true
151
188
  homepage: http://thoughtbot.com/projects/factory_girl
152
189
  licenses: []
@@ -159,27 +196,36 @@ rdoc_options:
159
196
  require_paths:
160
197
  - lib
161
198
  required_ruby_version: !ruby/object:Gem::Requirement
199
+ none: false
162
200
  requirements:
163
201
  - - ">="
164
202
  - !ruby/object:Gem::Version
203
+ hash: 3
165
204
  segments:
166
205
  - 0
167
206
  version: "0"
168
207
  required_rubygems_version: !ruby/object:Gem::Requirement
208
+ none: false
169
209
  requirements:
170
210
  - - ">="
171
211
  - !ruby/object:Gem::Version
212
+ hash: 3
172
213
  segments:
173
214
  - 0
174
215
  version: "0"
175
216
  requirements: []
176
217
 
177
218
  rubyforge_project:
178
- rubygems_version: 1.3.6
219
+ rubygems_version: 1.3.7
179
220
  signing_key:
180
221
  specification_version: 3
181
222
  summary: factory_girl provides a framework and DSL for defining and using model instance factories.
182
223
  test_files:
224
+ - spec/acceptance/acceptance_spec.rb
225
+ - spec/acceptance/syntax/blueprint_spec.rb
226
+ - spec/acceptance/syntax/generate_spec.rb
227
+ - spec/acceptance/syntax/make_spec.rb
228
+ - spec/acceptance/syntax/sham_spec.rb
183
229
  - spec/factory_girl/aliases_spec.rb
184
230
  - spec/factory_girl/attribute/association_spec.rb
185
231
  - spec/factory_girl/attribute/callback_spec.rb
@@ -193,8 +239,7 @@ test_files:
193
239
  - spec/factory_girl/proxy/stub_spec.rb
194
240
  - spec/factory_girl/proxy_spec.rb
195
241
  - spec/factory_girl/sequence_spec.rb
196
- - spec/factory_girl/syntax/blueprint_spec.rb
197
- - spec/factory_girl/syntax/generate_spec.rb
198
- - spec/factory_girl/syntax/make_spec.rb
199
- - spec/factory_girl/syntax/sham_spec.rb
200
- - spec/integration_spec.rb
242
+ - features/factory_girl_steps.feature
243
+ - features/step_definitions/database_steps.rb
244
+ - features/support/env.rb
245
+ - features/support/factories.rb
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 1.2.4