factory_girl 3.1.1 → 3.2.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 (59) hide show
  1. data/.simplecov +4 -0
  2. data/GETTING_STARTED.md +147 -3
  3. data/Gemfile.lock +1 -1
  4. data/NEWS +8 -0
  5. data/features/support/env.rb +0 -1
  6. data/gemfiles/3.0.gemfile.lock +1 -1
  7. data/gemfiles/3.1.gemfile.lock +1 -1
  8. data/gemfiles/3.2.gemfile.lock +1 -1
  9. data/lib/factory_girl.rb +50 -7
  10. data/lib/factory_girl/attribute.rb +1 -1
  11. data/lib/factory_girl/attribute/association.rb +1 -1
  12. data/lib/factory_girl/attribute/dynamic.rb +1 -1
  13. data/lib/factory_girl/attribute/sequence.rb +1 -1
  14. data/lib/factory_girl/attribute/static.rb +1 -1
  15. data/lib/factory_girl/attribute_assigner.rb +12 -3
  16. data/lib/factory_girl/callback.rb +4 -1
  17. data/lib/factory_girl/{callback_runner.rb → callbacks_observer.rb} +1 -1
  18. data/lib/factory_girl/definition.rb +1 -1
  19. data/lib/factory_girl/definition_proxy.rb +4 -0
  20. data/lib/factory_girl/disallows_duplicates_registry.rb +17 -0
  21. data/lib/factory_girl/evaluator.rb +14 -11
  22. data/lib/factory_girl/factory.rb +5 -5
  23. data/lib/factory_girl/null_object.rb +14 -2
  24. data/lib/factory_girl/registry.rb +15 -23
  25. data/lib/factory_girl/reload.rb +2 -0
  26. data/lib/factory_girl/strategy_calculator.rb +1 -5
  27. data/lib/factory_girl/syntax.rb +1 -0
  28. data/lib/factory_girl/syntax/blueprint.rb +1 -0
  29. data/lib/factory_girl/syntax/generate.rb +6 -3
  30. data/lib/factory_girl/syntax/make.rb +4 -2
  31. data/lib/factory_girl/syntax/methods.rb +0 -81
  32. data/lib/factory_girl/syntax/sham.rb +1 -0
  33. data/lib/factory_girl/syntax/vintage.rb +0 -2
  34. data/lib/factory_girl/syntax_runner.rb +5 -0
  35. data/lib/factory_girl/version.rb +1 -1
  36. data/spec/acceptance/activesupport_instrumentation_spec.rb +49 -0
  37. data/spec/acceptance/build_stubbed_spec.rb +6 -6
  38. data/spec/acceptance/initialize_with_spec.rb +26 -0
  39. data/spec/acceptance/modify_factories_spec.rb +2 -2
  40. data/spec/acceptance/register_strategies_spec.rb +120 -0
  41. data/spec/acceptance/skip_create_spec.rb +19 -0
  42. data/spec/acceptance/syntax/blueprint_spec.rb +2 -0
  43. data/spec/acceptance/syntax/generate_spec.rb +2 -0
  44. data/spec/acceptance/syntax/make_spec.rb +2 -0
  45. data/spec/acceptance/syntax/vintage_spec.rb +2 -2
  46. data/spec/acceptance/syntax_methods_within_dynamic_attributes_spec.rb +41 -0
  47. data/spec/factory_girl/attribute/dynamic_spec.rb +6 -6
  48. data/spec/factory_girl/attribute_list_spec.rb +4 -4
  49. data/spec/factory_girl/callback_spec.rb +7 -7
  50. data/spec/factory_girl/definition_proxy_spec.rb +6 -6
  51. data/spec/factory_girl/disallows_duplicates_registry_spec.rb +44 -0
  52. data/spec/factory_girl/evaluator_class_definer_spec.rb +5 -5
  53. data/spec/factory_girl/factory_spec.rb +3 -3
  54. data/spec/factory_girl/null_object_spec.rb +18 -4
  55. data/spec/factory_girl/registry_spec.rb +30 -72
  56. data/spec/factory_girl/sequence_spec.rb +3 -2
  57. data/spec/factory_girl/strategy_calculator_spec.rb +1 -1
  58. data/spec/spec_helper.rb +0 -1
  59. metadata +41 -28
@@ -1,6 +1,6 @@
1
1
  module FactoryGirl
2
2
  class Callback
3
- attr_reader :name, :block
3
+ attr_reader :name
4
4
 
5
5
  def initialize(name, block)
6
6
  @name = name.to_sym
