factory_girl 4.3.0 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/GETTING_STARTED.md +143 -137
  4. data/Gemfile.lock +1 -1
  5. data/LICENSE +1 -1
  6. data/NEWS +14 -0
  7. data/README.md +4 -4
  8. data/gemfiles/3.1.gemfile.lock +1 -1
  9. data/gemfiles/3.2.gemfile.lock +1 -1
  10. data/gemfiles/4.0.gemfile.lock +1 -1
  11. data/lib/factory_girl.rb +20 -0
  12. data/lib/factory_girl/attribute_assigner.rb +1 -1
  13. data/lib/factory_girl/attribute_list.rb +1 -1
  14. data/lib/factory_girl/callbacks_observer.rb +1 -1
  15. data/lib/factory_girl/configuration.rb +1 -1
  16. data/lib/factory_girl/declaration_list.rb +2 -2
  17. data/lib/factory_girl/definition.rb +7 -7
  18. data/lib/factory_girl/errors.rb +3 -0
  19. data/lib/factory_girl/factory.rb +2 -2
  20. data/lib/factory_girl/find_definitions.rb +1 -1
  21. data/lib/factory_girl/version.rb +1 -1
  22. data/spec/acceptance/callbacks_spec.rb +4 -4
  23. data/spec/acceptance/global_to_create_spec.rb +3 -3
  24. data/spec/acceptance/initialize_with_spec.rb +2 -2
  25. data/spec/acceptance/keyed_by_class_spec.rb +1 -1
  26. data/spec/acceptance/lint_spec.rb +55 -0
  27. data/spec/acceptance/modify_factories_spec.rb +1 -1
  28. data/spec/acceptance/nested_attributes_spec.rb +1 -1
  29. data/spec/acceptance/parent_spec.rb +1 -1
  30. data/spec/acceptance/sequence_context_spec.rb +4 -4
  31. data/spec/acceptance/sequence_spec.rb +2 -2
  32. data/spec/acceptance/syntax_methods_within_dynamic_attributes_spec.rb +2 -2
  33. data/spec/acceptance/traits_spec.rb +12 -12
  34. data/spec/acceptance/transient_attributes_spec.rb +1 -1
  35. data/spec/factory_girl/attribute/dynamic_spec.rb +1 -1
  36. data/spec/factory_girl/definition_proxy_spec.rb +1 -1
  37. data/spec/factory_girl/definition_spec.rb +7 -1
  38. data/spec/factory_girl/sequence_spec.rb +4 -4
  39. data/spec/support/matchers/trait.rb +3 -1
  40. metadata +4 -2
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- factory_girl (4.3.0)
4
+ factory_girl (4.4.0)
5
5
  activesupport (>= 3.0.0)
6
6
 
7
7
  GEM
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2008-2013 Joe Ferris and thoughtbot, inc.
1
+ Copyright (c) 2008-2014 Joe Ferris and thoughtbot, inc.
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/NEWS CHANGED
@@ -1,3 +1,17 @@
1
+ 4.4.0 (February 10, 2014)
2
+ Add FactoryGirl.lint
3
+ Fix memory leak in duplicate traits
4
+ Update documentation
5
+
6
+ 4.3.0 (November 3, 2013)
7
+ Start testing against Rails 4.0 and Ruby 2.0.0
8
+ Stop testing against Rails 3.0 and Ruby 1.9.2
9
+ Add *_pair methods to only build two objects
10
+ Raise if a method is defined with a FactoryGirl block (factory or trait)
11
+ Allow use of Symbol#to_proc in callbacks
12
+ Add global callbacks
13
+ Improve GETTING_STARTED and README
14
+
1
15
  4.2.0 (January 18, 2013)
2
16
  Improve documentation
3
17
  Allow *_list syntax methods to accept a block
data/README.md CHANGED
@@ -28,18 +28,18 @@ and run `bundle install` from your shell.
28
28
  Supported Ruby versions
29
29
  -----------------------
30
30
 
31
- The FactoryGirl 3.x+ series supports MRI Ruby 1.9. Additionally, FactoryGirl
31
+ The factory_girl 3.x+ series supports MRI Ruby 1.9. Additionally, factory_girl
32
32
  3.6+ supports JRuby 1.6.7.2+ while running in 1.9 mode. See
