factory_girl 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. data/Appraisals +3 -3
  2. data/GETTING_STARTED.md +74 -15
  3. data/Gemfile.lock +38 -44
  4. data/NEWS +12 -0
  5. data/gemfiles/3.0.gemfile +1 -1
  6. data/gemfiles/3.0.gemfile.lock +23 -24
  7. data/gemfiles/3.1.gemfile +1 -1
  8. data/gemfiles/3.1.gemfile.lock +19 -19
  9. data/gemfiles/3.2.gemfile +1 -1
  10. data/gemfiles/3.2.gemfile.lock +10 -10
  11. data/lib/factory_girl.rb +39 -37
  12. data/lib/factory_girl/aliases.rb +3 -4
  13. data/lib/factory_girl/attribute.rb +33 -11
  14. data/lib/factory_girl/attribute/association.rb +3 -2
  15. data/lib/factory_girl/attribute/dynamic.rb +3 -2
  16. data/lib/factory_girl/attribute/sequence.rb +1 -2
  17. data/lib/factory_girl/attribute/static.rb +3 -2
  18. data/lib/factory_girl/attribute_assigner.rb +6 -5
  19. data/lib/factory_girl/attribute_list.rb +16 -3
  20. data/lib/factory_girl/callback.rb +7 -3
  21. data/lib/factory_girl/callbacks_observer.rb +1 -0
  22. data/lib/factory_girl/configuration.rb +24 -0
  23. data/lib/factory_girl/declaration.rb +5 -4
  24. data/lib/factory_girl/declaration/association.rb +1 -0
  25. data/lib/factory_girl/declaration/dynamic.rb +1 -0
  26. data/lib/factory_girl/declaration/implicit.rb +1 -0
  27. data/lib/factory_girl/declaration/static.rb +1 -0
  28. data/lib/factory_girl/declaration_list.rb +1 -0
  29. data/lib/factory_girl/definition.rb +22 -3
  30. data/lib/factory_girl/definition_list.rb +31 -0
  31. data/lib/factory_girl/definition_proxy.rb +19 -4
  32. data/lib/factory_girl/evaluation.rb +3 -3
  33. data/lib/factory_girl/evaluator.rb +24 -14
  34. data/lib/factory_girl/evaluator_class_definer.rb +2 -13
  35. data/lib/factory_girl/factory.rb +22 -24
  36. data/lib/factory_girl/factory_runner.rb +6 -3
  37. data/lib/factory_girl/find_definitions.rb +2 -2
  38. data/lib/factory_girl/null_factory.rb +3 -1
  39. data/lib/factory_girl/null_object.rb +1 -0
  40. data/lib/factory_girl/reload.rb +4 -6
  41. data/lib/factory_girl/sequence.rb +3 -2
  42. data/lib/factory_girl/step_definitions.rb +1 -0
  43. data/lib/factory_girl/strategy/attributes_for.rb +1 -1
  44. data/lib/factory_girl/strategy/stub.rb +6 -6
  45. data/lib/factory_girl/strategy_calculator.rb +1 -0
  46. data/lib/factory_girl/strategy_syntax_method_registrar.rb +37 -0
  47. data/lib/factory_girl/syntax.rb +5 -4
  48. data/lib/factory_girl/syntax/blueprint.rb +5 -8
  49. data/lib/factory_girl/syntax/default.rb +18 -6
  50. data/lib/factory_girl/syntax/generate.rb +10 -13
  51. data/lib/factory_girl/syntax/make.rb +8 -11
  52. data/lib/factory_girl/syntax/methods.rb +76 -36
  53. data/lib/factory_girl/syntax/sham.rb +3 -2
  54. data/lib/factory_girl/syntax/vintage.rb +9 -9
  55. data/lib/factory_girl/syntax_runner.rb +1 -0
  56. data/lib/factory_girl/trait.rb +5 -4
  57. data/lib/factory_girl/version.rb +1 -2
  58. data/spec/acceptance/activesupport_instrumentation_spec.rb +15 -2
  59. data/spec/acceptance/callbacks_spec.rb +113 -9
  60. data/spec/acceptance/create_list_spec.rb +1 -1
  61. data/spec/acceptance/global_initialize_with_spec.rb +82 -0
  62. data/spec/acceptance/global_to_create_spec.rb +122 -0
  63. data/spec/acceptance/modify_factories_spec.rb +2 -2
  64. data/spec/acceptance/parent_spec.rb +1 -1
  65. data/spec/acceptance/register_strategies_spec.rb +8 -0
  66. data/spec/acceptance/syntax/vintage_spec.rb +8 -8
  67. data/spec/acceptance/traits_spec.rb +145 -3
  68. data/spec/acceptance/transient_attributes_spec.rb +1 -1
  69. data/spec/factory_girl/attribute_list_spec.rb +66 -1
  70. data/spec/factory_girl/attribute_spec.rb +1 -1
  71. data/spec/factory_girl/definition_proxy_spec.rb +6 -6
  72. data/spec/factory_girl/definition_spec.rb +22 -16
  73. data/spec/factory_girl/factory_spec.rb +6 -4
  74. data/spec/factory_girl/strategy/build_spec.rb +2 -2
  75. data/spec/factory_girl/strategy/create_spec.rb +1 -1
  76. data/spec/factory_girl/strategy/stub_spec.rb +2 -2
  77. data/spec/factory_girl/strategy_calculator_spec.rb +20 -14
  78. data/spec/support/shared_examples/strategy.rb +8 -9
  79. metadata +94 -29
  80. data/gemfiles/2.3.gemfile +0 -7