@@ -21,6 +21,9 @@ module FactoryGirl
21
21
  block == other.block
22
22
  end
23
23
 
24
+ protected
25
+ attr_reader :block
26
+
24
27
  private
25
28
 
26
29
  def check_name
@@ -1,5 +1,5 @@
1
1
  module FactoryGirl
2
- class CallbackRunner
2
+ class CallbacksObserver
3
3
  def initialize(callbacks, evaluator)
4
4
  @callbacks = callbacks
5
5
  @evaluator = evaluator
@@ -6,7 +6,7 @@ module FactoryGirl
6
6
  @declarations = DeclarationList.new(name)
7
7
  @callbacks = []
8
8
  @defined_traits = []
9
- @to_create = lambda {|instance| instance.save! }
9
+ @to_create = ->(instance) { instance.save! }
10
10
  @base_traits = base_traits
11
11
  @additional_traits = []
12
12
  @constructor = nil
@@ -144,6 +144,10 @@ module FactoryGirl
144
144
  @definition.to_create(&block)
145
145
  end
146
146
 
147
+ def skip_create
148
+ @definition.to_create {|instance| }
149
+ end
150
+
147
151
  def factory(name, options = {}, &block)
148
152
  @child_factories << [name, options, block]
149
153
  end
@@ -0,0 +1,17 @@
1
+ module FactoryGirl
2
+ class DisallowsDuplicatesRegistry
3
+ def initialize(component)
4
+ @component = component
5
+ end
6
+
7
+ delegate :clear, :each, :find, :[], :registered?, to: :@component
8
+
9
+ def register(name, item)
10
+ if registered?(name)
11
+ raise DuplicateDefinitionError, "#{@component.name} already registered: #{name}"
12
+ else
13
+ @component.register(name, item)
14
+ end
15
+ end
16
+ end
17
+ end
@@ -17,24 +17,23 @@ module FactoryGirl
17
17
  undef_method(method) unless method =~ /^__|initialize/
18
18
  end
19
19
 
20
- def initialize(build_strategy, overrides = {})
20
+ def initialize(build_class, build_strategy, overrides = {})
21
+ @build_class = build_class
21
22
  @build_strategy = build_strategy
22
23
  @overrides = overrides
23
24
  @cached_attributes = overrides
24
25
 
25
26
  @overrides.each do |name, value|
26
- singleton_class.send :define_method, name, lambda { value }
27
+ singleton_class.send :define_method, name, -> { value }
27
28
  end
28
29
  end
29
30
 
31
+ delegate :new, to: :@build_class
32
+
30
33
  def association(factory_name, overrides = {})
31
- build_strategy = if overrides.has_key?(:strategy)
32
- overrides[:strategy]
33
- else
34
- Strategy::Create
35
- end
34
+ strategy_override = overrides.fetch(:strategy) { FactoryGirl.strategy_by_name(:create) }
36
35
 
37
- build_strategy = StrategyCalculator.new(build_strategy).strategy
36
+ build_strategy = StrategyCalculator.new(strategy_override).strategy
38
37
  runner = FactoryRunner.new(factory_name, build_strategy, [overrides.except(:strategy)])
39
38
  @build_strategy.association(runner)
40
39
  end
@@ -47,12 +46,16 @@ module FactoryGirl
47
46
  if @cached_attributes.key?(method_name)
48
47
  @cached_attributes[method_name]
49
48
  else
50
- @instance.send(method_name, *args, &block)
49
+ if @instance.respond_to?(method_name)
50
+ @instance.send(method_name, *args, &block)
51
+ else
52
+ SyntaxRunner.new.send(method_name, *args, &block)
53
+ end
51
54
  end
52
55
  end
53
56
 
54
- def __overrides
55
- @overrides
57
+ def __override_names__
58
+ @overrides.keys
56
59
  end
57
60
  end
58
61
  end
@@ -27,16 +27,16 @@ module FactoryGirl
27
27
  end
28
28
 
29
29
  def run(strategy_class, overrides, &block) #:nodoc:
30
- block ||= lambda {|result| result }
30
+ block ||= ->(result) { result }
31
31
  compile
32
32
 
33
33
  strategy = strategy_class.new
34
34
 
35
- evaluator = evaluator_class.new(strategy, overrides.symbolize_keys)
36
- attribute_assigner = AttributeAssigner.new(evaluator, &instance_builder)
35
+ evaluator = evaluator_class.new(build_class, strategy, overrides.symbolize_keys)
36
+ attribute_assigner = AttributeAssigner.new(evaluator, build_class, &instance_builder)
37
37
 
