factory_girl 3.1.1 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
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