From 0d4b5cb34e65cf95bef083105cdeed869e922bd5 Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Fri, 11 May 2012 11:43:08 -0400 Subject: [PATCH] Fix initialize_with in the context of traits --- lib/factory_girl/definition.rb | 14 ++---- lib/factory_girl/definition_list.rb | 4 ++ lib/factory_girl/factory.rb | 16 +++--- lib/factory_girl/null_factory.rb | 3 +- lib/factory_girl/trait.rb | 4 +- spec/acceptance/traits_spec.rb | 76 ++++++++++++++++++++++++++++- 6 files changed, 96 insertions(+), 21 deletions(-) diff --git a/lib/factory_girl/definition.rb b/lib/factory_girl/definition.rb index 100932c..a2f9bbb 100644 --- a/lib/factory_girl/definition.rb +++ b/lib/factory_girl/definition.rb @@ -10,7 +10,7 @@ module FactoryGirl @to_create = nil @base_traits = base_traits @additional_traits = [] - @constructor = default_constructor + @constructor = nil end delegate :declare_attribute, to: :declarations @@ -50,6 +50,10 @@ module FactoryGirl definition_list.to_create end + def compiled_constructor + definition_list.constructor + end + def to_create(&block) if block_given? @to_create = block @@ -66,16 +70,8 @@ module FactoryGirl @constructor = block end - def custom_constructor? - @constructor != default_constructor - end - private - def default_constructor - @default_constructor ||= -> { new } - end - def base_traits @base_traits.map { |name| trait_by_name(name) } end diff --git a/lib/factory_girl/definition_list.rb b/lib/factory_girl/definition_list.rb index bd6fb23..8a4be6f 100644 --- a/lib/factory_girl/definition_list.rb +++ b/lib/factory_girl/definition_list.rb @@ -22,6 +22,10 @@ module FactoryGirl map(&:to_create).compact.last end + def constructor + map(&:constructor).compact.last + end + delegate :[], :==, to: :@definitions end end diff --git a/lib/factory_girl/factory.rb b/lib/factory_girl/factory.rb index 50fdfdf..0873dae 100644 --- a/lib/factory_girl/factory.rb +++ b/lib/factory_girl/factory.rb @@ -16,7 +16,7 @@ module FactoryGirl @compiled = false end - delegate :add_callback, :declare_attribute, :to_create, :define_trait, + delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor, :defined_traits, :inherit_traits, :append_traits, :definition_list, to: :@definition def build_class @@ -34,6 +34,7 @@ module FactoryGirl strategy = StrategyCalculator.new(build_strategy).strategy.new evaluator = evaluator_class.new(build_class, strategy, overrides.symbolize_keys) + constructor = compiled_constructor || -> { new } attribute_assigner = AttributeAssigner.new(evaluator, build_class, &constructor) evaluation = Evaluation.new(attribute_assigner, compiled_to_create) @@ -119,13 +120,12 @@ module FactoryGirl parent.callbacks + definition_list.callbacks end - def constructor - @constructor ||= - if @definition.custom_constructor? - @definition.constructor - else - parent.constructor - end + def compiled_to_create + @definition.compiled_to_create || parent.compiled_to_create + end + + def compiled_constructor + @definition.compiled_constructor || parent.compiled_constructor end private diff --git a/lib/factory_girl/null_factory.rb b/lib/factory_girl/null_factory.rb index 39b1b77..2a611fe 100644 --- a/lib/factory_girl/null_factory.rb +++ b/lib/factory_girl/null_factory.rb @@ -7,7 +7,8 @@ module FactoryGirl @definition = Definition.new end - delegate :defined_traits, :callbacks, :attributes, :constructor, :compiled_to_create, to: :definition + delegate :defined_traits, :callbacks, :attributes, :constructor, + :compiled_to_create, :compiled_constructor, to: :definition def compile; end def class_name; end diff --git a/lib/factory_girl/trait.rb b/lib/factory_girl/trait.rb index 844a208..74ba1eb 100644 --- a/lib/factory_girl/trait.rb +++ b/lib/factory_girl/trait.rb @@ -6,13 +6,13 @@ module FactoryGirl def initialize(name, &block) @name = name @block = block - @definition = Definition.new + @definition = Definition.new(@name) proxy = FactoryGirl::DefinitionProxy.new(@definition) proxy.instance_eval(&@block) if block_given? end - delegate :add_callback, :declare_attribute, :to_create, :define_trait, + delegate :add_callback, :declare_attribute, :to_create, :define_trait, :constructor, :callbacks, :attributes, to: :@definition def names diff --git a/spec/acceptance/traits_spec.rb b/spec/acceptance/traits_spec.rb index 9d4d2ce..6117601 100644 --- a/spec/acceptance/traits_spec.rb +++ b/spec/acceptance/traits_spec.rb @@ -420,7 +420,7 @@ describe "making sure the factory is properly compiled the first time we want to end end -describe "traits with other than attributes or callbacks defined" do +describe "traits with to_create" do before do define_model("User", name: :string) @@ -487,3 +487,77 @@ describe "traits with other than attributes or callbacks defined" do FactoryGirl.create(:child_user_with_trait_and_override, :overridden).name.should == "completely overridden" end end + +describe "traits with initialize_with" do + before do + define_class("User") do + attr_reader :name + + def initialize(name) + @name = name + end + end + + FactoryGirl.define do + factory :user do + trait :with_initialize_with do + initialize_with { new("initialize_with") } + end + + factory :sub_user do + initialize_with { new("sub") } + + factory :child_user + end + + factory :sub_user_with_trait do + with_initialize_with + + factory :child_user_with_trait + end + + factory :sub_user_with_trait_and_override do + with_initialize_with + initialize_with { new("sub with trait and override") } + + factory :child_user_with_trait_and_override + end + end + end + end + + it "can apply initialize_with from traits" do + FactoryGirl.build(:user, :with_initialize_with).name.should == "initialize_with" + end + + it "can apply initialize_with from the definition" do + FactoryGirl.build(:sub_user).name.should == "sub" + FactoryGirl.build(:child_user).name.should == "sub" + end + + it "gives additional traits higher priority than initialize_with from the definition" do + FactoryGirl.build(:sub_user, :with_initialize_with).name.should == "initialize_with" + FactoryGirl.build(:child_user, :with_initialize_with).name.should == "initialize_with" + end + + it "gives base traits normal priority" do + FactoryGirl.build(:sub_user_with_trait).name.should == "initialize_with" + FactoryGirl.build(:child_user_with_trait).name.should == "initialize_with" + end + + it "gives base traits lower priority than overrides" do + FactoryGirl.build(:sub_user_with_trait_and_override).name.should == "sub with trait and override" + FactoryGirl.build(:child_user_with_trait_and_override).name.should == "sub with trait and override" + end + + it "gives additional traits higher priority than base traits and factory definition" do + FactoryGirl.define do + trait :overridden do + initialize_with { new("completely overridden") } + end + end + + FactoryGirl.build(:sub_user_with_trait_and_override, :overridden).name.should == "completely overridden" + FactoryGirl.build(:child_user_with_trait_and_override, :overridden).name.should == "completely overridden" + end +end