38
38
  evaluation = Evaluation.new(attribute_assigner, to_create)
39
- evaluation.add_observer(CallbackRunner.new(callbacks, evaluator))
39
+ evaluation.add_observer(CallbacksObserver.new(callbacks, evaluator))
40
40
 
41
41
  strategy.result(evaluation).tap(&block)
42
42
  end
@@ -136,7 +136,7 @@ module FactoryGirl
136
136
 
137
137
  def instance_builder
138
138
  build_class = self.build_class
139
- constructor || lambda { build_class.new }
139
+ constructor || -> { build_class.new }
140
140
  end
141
141
 
142
142
  def initialize_copy(source)
@@ -1,7 +1,19 @@
1
1
  module FactoryGirl
2
2
  class NullObject < ::BasicObject
3
- def method_missing(*args)
4
- nil
3
+ def initialize(methods_to_respond_to)
4
+ @methods_to_respond_to = methods_to_respond_to.map(&:to_s)
5
+ end
6
+
7
+ def method_missing(name, *args, &block)
8
+ if respond_to?(name)
9
+ nil
10
+ else
11
+ super
12
+ end
13
+ end
14
+
15
+ def respond_to?(method, include_private=false)
16
+ @methods_to_respond_to.include? method.to_s
5
17
  end
6
18
  end
7
19
  end
@@ -2,45 +2,37 @@ module FactoryGirl
2
2
  class Registry
3
3
  include Enumerable
4
4
 
5
+ attr_reader :name
6
+
5
7
  def initialize(name)
6
8
  @name = name
7
9
  @items = {}
8
10
  end
9
11
 
10
- def add(item)
11
- item.names.each { |name| add_as(name, item) }
12
- item
13
- end
14
-
15
- def find(name)
16
- @items[name.to_sym] or raise ArgumentError.new("#{@name} not registered: #{name.to_s}")
12
+ def clear
13
+ @items.clear
17
14
  end
18
15
 
19
16
  def each(&block)
20
17
  @items.values.uniq.each(&block)
21
18
  end
22
19
 
23
- def [](name)
24
- find(name)
20
+ def find(name)
21
+ if registered?(name)
22
+ @items[name.to_sym]
23
+ else
24
+ raise ArgumentError, "#{@name} not registered: #{name}"
25
+ end
25
26
  end
26
27
 
27
- def registered?(name)
28
- @items.key?(name.to_sym)
29
- end
28
+ alias :[] :find
30
29
 
31
- def clear
32
- @items.clear
30
+ def register(name, item)
31
+ @items[name.to_sym] = item
33
32
  end
34
33
 
35
- private
36
-
37
- def add_as(name, item)
38
- if registered?(name)
39
- raise DuplicateDefinitionError, "#{@name} already registered: #{name}"
40
- else
41
- @items[name.to_sym] = item
42
- end
34
+ def registered?(name)
35
+ @items.key?(name.to_sym)
43
36
  end
44
37
  end
45
38
  end
46
-
@@ -3,6 +3,8 @@ module FactoryGirl
3
3
  self.factories.clear
4
4
  self.sequences.clear
5
5
  self.traits.clear
6
+ self.strategies.clear
7
+ self.register_default_strategies
6
8
  self.find_definitions
7
9
  end
8
10
  end
@@ -19,11 +19,7 @@ module FactoryGirl
19
19
  end
20
20
 
21
21
  def strategy_name_to_object
22
- case @name_or_object
23
- when :build then Strategy::Build
24
- when :create then Strategy::Create
25
- else raise "unrecognized method #{@name_or_object}"
26
- end
22
+ FactoryGirl.strategy_by_name(@name_or_object)
27
23
  end
28
24
  end
29
25
  end
@@ -1,3 +1,4 @@
1
+ require "active_support/deprecation"
1
2
  require "factory_girl/syntax/methods"
2
3
  require "factory_girl/syntax/default"
3
4
  require "factory_girl/syntax/vintage"
@@ -26,6 +26,7 @@ module FactoryGirl
26
26
  module ClassMethods #:nodoc:
27
27
 
28
28
  def blueprint(&block)
29
+ ActiveSupport::Deprecation.warn "Model.blueprint is deprecated; use the FactoryGirl.define syntax instead", caller
29
30
  instance = Factory.new(name.underscore, class: self)
30
31
  proxy = FactoryGirl::DefinitionProxy.new(instance)
31
32
  proxy.instance_eval(&block)
@@ -42,20 +42,23 @@ module FactoryGirl
42
42
  module ClassMethods #:nodoc:
43
43
 
44
44
  def generate(overrides = {}, &block)
45
- instance = FactoryRunner.new(name.underscore, Strategy::Build, [overrides]).run
45
+ ActiveSupport::Deprecation.warn "Model.generate is deprecated; use the FactoryGirl.define syntax instead", caller
46
+ instance = FactoryRunner.new(name.underscore, FactoryGirl.strategy_by_name(:build), [overrides]).run
46
47
  instance.save
47
48
  yield(instance) if block_given?
48
49
  instance
49
50
  end
50
51
 
51
52
  def generate!(overrides = {}, &block)
52
- instance = FactoryRunner.new(name.underscore, Strategy::Create, [overrides]).run
53
+ ActiveSupport::Deprecation.warn "Model.generate! is deprecated; use the FactoryGirl.define syntax instead", caller
54
+ instance = FactoryRunner.new(name.underscore, FactoryGirl.strategy_by_name(:create), [overrides]).run
53
55
  yield(instance) if block_given?
54
56
  instance
55
57
  end
56
58
 
57
59
  def spawn(overrides = {}, &block)
58
- instance = FactoryRunner.new(name.underscore, Strategy::Build, [overrides]).run
60
+ ActiveSupport::Deprecation.warn "Model.spawn is deprecated; use the FactoryGirl.define syntax instead", caller
61
+ instance = FactoryRunner.new(name.underscore, FactoryGirl.strategy_by_name(:build), [overrides]).run
59
62
  yield(instance) if block_given?
60
63
  instance
61
64
  end
@@ -28,11 +28,13 @@ module FactoryGirl
28
28
  module ClassMethods #:nodoc:
29
29
 
30
30
  def make(overrides = {})
31
- FactoryRunner.new(name.underscore, Strategy::Build, [overrides]).run
31
+ ActiveSupport::Deprecation.warn "Model.make is deprecated; use the FactoryGirl.define syntax instead", caller
32
+ FactoryRunner.new(name.underscore, FactoryGirl.strategy_by_name(:build), [overrides]).run
32
33
  end
33
34
 
34
35
  def make!(overrides = {})
35
- FactoryRunner.new(name.underscore, Strategy::Create, [overrides]).run
36
+ ActiveSupport::Deprecation.warn "Model.make! is deprecated; use the FactoryGirl.define syntax instead", caller
37
+ FactoryRunner.new(name.underscore, FactoryGirl.strategy_by_name(:create), [overrides]).run
36
38
  end
37
39
 
38
40
  end
@@ -1,87 +1,6 @@
1
1
  module FactoryGirl
2
2
  module Syntax
3
3
  module Methods
4
- # Generates and returns a Hash of attributes from this factory. Attributes
5
- # can be individually overridden by passing in a Hash of attribute => value
6
- # pairs.
7
- #
8
- # Arguments:
9
- # * name: +Symbol+ or +String+
10
- # The name of the factory that should be used.
11
- # * traits_and_overrides: +Array+
12
- # [+*Array+] Traits to be applied
13
- # [+Hash+] Attributes to overwrite for this set.
14
- # * block:
15
- # Yields the hash of attributes.
16
- #
17
- # Returns: +Hash+
18
- # A set of attributes that can be used to build an instance of the class
19
- # this factory generates.
20
- def attributes_for(name, *traits_and_overrides, &block)
21
- FactoryRunner.new(name, Strategy::AttributesFor, traits_and_overrides).run(&block)
22
- end
23
-
24
- # Generates and returns an instance from this factory. Attributes can be
25
- # individually overridden by passing in a Hash of attribute => value pairs.
26
- #
27
- # Arguments:
28
- # * name: +Symbol+ or +String+
29
- # The name of the factory that should be used.
30
- # * traits_and_overrides: +Array+
31
- # [+*Array+] Traits to be applied
32
- # [+Hash+] Attributes to overwrite for this instance.
33
- # * block:
34
- # Yields the built instance.
35
- #
36
- # Returns: +Object+
37
- # An instance of the class this factory generates, with generated attributes
38
- # assigned.
39
- def build(name, *traits_and_overrides, &block)
40
- FactoryRunner.new(name, Strategy::Build, traits_and_overrides).run(&block)
41
- end
42
-
43
- # Generates, saves, and returns an instance from this factory. Attributes can
44
- # be individually overridden by passing in a Hash of attribute => value
45
- # pairs.
46
- #
47
- # Instances are saved using the +save!+ method, so ActiveRecord models will
48
- # raise ActiveRecord::RecordInvalid exceptions for invalid attribute sets.
49
- #
50
- # Arguments:
51
- # * name: +Symbol+ or +String+
52
- # The name of the factory that should be used.
53
- # * traits_and_overrides: +Array+
54
- # [+*Array+] Traits to be applied
55
- # [+Hash+] Attributes to overwrite for this instance.
56
- # * block:
57
- # Yields the created instance.
58
- #
59
- # Returns: +Object+
60
- # A saved instance of the class this factory generates, with generated
61
- # attributes assigned.
62
- def create(name, *traits_and_overrides, &block)
63
- FactoryRunner.new(name, Strategy::Create, traits_and_overrides).run(&block)
64
- end
65
-
66
- # Generates and returns an object with all attributes from this factory
67
- # stubbed out. Attributes can be individually overridden by passing in a Hash
68
- # of attribute => value pairs.
69
- #
70
- # Arguments:
71
- # * name: +Symbol+ or +String+
72
- # The name of the factory that should be used.
73
- # * traits_and_overrides: +Array+
74
- # [+*Array+] Traits to be applied
75
- # [+Hash+] Attributes to overwrite for this instance.
76
- # * block
77
- # Yields the stubbed object.
78
- #
79
- # Returns: +Object+
80
- # An object with generated attributes stubbed out.
81
- def build_stubbed(name, *traits_and_overrides, &block)
82
- FactoryRunner.new(name, Strategy::Stub, traits_and_overrides).run(&block)
83
- end
84
-
85
4
  # Builds and returns multiple instances from this factory as an array. Attributes can be
