From 36cb43e9b0e5174ff28695d48c066396db82675d Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Fri, 8 Feb 2013 11:00:22 -0500 Subject: [PATCH] Add global callbacks This allows callbacks (after :build, :create, etc.) to be defined at the FactoryGirl level; this means that the callback will be invoked for all factories. This is primarily to maintain consistency and follow the principle of least surprise. As usual, callbacks are applied from the lowest component to the highest, meaning that global callbacks will be run after factory and trait callbacks are run. FactoryGirl.define do after(:build) {|object| puts "Built #{object}" } factory :user # ... end Closes #481 Closes #486 --- GETTING_STARTED.md | 14 +++++++ gemfiles/3.0.gemfile.lock | 2 +- lib/factory_girl.rb | 2 +- lib/factory_girl/configuration.rb | 3 +- lib/factory_girl/definition.rb | 15 +++++++ lib/factory_girl/definition_hierarchy.rb | 2 +- lib/factory_girl/definition_proxy.rb | 17 +------- lib/factory_girl/syntax/default.rb | 8 ++++ spec/acceptance/callbacks_spec.rb | 51 ++++++++++++++++++++++++ 9 files changed, 95 insertions(+), 19 deletions(-) diff --git a/GETTING_STARTED.md b/GETTING_STARTED.md index ddd616b..c665a38 100644 --- a/GETTING_STARTED.md +++ b/GETTING_STARTED.md @@ -748,6 +748,20 @@ factory :user do end ``` +To override callbacks for all factories, define them within the +`FactoryGirl.define` block: + +```ruby +FactoryGirl.define do + after(:build) {|object| puts "Built #{object}" } + after(:create) {|object| AuditLog.create(attrs: object.attributes) } + + factory :user do + name "John Doe" + end +end +``` + Modifying factories ------------------- diff --git a/gemfiles/3.0.gemfile.lock b/gemfiles/3.0.gemfile.lock index afb60c0..7f4abf9 100644 --- a/gemfiles/3.0.gemfile.lock +++ b/gemfiles/3.0.gemfile.lock @@ -1,5 +1,5 @@ PATH - remote: /Users/mjankowski/Development/OpenSource/factory_girl + remote: /Users/joshuaclayton/dev/gems/factory_girl specs: factory_girl (4.2.0) activesupport (>= 3.0.0) diff --git a/lib/factory_girl.rb b/lib/factory_girl.rb index b47aef8..92bb8b5 100644 --- a/lib/factory_girl.rb +++ b/lib/factory_girl.rb @@ -55,7 +55,7 @@ module FactoryGirl end class << self - delegate :factories, :sequences, :traits, :strategies, :callback_names, + delegate :factories, :sequences, :traits, :callbacks, :strategies, :callback_names, :to_create, :skip_create, :initialize_with, :constructor, :duplicate_attribute_assignment_from_initialize_with, :duplicate_attribute_assignment_from_initialize_with=, to: :configuration end diff --git a/lib/factory_girl/configuration.rb b/lib/factory_girl/configuration.rb index 8d9c28c..05a0d1f 100644 --- a/lib/factory_girl/configuration.rb +++ b/lib/factory_girl/configuration.rb @@ -15,7 +15,8 @@ module FactoryGirl initialize_with { new } end - delegate :to_create, :skip_create, :constructor, to: :@definition + delegate :to_create, :skip_create, :constructor, :before, :after, + :callback, :callbacks, to: :@definition def initialize_with(&block) @definition.define_constructor(&block) diff --git a/lib/factory_girl/definition.rb b/lib/factory_girl/definition.rb index ee3bac8..d53a249 100644 --- a/lib/factory_girl/definition.rb +++ b/lib/factory_girl/definition.rb @@ -84,6 +84,21 @@ module FactoryGirl @constructor = block end + def before(*names, &block) + callback(*names.map {|name| "before_#{name}" }, &block) + end + + def after(*names, &block) + callback(*names.map {|name| "after_#{name}" }, &block) + end + + def callback(*names, &block) + names.each do |name| + FactoryGirl.register_callback(name) + add_callback(Callback.new(name, block)) + end + end + private def base_traits diff --git a/lib/factory_girl/definition_hierarchy.rb b/lib/factory_girl/definition_hierarchy.rb index c91cb0f..77807f5 100644 --- a/lib/factory_girl/definition_hierarchy.rb +++ b/lib/factory_girl/definition_hierarchy.rb @@ -1,7 +1,7 @@ module FactoryGirl class DefinitionHierarchy def callbacks - [] + FactoryGirl.callbacks end def constructor diff --git a/lib/factory_girl/definition_proxy.rb b/lib/factory_girl/definition_proxy.rb index 79c9789..998fc04 100644 --- a/lib/factory_girl/definition_proxy.rb +++ b/lib/factory_girl/definition_proxy.rb @@ -6,6 +6,8 @@ module FactoryGirl undef_method(method) unless UNPROXIED_METHODS.include?(method.to_s) end + delegate :before, :after, :callback, to: :@definition + attr_reader :child_factories def initialize(definition, ignore = false) @@ -157,20 +159,5 @@ module FactoryGirl def initialize_with(&block) @definition.define_constructor(&block) end - - def before(*names, &block) - callback(*names.map {|name| "before_#{name}" }, &block) - end - - def after(*names, &block) - callback(*names.map {|name| "after_#{name}" }, &block) - end - - def callback(*names, &block) - names.each do |name| - FactoryGirl.register_callback(name) - @definition.add_callback(Callback.new(name, block)) - end - end end end diff --git a/lib/factory_girl/syntax/default.rb b/lib/factory_girl/syntax/default.rb index 039467f..41a5266 100644 --- a/lib/factory_girl/syntax/default.rb +++ b/lib/factory_girl/syntax/default.rb @@ -48,6 +48,14 @@ module FactoryGirl def self.run(block) new.instance_eval(&block) end + + delegate :before, :after, :callback, to: :configuration + + private + + def configuration + FactoryGirl.configuration + end end class ModifyDSL diff --git a/spec/acceptance/callbacks_spec.rb b/spec/acceptance/callbacks_spec.rb index db4a84a..af32e42 100644 --- a/spec/acceptance/callbacks_spec.rb +++ b/spec/acceptance/callbacks_spec.rb @@ -175,3 +175,54 @@ describe 'binding a callback to multiple callbacks' do expect(FactoryGirl.build_stubbed(:user, name: 'John Doe').name).to eq 'JOHN DOE' end end + +describe 'global callbacks' do + include FactoryGirl::Syntax::Methods + + before do + define_model('User', name: :string) + define_model('Company', name: :string) + + FactoryGirl.define do + after :build do |object| + object.name = case object.class.to_s + when 'User' then 'John Doe' + when 'Company' then 'Acme Suppliers' + end + end + + after :create do |object| + object.name = "#{object.name}!!!" + end + + trait :awesome do + after :build do |object| + object.name = "___#{object.name}___" + end + + after :create do |object| + object.name = "A#{object.name}Z" + end + end + + factory :user do + after :build do |user| + user.name = user.name.downcase + end + end + + factory :company do + after :build do |company| + company.name = company.name.upcase + end + end + end + end + + it 'triggers after build callbacks for all factories' do + expect(build(:user).name).to eq 'john doe' + expect(create(:user).name).to eq 'john doe!!!' + expect(create(:user, :awesome).name).to eq 'A___john doe___!!!Z' + expect(build(:company).name).to eq 'ACME SUPPLIERS' + end +end