diff --git a/lib/factory_girl.rb b/lib/factory_girl.rb index 056e34e..de3570a 100644 --- a/lib/factory_girl.rb +++ b/lib/factory_girl.rb @@ -3,6 +3,7 @@ require "active_support/notifications" require 'factory_girl/errors' require 'factory_girl/factory_runner' +require 'factory_girl/strategy_syntax_method_registrar' require 'factory_girl/strategy_calculator' require "factory_girl/strategy/build" require "factory_girl/strategy/create" @@ -87,16 +88,7 @@ module FactoryGirl def self.register_strategy(strategy_name, strategy_class) strategies.register(strategy_name, strategy_class) - - FactoryGirl::Syntax::Methods.module_exec do - define_method(strategy_name) do |name, *traits_and_overrides, &block| - instrumentation_payload = { name: name, strategy: strategy_name } - - ActiveSupport::Notifications.instrument("factory_girl.run_factory", instrumentation_payload) do - FactoryRunner.new(name, strategy_name, traits_and_overrides).run(&block) - end - end - end + StrategySyntaxMethodRegistrar.new(strategy_name).define_strategy_methods end def self.strategy_by_name(name) diff --git a/lib/factory_girl/factory_runner.rb b/lib/factory_girl/factory_runner.rb index 7b218dc..9232c71 100644 --- a/lib/factory_girl/factory_runner.rb +++ b/lib/factory_girl/factory_runner.rb @@ -17,7 +17,11 @@ module FactoryGirl factory = factory.with_traits(@traits) end - factory.run(runner_strategy, @overrides, &block) + instrumentation_payload = { name: @name, strategy: runner_strategy } + + ActiveSupport::Notifications.instrument("factory_girl.run_factory", instrumentation_payload) do + factory.run(runner_strategy, @overrides, &block) + end end end end diff --git a/lib/factory_girl/strategy_syntax_method_registrar.rb b/lib/factory_girl/strategy_syntax_method_registrar.rb new file mode 100644 index 0000000..2505f55 --- /dev/null +++ b/lib/factory_girl/strategy_syntax_method_registrar.rb @@ -0,0 +1,36 @@ +module FactoryGirl + class StrategySyntaxMethodRegistrar + def initialize(strategy_name) + @strategy_name = strategy_name + end + + def define_strategy_methods + define_singular_strategy_method + define_list_strategy_method + end + + private + + def define_singular_strategy_method + strategy_name = @strategy_name + + define_syntax_method(strategy_name) do |name, *traits_and_overrides, &block| + FactoryRunner.new(name, strategy_name, traits_and_overrides).run(&block) + end + end + + def define_list_strategy_method + strategy_name = @strategy_name + + define_syntax_method("#{strategy_name}_list") do |name, amount, *traits_and_overrides| + amount.times.map { send(strategy_name, name, *traits_and_overrides) } + end + end + + def define_syntax_method(name, &block) + FactoryGirl::Syntax::Methods.module_exec do + define_method(name, &block) + end + end + end +end diff --git a/lib/factory_girl/syntax/methods.rb b/lib/factory_girl/syntax/methods.rb index 23092da..566387d 100644 --- a/lib/factory_girl/syntax/methods.rb +++ b/lib/factory_girl/syntax/methods.rb @@ -1,43 +1,83 @@ module FactoryGirl module Syntax + ## This module is a container for all strategy methods provided by + ## FactoryGirl. This includes all the default strategies provided ({Methods#build}, + ## {Methods#create}, {Methods#build_stubbed}, and {Methods#attributes_for}), as well as + ## the complementary *_list methods. + ## @example singular factory execution + ## # basic use case + ## build(:completed_order) + ## + ## # factory yielding its result to a block + ## create(:post) do |post| + ## create(:comment, post: post) + ## end + ## + ## # factory with attribute override + ## attributes_for(:post, title: "I love Ruby!") + ## + ## # factory with traits and attribute override + ## build_stubbed(:user, :admin, :male, name: "John Doe") + ## + ## @example multiple factory execution + ## # basic use case + ## build_list(:completed_order, 2) + ## create_list(:completed_order, 2) + ## + ## # factory with attribute override + ## attributes_for_list(:post, 4, title: "I love Ruby!") + ## + ## # factory with traits and attribute override + ## build_stubbed_list(:user, 15, :admin, :male, name: "John Doe") module Methods - # Builds and returns multiple instances from this factory as an array. Attributes can be - # individually overridden by passing in a Hash of attribute => value pairs. - # - # Arguments: - # * name: +Symbol+ or +String+ - # The name of the factory to be used. - # * amount: +Integer+ - # number of instances to be built. - # * traits_and_overrides: +Array+ - # [+*Array+] Traits to be applied - # [+Hash+] Attributes to overwrite for this instance. - # - # Returns: +Array+ - # An array of instances of the class this factory generates, with generated attributes - # assigned. - def build_list(name, amount, *traits_and_overrides) - amount.times.map { build(name, *traits_and_overrides) } - end + # @!parse FactoryGirl.register_default_strategies + # @!method build(name, *traits_and_overrides, &block) + # (see #strategy_method) + # Builds a registered factory by name. + # @return [Object] instantiated object defined by the factory - # Creates and returns multiple instances from this factory as an array. Attributes can be - # individually overridden by passing in a Hash of attribute => value pairs. - # - # Arguments: - # * name: +Symbol+ or +String+ - # The name of the factory to be used. - # * amount: +Integer+ - # number of instances to be created. - # * traits_and_overrides: +Array+ - # [+*Array+] Traits to be applied - # [+Hash+] Attributes to overwrite for this instance. - # - # Returns: +Array+ - # An array of instances of the class this factory generates, with generated attributes - # assigned. - def create_list(name, amount, *traits_and_overrides) - amount.times.map { create(name, *traits_and_overrides) } - end + # @!method create(name, *traits_and_overrides, &block) + # (see #strategy_method) + # Creates a registered factory by name. + # @return [Object] instantiated object defined by the factory + + # @!method build_stubbed(name, *traits_and_overrides, &block) + # (see #strategy_method) + # Builds a stubbed registered factory by name. + # @return [Object] instantiated object defined by the factory + + # @!method attributes_for(name, *traits_and_overrides, &block) + # (see #strategy_method) + # Generates a hash of attributes for a registered factory by name. + # @return [Hash] hash of attributes for the factory + + # @!method build_list(name, amount, *traits_and_overrides) + # (see #strategy_method_list) + # @return [Array] array of built objects defined by the factory + + # @!method create_list(name, amount, *traits_and_overrides) + # (see #strategy_method_list) + # @return [Array] array of created objects defined by the factory + + # @!method build_stubbed_list(name, amount, *traits_and_overrides) + # (see #strategy_method_list) + # @return [Array] array of stubbed objects defined by the factory + + # @!method attributes_for_list(name, amount, *traits_and_overrides) + # (see #strategy_method_list) + # @return [Array] array of attribute hashes for the factory + + # @!method strategy_method + # @!visibility private + # @param [Symbol] name name of the factory to build + # @param [Array] traits_and_overrides splat args traits and a hash of overrides + # @param [Proc] block block to be executed + + # @!method strategy_method_list + # @!visibility private + # @param [Symbol] name name of the factory to execute + # @param [Integer] amount the number of instances to execute + # @param [Array] traits_and_overrides splat args traits and a hash of overrides # Generates and returns the next value in a sequence. # diff --git a/spec/acceptance/register_strategies_spec.rb b/spec/acceptance/register_strategies_spec.rb index 8cf2322..58b2b8a 100644 --- a/spec/acceptance/register_strategies_spec.rb +++ b/spec/acceptance/register_strategies_spec.rb @@ -41,6 +41,14 @@ describe "register custom strategies" do FactoryGirl.build(:named_object).name.should == "Great" FactoryGirl.insert(:named_object).name.should == "Custom strategy" end + + it "allows using the *_list method to build a list using a custom strategy" do + FactoryGirl.register_strategy(:insert, custom_strategy) + + inserted_items = FactoryGirl.insert_list(:named_object, 2) + inserted_items.length.should == 2 + inserted_items.map(&:name).should == ["Custom strategy", "Custom strategy"] + end end describe "including FactoryGirl::Syntax::Methods when custom strategies have been declared" do