@@ -1,9 +1,10 @@
1
- require "factory_girl/declaration/static"
2
- require "factory_girl/declaration/dynamic"
3
- require "factory_girl/declaration/association"
4
- require "factory_girl/declaration/implicit"
1
+ require 'factory_girl/declaration/static'
2
+ require 'factory_girl/declaration/dynamic'
3
+ require 'factory_girl/declaration/association'
4
+ require 'factory_girl/declaration/implicit'
5
5
 
6
6
  module FactoryGirl
7
+ # @api private
7
8
  class Declaration
8
9
  attr_reader :name
9
10
 
@@ -1,5 +1,6 @@
1
1
  module FactoryGirl
2
2
  class Declaration
3
+ # @api private
3
4
  class Association < Declaration
4
5
  def initialize(name, options)
5
6
  super(name, false)
@@ -1,5 +1,6 @@
1
1
  module FactoryGirl
2
2
  class Declaration
3
+ # @api private
3
4
  class Dynamic < Declaration
4
5
  def initialize(name, ignored = false, block = nil)
5
6
  super(name, ignored)
@@ -1,5 +1,6 @@
1
1
  module FactoryGirl
2
2
  class Declaration
3
+ # @api private
3
4
  class Implicit < Declaration
4
5
  def initialize(name, factory = nil, ignored = false)
5
6
  super(name, ignored)
@@ -1,5 +1,6 @@
1
1
  module FactoryGirl
2
2
  class Declaration
3
+ # @api private
3
4
  class Static < Declaration
4
5
  def initialize(name, value, ignored = false)
5
6
  super(name, ignored)
@@ -1,4 +1,5 @@
1
1
  module FactoryGirl
2
+ # @api private
2
3
  class DeclarationList
3
4
  include Enumerable
4
5
 
@@ -1,4 +1,5 @@
1
1
  module FactoryGirl
2
+ # @api private
2
3
  class Definition
3
4
  attr_reader :callbacks, :defined_traits, :declarations, :constructor
4
5
 
@@ -6,7 +7,7 @@ module FactoryGirl
6
7
  @declarations = DeclarationList.new(name)
7
8
  @callbacks = []
8
9
  @defined_traits = []
9
- @to_create = ->(instance) { instance.save! }
10
+ @to_create = nil
10
11
  @base_traits = base_traits
11
12
  @additional_traits = []
12
13
  @constructor = nil
@@ -22,8 +23,10 @@ module FactoryGirl
22
23
  attributes
23
24
  end
24
25
 
25
- def processing_order
26
- base_traits + [self] + additional_traits
26
+ def definition_list
27
+ DefinitionList.new(
28
+ base_traits.map(&:definition) + [self] + additional_traits.map(&:definition)
29
+ )
27
30
  end
28
31
 
29
32
  def overridable
@@ -32,6 +35,10 @@ module FactoryGirl
32
35
  end
33
36
 
34
37
  def inherit_traits(new_traits)
38
+ @base_traits += new_traits
39
+ end
40
+
41
+ def append_traits(new_traits)
35
42
  @additional_traits += new_traits
36
43
  end
37
44
 
@@ -39,6 +46,14 @@ module FactoryGirl
39
46
  @callbacks << callback
40
47
  end
41
48
 
49
+ def compiled_to_create
50
+ definition_list.to_create
51
+ end
52
+
53
+ def compiled_constructor
54
+ definition_list.constructor
55
+ end
56
+
42
57
  def to_create(&block)