33
33
  [GETTING_STARTED](https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md)
34
34
  for more information on configuring the JRuby environment.
35
35
 
36
- For versions of Ruby prior to 1.9, please use FactoryGirl 2.x.
36
+ For versions of Ruby prior to 1.9, please use factory_girl 2.x.
37
37
 
38
38
  More Information
39
39
  ----------------
40
40
 
41
41
  * [Rubygems](https://rubygems.org/gems/factory_girl)
42
- * [Mailing list](http://groups.google.com/group/factory_girl)
42
+ * [Stack Overflow](http://stackoverflow.com/questions/tagged/factory-girl)
43
43
  * [Issues](https://github.com/thoughtbot/factory_girl/issues)
44
44
  * [GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS](http://robots.thoughtbot.com/)
45
45
 
@@ -64,4 +64,4 @@ The names and logos for thoughtbot are trademarks of thoughtbot, inc.
64
64
  License
65
65
  -------
66
66
 
67
- factory_girl is Copyright © 2008-2013 Joe Ferris and thoughtbot. It is free software, and may be redistributed under the terms specified in the [LICENSE](https://github.com/thoughtbot/factory_girl/blob/master/LICENSE) file.
67
+ factory_girl is Copyright © 2008-2014 Joe Ferris and thoughtbot. It is free software, and may be redistributed under the terms specified in the [LICENSE](https://github.com/thoughtbot/factory_girl/blob/master/LICENSE) file.
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- factory_girl (4.3.0)
4
+ factory_girl (4.4.0)
5
5
  activesupport (>= 3.0.0)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: /Users/joshuaclayton/dev/gems/factory_girl
3
3
  specs:
4
- factory_girl (4.3.0)
4
+ factory_girl (4.4.0)
5
5
  activesupport (>= 3.0.0)
6
6
 
7
7
  GEM
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- factory_girl (4.3.0)
4
+ factory_girl (4.4.0)
5
5
  activesupport (>= 3.0.0)
6
6
 
7
7
  GEM
@@ -54,6 +54,26 @@ module FactoryGirl
54
54
  @configuration = nil
55
55
  end
56
56
 
57
+ def self.lint
58
+ invalid_factories = FactoryGirl.factories.select do |factory|
59
+ built_factory = FactoryGirl.build(factory.name)
60
+
61
+ if built_factory.respond_to?(:valid?)
62
+ !built_factory.valid?
63
+ end
64
+ end
65
+
66
+ if invalid_factories.any?
67
+ error_message = <<-ERROR_MESSAGE.strip
68
+ The following factories are invalid:
69
+
70
+ #{invalid_factories.map {|factory| "* #{factory.name}" }.join("\n")}
71
+ ERROR_MESSAGE
72
+
73
+ raise InvalidFactoryError, error_message
74
+ end
75
+ end
76
+
57
77
  class << self
58
78
  delegate :factories, :sequences, :traits, :callbacks, :strategies, :callback_names,
59
79
  :to_create, :skip_create, :initialize_with, :constructor, :duplicate_attribute_assignment_from_initialize_with,
@@ -90,7 +90,7 @@ module FactoryGirl
90
90
 
91
91
  def alias_names_to_ignore
92
92
  @attribute_list.non_ignored.map do |attribute|
93
- override_names.map {|override| attribute.name if attribute.alias_for?(override) && attribute.name != override && !ignored_attribute_names.include?(override) }
93
+ override_names.map { |override| attribute.name if attribute.alias_for?(override) && attribute.name != override && !ignored_attribute_names.include?(override) }
94
94
  end.flatten.compact
95
95
  end
96
96
  end
@@ -36,7 +36,7 @@ module FactoryGirl
36
36
  end
37
37
 
38
38
  def apply_attributes(attributes_to_apply)
39
- attributes_to_apply.each {|attribute| add_attribute(attribute) }
39
+ attributes_to_apply.each { |attribute| add_attribute(attribute) }
40
40
  end
41
41
 
42
42
  private
@@ -15,7 +15,7 @@ module FactoryGirl
15
15
  private
16
16
 
17
17
  def callbacks_by_name(name)
18
- @callbacks.select {|callback| callback.name == name }
18
+ @callbacks.select { |callback| callback.name == name }
19
19
  end
20
20
  end
21
21
  end
@@ -11,7 +11,7 @@ module FactoryGirl
11
11
  @callback_names = Set.new
12
12
  @definition = Definition.new
13
13
 
14
- to_create {|instance| instance.save! }
14
+ to_create { |instance| instance.save! }
15
15
  initialize_with { new }
16
16
  end
17
17
 
@@ -35,11 +35,11 @@ module FactoryGirl
35
35
  private
36
36
 
37
37
  def delete_declaration(declaration)
38
- @declarations.delete_if {|decl| decl.name == declaration.name }
38
+ @declarations.delete_if { |decl| decl.name == declaration.name }
39
39
  end
40
40
 
41
41
  def to_attributes
42
- @declarations.inject([]) {|result, declaration| result += declaration.to_attributes }
42
+ @declarations.inject([]) { |result, declaration| result += declaration.to_attributes }
43
43
  end
44
44
 
45
45
  def overridable?
@@ -6,7 +6,7 @@ module FactoryGirl
6
6
  def initialize(name = nil, base_traits = [])
7
7
  @declarations = DeclarationList.new(name)
8
8
  @callbacks = []
9
- @defined_traits = []
9
+ @defined_traits = Set.new
10
10
  @to_create = nil
11
11
  @base_traits = base_traits
12
12
  @additional_traits = []
@@ -47,8 +47,8 @@ module FactoryGirl
47
47
  declarations.attributes
48
48
 
49
49
  defined_traits.each do |defined_trait|
50
- base_traits.each {|bt| bt.define_trait defined_trait }
51
- additional_traits.each {|bt| bt.define_trait defined_trait }
50
+ base_traits.each { |bt| bt.define_trait defined_trait }
51
+ additional_traits.each { |bt| bt.define_trait defined_trait }
52
52
  end
53
53
 
54
54
  @compiled = true
@@ -77,7 +77,7 @@ module FactoryGirl
77
77
  end
78
78
 
79
79
  def define_trait(trait)
80
- @defined_traits << trait
80
+ @defined_traits.add(trait)
81
81
  end
82
82
 
83
83
  def define_constructor(&block)
@@ -85,11 +85,11 @@ module FactoryGirl
85
85
  end
86
86
 
87
87
  def before(*names, &block)
88
- callback(*names.map {|name| "before_#{name}" }, &block)
88
+ callback(*names.map { |name| "before_#{name}" }, &block)
89
89
  end
90
90
 
91
91
  def after(*names, &block)
92
- callback(*names.map {|name| "after_#{name}" }, &block)
92
+ callback(*names.map { |name| "after_#{name}" }, &block)
93
93
  end
94
94
 
95
95
  def callback(*names, &block)
@@ -114,7 +114,7 @@ module FactoryGirl
114
114
  end
115
115
 
116
116
  def trait_for(name)
117
- defined_traits.detect {|trait| trait.name == name }
117
+ defined_traits.detect { |trait| trait.name == name }
118
118
  end
119
119
 
120
120
  def initialize_copy(source)
@@ -19,4 +19,7 @@ module FactoryGirl
19
19
 
20
20
  # Raised when a method is defined in a factory or trait with arguments
21
21
  class MethodDefinitionError < RuntimeError; end
22
+
23
+ # Raised when any factory is considered invalid
24
+ class InvalidFactoryError < RuntimeError; end
22
25
  end
@@ -43,7 +43,7 @@ module FactoryGirl
43
43
  end
44
44
 
45
45
  def human_names
46
- names.map {|name| name.to_s.humanize.downcase }
46
+ names.map { |name| name.to_s.humanize.downcase }
47
47
  end
48
48
 
49
49
  def associations
@@ -82,7 +82,7 @@ module FactoryGirl
82
82
  def compile
83
83
  unless @compiled
84
84
  parent.compile
85
- parent.defined_traits.each {|trait| define_trait(trait) }
85
+ parent.defined_traits.each { |trait| define_trait(trait) }
86
86
  @definition.compile
87
87
  build_hierarchy
88
88
  @compiled = true
@@ -10,7 +10,7 @@ module FactoryGirl
10
10
  self.definition_file_paths = %w(factories test/factories spec/factories)
11
11
 
12
12
  def self.find_definitions
13
- absolute_definition_file_paths = definition_file_paths.map {|path| File.expand_path(path) }
13
+ absolute_definition_file_paths = definition_file_paths.map { |path| File.expand_path(path) }
14
14
 
15
15
  absolute_definition_file_paths.uniq.each do |path|
16
16
  load("#{path}.rb") if File.exists?("#{path}.rb")
@@ -1,3 +1,3 @@
1
1
  module FactoryGirl
2
- VERSION = '4.3.0'
2
+ VERSION = '4.4.0'
3
3
  end
@@ -82,8 +82,8 @@ describe "callbacks using syntax methods without referencing FactoryGirl explici
82
82
 
83
83
  factory :user do
84
84
  after(:stub) { generate(:sequence_3) }
85
- after(:build) {|user| user.first_name = generate(:sequence_1) }
86
- after(:create) {|user, evaluator| user.last_name = generate(:sequence_2) }
85
+ after(:build) { |user| user.first_name = generate(:sequence_1) }
86
+ after(:create) { |user, evaluator| user.last_name = generate(:sequence_2) }
87
87
  end
88
88
  end
89
89
  end
@@ -149,8 +149,8 @@ describe "custom callbacks" do
149
149
  first_name "John"
150
150
  last_name "Doe"
151
151
 
152
- before(:custom) {|instance| instance.first_name = "Overridden First" }
153
- after(:custom) {|instance| instance.last_name = "Overridden Last" }
152
+ before(:custom) { |instance| instance.first_name = "Overridden First" }
153
+ after(:custom) { |instance| instance.last_name = "Overridden Last" }
154
154
  callback(:totally_custom) do |instance|
155
155
  instance.first_name = "Totally"
156
156
  instance.last_name = "Custom"
@@ -6,10 +6,10 @@ describe 'global to_create' do
6
6
  define_model('Post', name: :string)
7
7
 
8
8
  FactoryGirl.define do
9
- to_create {|instance| instance.name = 'persisted!' }
9
+ to_create { |instance| instance.name = 'persisted!' }
10
10
 
11
11
  trait :override_to_create do
12
- to_create {|instance| instance.name = 'override' }
12
+ to_create { |instance| instance.name = 'override' }
13
13
  end
14
14
 
15
15
  factory :user do
@@ -75,7 +75,7 @@ describe 'global skip_create' do
75
75
  skip_create
76
76
 
77
77
  trait :override_to_create do
78
- to_create {|instance| instance.name = 'override' }
78
+ to_create { |instance| instance.name = 'override' }
79
79
  end
80
80
 
81
81
  factory :user do
@@ -160,7 +160,7 @@ describe "initialize_with doesn't duplicate assignment on attributes accessed fr
160
160
  end
161
161
 
162
162
  FactoryGirl.define do
163
- sequence(:email) {|n| "person#{n}@example.com" }
163
+ sequence(:email) { |n| "person#{n}@example.com" }
164
164
 
165
165
  factory :user do
166
166
  email
@@ -192,7 +192,7 @@ describe "initialize_with has access to all attributes for construction" do
192
192
  end
193
193
 
194
194
  FactoryGirl.define do
195
- sequence(:email) {|n| "person#{n}@example.com" }
195
+ sequence(:email) { |n| "person#{n}@example.com" }
196
196
 
197
197
  factory :user do
198
198
  ignore do
@@ -9,7 +9,7 @@ describe 'finding factories keyed by class instead of symbol' do
9
9
  FactoryGirl.define do
10
10
  factory :user do
11
11
  name 'John Doe'
12
- sequence(:email) {|n| "person#{n}@example.com" }
12
+ sequence(:email) { |n| "person#{n}@example.com" }
13
13
  end
14
14
  end
15
15
  end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'FactoryGirl.lint' do
4
+ it 'raises when a factory is invalid' do
5
+ define_model 'User', name: :string do
6
+ validates :name, presence: true
7
+ end
8
+
9
+ define_model 'AlwaysValid'
10
+
11
+ FactoryGirl.define do
12
+ factory :user do
13
+ factory :admin_user
14
+ end
15
+
16
+ factory :always_valid
17
+ end
18
+
19
+ error_message = <<-ERROR_MESSAGE.strip
20
+ The following factories are invalid:
21
+
22
+ * user
23
+ * admin_user
24
+ ERROR_MESSAGE
25
+
26
+ expect do
27
+ FactoryGirl.lint
28
+ end.to raise_error FactoryGirl::InvalidFactoryError, error_message
29
+ end
30
+
31
+ it 'does not raise when all factories are valid' do
32
+ define_model 'User', name: :string do
33
+ validates :name, presence: true
34
+ end
35
+
36
+ FactoryGirl.define do
37
+ factory :user do
38
+ name 'assigned'
39
+ end
40
+ end
41
+
42
+ expect { FactoryGirl.lint }.not_to raise_error
43
+ end
44
+
45
+ it 'supports models which do not respond to #valid?' do
46
+ define_class 'Thing'
47
+
48
+ FactoryGirl.define do
49
+ factory :thing
50
+ end
51
+
52
+ expect(Thing.new).not_to respond_to(:valid?)
53
+ expect { FactoryGirl.lint }.not_to raise_error
54
+ end
55
+ end
@@ -7,7 +7,7 @@ describe "modifying factories" do
7
7
  define_model('User', name: :string, admin: :boolean, email: :string, login: :string)
8
8
 
9
9
  FactoryGirl.define do
10
- sequence(:email) {|n| "user#{n}@example.com" }
10
+ sequence(:email) { |n| "user#{n}@example.com" }
11
11
 
12
12
  factory :user do
13
13
  email
@@ -17,7 +17,7 @@ describe "association assignment from nested attributes" do
17
17
  end
18
18
 
19
19
  factory :comment do
20
- sequence(:body) {|n| "Body #{n}" }
20
+ sequence(:body) { |n| "Body #{n}" }
21
21
  end
22
22
  end
23
23
  end
@@ -78,7 +78,7 @@ describe "nested factories with different parents" do
78
78
  end
79
79
 
80
80
  factory :uppercase_male_user, parent: :male_user do
81
- after(:build) {|user| user.name = user.name.upcase }
81
+ after(:build) { |user| user.name = user.name.upcase }
82
82
  end
83
83
  end
84
84
  end
@@ -14,7 +14,7 @@ describe 'sequences are evaluated in the correct context' do
14
14
  it 'builds a sequence calling sprintf correctly' do
15
15
  FactoryGirl.define do
16
16
  factory :sequence_with_sprintf, class: User do
17
- sequence(:id) {|n| sprintf("foo%d", n) }
17
+ sequence(:id) { |n| sprintf("foo%d", n) }
18
18
  end
19
19
  end
20
20
 
@@ -24,7 +24,7 @@ describe 'sequences are evaluated in the correct context' do
24
24
  it 'invokes the correct method on the instance' do
25
25
  FactoryGirl.define do
26
26
  factory :sequence_with_public_method, class: User do
27
- sequence(:id) {|n| public_method(:awesome).call }
27
+ sequence(:id) { |n| public_method(:awesome).call }
28
28
  end
29
29
  end
30
30
 
@@ -34,7 +34,7 @@ describe 'sequences are evaluated in the correct context' do
34
34
  it 'invokes a method with no arguments on the instance' do
35
35
  FactoryGirl.define do
36
36
  factory :sequence_with_frozen, class: User do
37
- sequence(:id) {|n| frozen? }
37
+ sequence(:id) { |n| frozen? }
38
38
  end
39
39
  end
40
40
 
@@ -44,7 +44,7 @@ describe 'sequences are evaluated in the correct context' do
44
44
  it 'allows direct reference of a method in a sequence' do
45
45
  FactoryGirl.define do
46
46
  factory :sequence_referencing_attribute_directly, class: User do
47
- sequence(:id) {|n| "#{awesome}#{n}" }
47
+ sequence(:id) { |n| "#{awesome}#{n}" }
48
48
  end
49
49
  end
50
50
  expect(FactoryGirl.build(:sequence_referencing_attribute_directly).id).to eq 'aw yeah1'