86
5
  # individually overridden by passing in a Hash of attribute => value pairs.
87
6
  #
@@ -26,6 +26,7 @@ module FactoryGirl
26
26
  module Sham #:nodoc:
27
27
  def self.method_missing(name, *args, &block)
28
28
  if block_given?
29
+ ActiveSupport::Deprecation.warn "Sham.sequence is deprecated; use the FactoryGirl.define syntax instead", caller
29
30
  start_value = args.first
30
31
  FactoryGirl.register_sequence(Sequence.new(name, start_value || 1, &block))
31
32
  else
@@ -1,5 +1,3 @@
1
- require "active_support/deprecation"
2
-
3
1
  module FactoryGirl
4
2
  module Syntax
5
3
  module Vintage
@@ -0,0 +1,5 @@
1
+ module FactoryGirl
2
+ class SyntaxRunner
3
+ include Syntax::Methods
4
+ end
5
+ end
@@ -1,4 +1,4 @@
1
1
  module FactoryGirl
2
- VERSION = "3.1.1"
2
+ VERSION = "3.2.0"
3
3
  end
4
4
 
@@ -0,0 +1,49 @@
1
+ require "spec_helper"
2
+
3
+ describe "using ActiveSupport::Instrumentation to track factory interaction" do
4
+ before do
5
+ define_model("User", email: :string)
6
+ FactoryGirl.define do
7
+ factory :user do
8
+ email "john@example.com"
9
+
10
+ factory :slow_user do
11
+ after_build { Kernel.sleep(0.1) }
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+
18
+ it "tracks proper time of creating the record" do
19
+ time_to_execute = 0
20
+ callback = ->(name, start, finish, id, payload) { time_to_execute = finish - start }
21
+ ActiveSupport::Notifications.subscribed(callback, "factory_girl.run_factory") do
22
+ FactoryGirl.build(:slow_user)
23
+ end
24
+
25
+ time_to_execute.should be_within(0.01).of(0.1)
26
+ end
27
+
28
+ it "builds the correct payload" do
29
+ tracked_invocations = {}
30
+
31
+ callback = ->(name, start, finish, id, payload) do
32
+ factory_name = payload[:name]
33
+ strategy_name = payload[:strategy]
34
+ tracked_invocations[factory_name] ||= {}
35
+ tracked_invocations[factory_name][strategy_name] ||= 0
36
+ tracked_invocations[factory_name][strategy_name] += 1
37
+ end
38
+
39
+ ActiveSupport::Notifications.subscribed(callback, "factory_girl.run_factory") do
40
+ FactoryGirl.build_list(:slow_user, 2)
41
+ FactoryGirl.build_list(:user, 5)
42
+ FactoryGirl.create_list(:user, 2)
43
+ FactoryGirl.attributes_for(:slow_user)
44
+ end
45
+
46
+ tracked_invocations[:slow_user].should == { build: 2, attributes_for: 1 }
47
+ tracked_invocations[:user].should == { build: 5, create: 2 }
48
+ end
49
+ end