43
58
  if block_given?
44
59
  @to_create = block
@@ -47,6 +62,10 @@ module FactoryGirl
47
62
  end
48
63
  end
49
64
 
65
+ def skip_create
66
+ @to_create = ->(instance) { }
67
+ end
68
+
50
69
  def define_trait(trait)
51
70
  @defined_traits << trait
52
71
  end
@@ -0,0 +1,31 @@
1
+ module FactoryGirl
2
+ class DefinitionList
3
+ include Enumerable
4
+
5
+ def initialize(definitions = [])
6
+ @definitions = definitions
7
+ end
8
+
9
+ def each(&block)
10
+ @definitions.each &block
11
+ end
12
+
13
+ def callbacks
14
+ map(&:callbacks).flatten
15
+ end
16
+
17
+ def attributes
18
+ map {|definition| definition.attributes.to_a }.flatten
19
+ end
20
+
21
+ def to_create
22
+ map(&:to_create).compact.last
23
+ end
24
+
25
+ def constructor
26
+ map(&:constructor).compact.last
27
+ end
28
+
29
+ delegate :[], :==, to: :@definitions
30
+ end
31
+ end
@@ -1,6 +1,6 @@
1
1
  module FactoryGirl
2
2
  class DefinitionProxy
3
- UNPROXIED_METHODS = %w(__send__ __id__ nil? send object_id extend instance_eval initialize block_given? raise)
3
+ UNPROXIED_METHODS = %w(__send__ __id__ nil? send object_id extend instance_eval initialize block_given? raise caller)
4
4
 
5
5
  (instance_methods + private_instance_methods).each do |method|
6
6
  undef_method(method) unless UNPROXIED_METHODS.include?(method.to_s)
@@ -33,7 +33,7 @@ module FactoryGirl
33
33
  # * value: +Object+
34
34
  # If no block is given, this value will be used for this attribute.
35
35
  def add_attribute(name, value = nil, &block)
36
- raise AttributeDefinitionError, "Both value and block given" if value && block_given?
36
+ raise AttributeDefinitionError, 'Both value and block given' if value && block_given?
37
37
 
38
38
  declaration = if block_given?
39
39
  Declaration::Dynamic.new(name, @ignore, block)
@@ -83,9 +83,11 @@ module FactoryGirl
83
83
  def method_missing(name, *args, &block)
84
84
  if args.empty? && block.nil?
85
85
  @definition.declare_attribute(Declaration::Implicit.new(name, @definition, @ignore))
86
- elsif args.first.is_a?(Hash) && args.first.has_key?(:factory)
86
+ elsif args.first.respond_to?(:has_key?) && args.first.has_key?(:factory)
87
87
  association(name, *args)
88
88
  elsif FactoryGirl.callback_names.include?(name)
89
+ callback_when, callback_name = name.to_s.split('_', 2)
90
+ ActiveSupport::Deprecation.warn "Calling #{name} is deprecated; use the syntax #{callback_when}(:#{callback_name}) {}", caller
89
91
  @definition.add_callback(Callback.new(name, block))
90
92
  else
91
93
  add_attribute(name, *args, &block)
@@ -145,7 +147,7 @@ module FactoryGirl
145
147
  end
146
148
 
147
149
  def skip_create
148
- @definition.to_create {|instance| }
150
+ @definition.skip_create
149
151
  end
150
152
 
151
153
  def factory(name, options = {}, &block)
@@ -159,5 +161,18 @@ module FactoryGirl
159
161
  def initialize_with(&block)
160
162
  @definition.define_constructor(&block)
161
163
  end
164
+
165
+ def before(name, &block)
166
+ callback("before_#{name}", &block)
167
+ end
168
+
169
+ def after(name, &block)
170
+ callback("after_#{name}", &block)
171
+ end
172
+
173
+ def callback(name, &block)
174
+ FactoryGirl.register_callback(name)
175
+ @definition.add_callback(Callback.new(name, block))
176
+ end
162
177
  end
163
178
  end
@@ -1,4 +1,4 @@
1
- require "observer"
1
+ require 'observer'
2
2
 
3
3
  module FactoryGirl
4
4
  class Evaluation
@@ -9,12 +9,12 @@ module FactoryGirl
9
9
  @to_create = to_create
10
10
  end
11
11
 
12
+ delegate :object, :hash, to: :@attribute_assigner
13
+
12
14
  def create(result_instance)
13
15
  @to_create[result_instance]
14
16
  end
15
17
 
16
- delegate :object, :hash, to: :@attribute_assigner
17
-
18
18
  def notify(name, result_instance)
19
19
  changed
20
20
  notify_observers(name, result_instance)
@@ -1,18 +1,11 @@
1
- require "active_support/core_ext/hash/except"
2
- require "active_support/core_ext/class/attribute"
1
+ require 'active_support/core_ext/hash/except'
2
+ require 'active_support/core_ext/class/attribute'
3
3
 
4
4
  module FactoryGirl
5
+ # @api private
5
6
  class Evaluator
6
7
  class_attribute :attribute_lists
7
8
 
8
- def self.attribute_list
9
- AttributeList.new.tap do |list|
10
- attribute_lists.each do |attribute_list|
11
- list.apply_attributes attribute_list.to_a
12
- end
13
- end
14
- end
15
-
16
9
  private_instance_methods.each do |method|
17
10
  undef_method(method) unless method =~ /^__|initialize/
18
11
  end
@@ -24,17 +17,16 @@ module FactoryGirl
24
17
  @cached_attributes = overrides
25
18
 
26
19
  @overrides.each do |name, value|
27
- singleton_class.send :define_method, name, -> { value }
20
+ singleton_class.define_attribute(name) { value }
28
21
  end
29
22
  end
30
23
 
31
24
  delegate :new, to: :@build_class
32
25
 
33
26
  def association(factory_name, overrides = {})
34
- strategy_override = overrides.fetch(:strategy) { FactoryGirl.strategy_by_name(:create) }
27
+ strategy_override = overrides.fetch(:strategy) { :create }
35
28
 
36
- build_strategy = StrategyCalculator.new(strategy_override).strategy
37
- runner = FactoryRunner.new(factory_name, build_strategy, [overrides.except(:strategy)])
29
+ runner = FactoryRunner.new(factory_name, strategy_override, [overrides.except(:strategy)])
38
30
  @build_strategy.association(runner)
39
31
  end
40
32
 
@@ -57,5 +49,23 @@ module FactoryGirl
57
49
  def __override_names__
58
50
  @overrides.keys
59
51
  end
52
+
53
+ def self.attribute_list
54
+ AttributeList.new.tap do |list|
55
+ attribute_lists.each do |attribute_list|
56
+ list.apply_attributes attribute_list.to_a
57
+ end
58
+ end
59
+ end
60
+
61
+ def self.define_attribute(name, &block)
62
+ define_method(name) do
63
+ if @cached_attributes.key?(name)
64
+ @cached_attributes[name]
65
+ else
66
+ @cached_attributes[name] = instance_exec(&block)
67
+ end
68
+ end
69
+ end
60
70
  end
61
71
  end
@@ -1,11 +1,12 @@
1
1
  module FactoryGirl
2
+ # @api private
2
3
  class EvaluatorClassDefiner
3
4
  def initialize(attributes, parent_class)
4
5
  @parent_class = parent_class
5
6
  @attributes = attributes
6
7
 
7
8
  attributes.each do |attribute|
8
- define_attribute(attribute.name, attribute.to_proc)
9
+ evaluator_class.define_attribute(attribute.name, &attribute.to_proc)
9
10
  end
10
11
  end
11
12
 
@@ -15,17 +16,5 @@ module FactoryGirl
15
16
  klass.attribute_lists += [@attributes]
16
17
  end
17
18
  end
18
-
19
- private
20
-
21
- def define_attribute(attribute_name, attribute_proc)
22
- evaluator_class.send(:define_method, attribute_name) do
23
- if @cached_attributes.key?(attribute_name)
24
- @cached_attributes[attribute_name]
25
- else
26
- @cached_attributes[attribute_name] = instance_exec(&attribute_proc)
27
- end
28
- end
29
- end
30
19
  end
31
20
  end
@@ -1,11 +1,12 @@
1
- require "active_support/core_ext/hash/keys"
2
- require "active_support/inflector"
1
+ require 'active_support/core_ext/hash/keys'
2
+ require 'active_support/inflector'
3
3
 
4
4
  module FactoryGirl
5
+ # @api private
5
6
  class Factory
6
- attr_reader :name, :definition #:nodoc:
7
+ attr_reader :name, :definition
7
8
 
8
- def initialize(name, options = {}) #:nodoc:
9
+ def initialize(name, options = {})
9
10
  assert_valid_options(options)
10
11
  @name = name.is_a?(Symbol) ? name : name.to_s.underscore.to_sym
11
12
  @parent = options[:parent]
@@ -15,10 +16,10 @@ module FactoryGirl
15
16
  @compiled = false
16
17
  end
17
18
 
18
- delegate :add_callback, :declare_attribute, :to_create, :define_trait,
19
- :defined_traits, :inherit_traits, :processing_order, to: :@definition
19
+ delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor,
20
+ :defined_traits, :inherit_traits, :append_traits, :definition_list, to: :@definition
20
21
 
21
- def build_class #:nodoc:
22
+ def build_class
22
23
  @build_class ||= if class_name.is_a? Class
23
24
  class_name
24
25
  else
@@ -26,16 +27,16 @@ module FactoryGirl
26
27
  end
27
28
  end
28
29
 
29
- def run(strategy_class, overrides, &block) #:nodoc:
30
+ def run(build_strategy, overrides, &block)
30
31
  block ||= ->(result) { result }
31
32
  compile
32
33
 
33
- strategy = strategy_class.new
34
+ strategy = StrategyCalculator.new(build_strategy).strategy.new
34
35
 
35
36
  evaluator = evaluator_class.new(build_class, strategy, overrides.symbolize_keys)
36
- attribute_assigner = AttributeAssigner.new(evaluator, build_class, &instance_builder)
37
+ attribute_assigner = AttributeAssigner.new(evaluator, build_class, &compiled_constructor)
37
38
 
38
- evaluation = Evaluation.new(attribute_assigner, to_create)
39
+ evaluation = Evaluation.new(attribute_assigner, compiled_to_create)
39
40
  evaluation.add_observer(CallbacksObserver.new(callbacks, evaluator))
40
41
 
41
42
  strategy.result(evaluation).tap(&block)
@@ -89,13 +90,13 @@ module FactoryGirl
89
90
 
90
91
  def with_traits(traits)
91
92
  self.clone.tap do |factory_with_traits|
92
- factory_with_traits.inherit_traits traits
93
+ factory_with_traits.append_traits traits
93
94
  end
94
95
  end
95
96
 
96
97
  protected
97
98
 
98
- def class_name #:nodoc:
99
+ def class_name
99
100
  @class_name || parent.class_name || name
100
101
  end
101
102
 
@@ -106,18 +107,20 @@ module FactoryGirl
106
107
  def attributes
107
108
  compile
108
109
  AttributeList.new(@name).tap do |list|
109
- processing_order.each do |factory|
110
- list.apply_attributes factory.attributes
111
- end
110
+ list.apply_attributes definition_list.attributes
112
111
  end
113
112
  end
114
113
 
115
114
  def callbacks
116
- parent.callbacks + processing_order.map {|factory| factory.callbacks }.flatten
115
+ parent.callbacks + definition_list.callbacks
117
116
  end
118
117
 
119
- def constructor
120
- @constructor ||= @definition.constructor || parent.constructor
118
+ def compiled_to_create
119
+ @definition.compiled_to_create || parent.compiled_to_create || FactoryGirl.to_create
120
+ end
121
+
122
+ def compiled_constructor
123
+ @definition.compiled_constructor || parent.compiled_constructor || FactoryGirl.constructor
121
124
  end
122
125
 
123
126
  private
@@ -134,11 +137,6 @@ module FactoryGirl
134
137
  end
135
138
  end
136
139
 
137
- def instance_builder
138
- build_class = self.build_class
139
- constructor || -> { build_class.new }
140
- end
141
-
142
140
  def initialize_copy(source)
143
141
  super
144
142
  @definition = @definition.clone
@@ -8,8 +8,7 @@ module FactoryGirl
8
8
  @traits = traits_and_overrides
9
9
  end
10
10
 
11
- def run(strategy_override = nil, &block)
12
- strategy_override ||= @strategy
11
+ def run(runner_strategy = @strategy, &block)
13
12
  factory = FactoryGirl.factory_by_name(@name)
14
13
 
15
14
  factory.compile
@@ -18,7 +17,11 @@ module FactoryGirl
18
17
  factory = factory.with_traits(@traits)
19
18
  end
20
19
 
21
- factory.run(strategy_override, @overrides, &block)
20
+ instrumentation_payload = { name: @name, strategy: runner_strategy }
21
+
22
+ ActiveSupport::Notifications.instrument('factory_girl.run_factory', instrumentation_payload) do
23
+ factory.run(runner_strategy, @overrides, &block)
24
+ end
22
25
  end
23
26
  end
24
27
  end